3.13. global directives

these directives can be used anywhere in your config file. they are not affected by the active section.

In addition to the directives below, the parser also supports line-level conditional prefixes of the form ifdef SOME_DEFINE: key: value and ifndef SOME_DEFINE: key: value. Those are documented further below in conditional config lines: ifdef and ifndef.

Historically these directive spellings are not fully uniform: the various include directives are written without a trailing :, while push_name_prefix:, add_message_definition_dir:, and add_process_default_template: are written with one.

3.13.1. include

syntax:

INCLUDE_DIRECTIVE := "include" + FILENAME + "\n"

example:

include my_subsystem.inc.lnc

this directive can be used to read ln-config-directives from another file. it is useful to split up larger configs across multiple files. also parts of your config might be provided by some other project that provides such an include file.

the included file will be read exactly the same way the main config file is read, with the only exception that names-prefixes pushed in an include file will automatically be pop’ed at the end of that file.

3.13.2. optional_include

syntax:

OPT_INCLUDE_DIRECTIVE := "optional_include" + FILENAME + "\n"

example:

optional_include my_subsystem_for_%(host).inc.lnc

same as the above include directive, but it’s not considered as an error if the specified file does not exist.

this is useful to conditionally include many directives only if some condition is matched - this can be achieved by using %()-defines in that FILENAME.

3.13.3. include_glob & optional_include_glob

syntax:

INCLUDE_GLOB_DIRECTIVE := "include_glob" + PATTERN + "\n"
OPT_INCLUDE_GLOB_DIRECTIVE := "optional_include_glob" + PATTERN + "\n"

example:

include_glob cissygen/**/*.inc.lnc

this directive can search for multiple include files and include them in the same way as the above include directive would do it. this is useful if you want to include many, possibly generated files where you don’t want to explicitely spell the exact-filename.

patterns are matches with python’s fnmatch.fnmatch()-function with the addition that ** can match any sub-directory.

3.13.4. pipe_include

syntax:

PIPE_INCLUDE_DIRECTIVE := "pipe_include" + COMMANDLINE + "\n"

example:

pipe_include python generate_ln_config.py

this directive will execute the specified COMMANDLINE while the current config file is parsed. the standard-output from that command will be interpreted as if it would be contents of an include file, in exactly the same way as above with the include-directive.

this can be used to procedurally generate processes, defines or any other config-directives.

3.13.5. requires_version

syntax:

REQUIRES_VERSION_DIRECTIVE := "requires_version" + VERSION + "\n"

example:

requires_version 3.5.0

This directive aborts config loading unless the running ln_manager version is at least the specified version.

Use this when a configuration depends on parser or manager behavior that is not available in older installations. The check is performed while reading the config file, before the rest of the file is processed further.

3.13.6. push_name_prefix

syntax:

push_name_prefix: <PREFIX>

all objects (processes, groups, states) which are defined after this directive will get their name prefixed with <PREFIX>/ (note the additional /).

example:

# ...
push_name_prefix: MyPrefix

process proc1
# ...

process proc2
# ...

push_name_prefix: SubSection

process proc3
# ...

pop_name_prefix

process proc4
# ...

will create 4 processes with these names:

MyPrefix/proc1
MyPrefix/proc2
MyPrefix/SubSection/proc3
MyPrefix/proc4

this is mainly useful when having the instance-flag enable_auto_groups set to true (see its description for more information).

3.13.7. pop_name_prefix

syntax:

pop_name_prefix

will remove the last pushed name prefix.

3.13.8. warning

this directive can be used to output warnings to ln-managers log while reading the configuration. this can be useful for debugging: e.g. to print out the value of a define at a certain point within the configuration:

syntax:

WARNING_DIRECTIVE := "warning: " + MESSAGE + "\n"
MESSAGE := EVALUATED_STRING

example:

defines
SOME_SETTING: value42

warning: value of SOME_SETTING: %(SOME_SETTING)

the MESSAGE will be prefixed with the current configration file’s name and the line-number within that file.

example log-output could look like this:

2021-11-16 10:54:32.97 warning SystemConfiguratio path/to/my/config.lnc:10: value of SOME_SETTING: value42

3.13.9. conditional config lines: ifdef and ifndef

These are not separate sections. Instead, they are prefixes that conditionally enable or skip one normal key: value config line.

You can think of them as a very small, line-based preprocessor, similar in spirit to C’s #ifdef and #ifndef.

syntax:

