Build config: selectable parameters

ZenMake provides ability to select values for parameters in task params depending on some conditions. This feature of ZenMake is similar to Configurable attributes from Bazel build system and main idea was borrowed from that system. But implementation is different.

It can be used for selecting different source files, includes, compiler flags and others on different platforms, different toolchains, etc.

Example:

tasks = {
    # ...
}

conditions = {
    'windows-msvc' : {
        'platform' : 'windows',
        'toolchain' : 'msvc',
    },
}

buildtypes = {
    'debug' : {
    },
    'release' : {
        'cxxflags.select' : {
            'windows-msvc': '/O2',
            'default': '-O2',
        },
    },
}

In this example for build type ‘release’ we set value ‘/O2’ to ‘cxxflags’ if toolchain ‘msvc’ is used on MS Windows and set ‘-02’ for all other cases.

This method can be used for any parameter in task params excluding features in the form:

'<parameter name>.select' : {
    '<condition name1>' : <value>,
    '<condition name2>' : <value>,
    ...
    'default' : <value>,
}

A <parameter name> here is a parameter from task params. Examples: ‘toolchain.select’, ‘source.select’, ‘use.select’, etc.

Each condition name must refer to a key in conditions or to one of internal conditions (see below). There is also special optional key default wich means default value if none of the conditions has been selected. If the key default doen’t exist then ZenMake tries to use the value of <parameter name> if it exists. If none of the conditions has been selected and no default value for the parameter then this parameter will not be used.

Keys in conditions are just strings with any characters excluding white spaces. A value of each condition is a dict with one or more such parameters:

platform:

Selected platform like ‘linux’, ‘windows’, ‘darwin’, etc.

It can be one value or list of values or string with more than one value separated by spaces like this: ‘linux windows’.

cpu-arch:

Selected current CPU architecture. Actual it’s a result of the python function platform.machine() See https://docs.python.org/library/platform.html. Some possible values are: arm, i386, i686, x86_64, AMD64. Real value depends also on platform. For example, on Windows you can get AMD64 while on Linux you gets x86_64 on the same host.

Current value can be obtained also with the command zenmake sysinfo.

It can be one value or list of values or string with more than one value separated by spaces like this: ‘i686 x86_64’.

toolchain:

Selected/detected toolchain.

It can be one value or list of values or string with more than one value separated by spaces like this: ‘gcc clang’.

task:

Selected build task name.

It can be one value or list of values or string with more than one value separated by spaces like this: ‘mylib myprogram’.

buildtype:

Selected buildtype.

It can be one value or list of values or string with more than one value separated by spaces like this: ‘debug release’.

env:

Check system environment variables. It’s a dict of pairs <variable> : <value>. Example:

conditions = {
     'my-env' : {
         'env' : {
             'TEST' : 'true',
             'CXX' : 'gcc',
         }
     },
 }

If a parameter in a condition contains more than one value then any of these values will fulfill selected condition. It means if some condition, for example, has platform which contains 'linux windows' without other parameters then this condition will be selected on any of these platforms (on GNU/Linux and on MS Windows). But with parameter env the situation is different. This parameter can contain more than one environment variable and a condition will be selected only when all of these variables are equal to existing variables from the system environment. If you want to have condition to select by any of such variables you can do it by making different conditions in conditions.

Note

There is one limitation for toolchain.select - it’s not possible to use condition with ‘toolchain’ parameter inside toolchain.select.

Only one record from *.select for each parameter can be selected for each task during configuring but condition name in *.select can be string with more than one name from conditions. Such names must be just separated by spaces in the string. In this case it is considered like:

'<parameter name>.select' : {
    '<name1 AND name2>' : <value>,
    ...
}

Example:

conditions = {
    'linux' : {
        'platform' : 'linux',
    },
    'g++' : {
        'toolchain' : 'g++',
    },
}

buildtypes = {
    'debug' : {
    },
    'release' : {
        'cxxflags.select' : {
            # will be selected only on linux with selected/detected toolchain g++
            'linux g++': '-Ofast',
            # will be selected in all other cases
            'default': '-O2',
        },
    },
}

For convenience there are ready to use internal conditions for known platforms and supported toolchains. So in example above variable conditions is not needed at all because conditions with names linux and g++ already exist:

# no declaration of conditions

buildtypes = {
    'debug' : {
    },
    'release' : {
        'cxxflags.select' : {
            # will be selected only on linux with selected/detected toolchain g++
            'linux g++': '-Ofast',
            # will be selected in all other cases
            'default': '-O2',
        },
    },
}

Also you can use internal conditions for supported buildtypes. But if any name of supported buildtype is the same as one of known platforms or supported toolchains then such a buildtype can not be used as internal condition. For example, you can want to make/use buildtype ‘linux’ and it will be possible but for using in conditions you have to declare some different name in this case because ‘linux’ is one of known platforms.

There is one detail about internal conditions for toolchains - only toolchains supported for current build tasks exist. ZenMake detects them with all features of all existing build tasks in current project during configuring. For example, if tasks exist for C language only then supported toolchains for all other languages don’t exist in internal conditions.

If you declare condition in conditions with the same name of some internal condition then your condition will be used instead of internal condition.