IFDEF_LINE := "ifdef " + DEFINE_NAME + ": " + KEY + ": " + VALUE + "\n"
IFNDEF_LINE := "ifndef " + DEFINE_NAME + ": " + KEY + ": " + VALUE + "\n"

example:

defines
ENABLE_DEBUG_OUTPUT: 1

process demo
ifdef ENABLE_DEBUG_OUTPUT: add environment: DEBUG_OUTPUT=1
ifndef LOG_LEVEL: add environment: LOG_LEVEL=info

In the example above:

  • ifdef ENABLE_DEBUG_OUTPUT: ... is applied because ENABLE_DEBUG_OUTPUT exists and is non-empty.

  • ifndef LOG_LEVEL: ... is applied because LOG_LEVEL is not defined.

The parser behaves as if the inner line had been written directly at that position:

add environment: DEBUG_OUTPUT=1
add environment: LOG_LEVEL=info

Important behavior and limitations:

  • ifdef checks whether the named define currently exists and has a non-empty value.

  • ifndef is the inverse: it applies the line only when the define is missing or currently set to the empty string.

  • The define name after ifdef / ifndef is taken literally. It is not string-evaluated, so write ifdef SOME_DEFINE: ..., not ifdef %(SOME_DEFINE): ....

  • Only one normal key: value line can be guarded. The text after the condition must itself be one complete config line.

  • It works for normal section entries such as add environment: ..., environment: ... or flags: ....

  • It also works for single-line directives and entries such as include ..., optional_include ..., include_glob ..., pipe_include ..., add_message_definition_dir: ..., add_process_default_template: ..., undef: ..., push_name_prefix: ..., pop_name_prefix, warning: ..., requires_version ..., and entries in sections such as hosts, node_map and custom_start_tools.

  • It can also guard section-header lines such as process foo or state bar, but this still affects only that one line.

  • Because these conditionals are line-scoped, they are not a block syntax. Guarding a section header does not automatically guard the following section body. If you need to conditionally include a larger block, use include / pipe_include together with ifdef / ifndef or restructure the config so each guarded item is a complete single line.

  • Multi-line values starting with [ are still parsed as a single logical value. If the condition is false, the whole multi-line value is skipped.

This is especially useful for optional process properties, environment entries, or per-project additions that should only be active when a define has been provided earlier in the configuration.

3.13.10. undef

syntax:

UNDEF_LINE := "undef: " + DEFINE_NAME + "\n"

example:

defines
ENABLE_LOGGING: 1

process demo
ifdef ENABLE_LOGGING: add environment: ENABLE_LOGGING=1
undef: ENABLE_LOGGING
ifdef ENABLE_LOGGING: add environment: THIS_LINE_WILL_NOT_BE_USED=1

undef removes a define from the current set of active defines.

Behavior details:

  • removing a define that does not exist is silently ignored

  • the define name is taken literally and is not string-evaluated

  • this is often useful together with ifdef / ifndef when a define should only affect part of a configuration file

3.13.11. add_message_definition_dir

syntax:

ADD_MESSAGE_DEFINITION_DIR := "add_message_definition_dir: " + DIRECTORY + "\n"

example:

add_message_definition_dir: %(CURDIR)/msg_defs

This directive adds another directory to ln_manager’s message-definition search path.

The directory is appended to the end of the list of configured message-definition search paths, in the same order in which add_message_definition_dir directives appear in the config file. See also Message Definitions for the detailed lookup rules.

This is important because ln_manager must be able to find all message definitions that are used at runtime, for example:

  • topic message definitions used by configured processes and running clients

  • service message definitions

The value is usually the directory that contains the top-level namespace folders of your message definitions. If a message definition is named my_project/some_type, ln_manager will look for a file with that relative path below each known message-definition directory.

Typical usage is to add a project-local message-definition directory near the top of the config file, before any processes or states that depend on those types are defined.

3.13.12. add_process_default_template

syntax:

ADD_PROCESS_DEFAULT_TEMPLATE := "add_process_default_template: " + TEMPLATE_USE + "\n"

example:

add_process_default_template: shell with home("my_home", "echo hello")

This directive registers a default use_template specification that is applied automatically to matching processes later in the configuration.

Behavior details:

  • the directive is global and may appear anywhere in the config

  • it affects processes defined after it is read

  • the current push_name_prefix stack is stored with the directive, so the default template only applies to processes below that prefix

  • process-local use_template entries are still possible in addition to these defaults

  • processes can disable such automatically applied defaults with the no_default_templates flag

This is useful when many processes in one part of the config should all inherit the same template without repeating use_template: ... in every process section.