Build items

(You can read this document with the command cmany help build_items).

cmany creates its builds by combining build items. There are the following classes of build items:

  • systems: -s/--systems sys1[,sys2[,...]]
  • architectures: -a/--architectures arch1[,arch2[,...]]
  • compilers: -c/--compilers comp1[,comp2[,...]]
  • build types: -t/--build-types btype1[,btype2[,...]]
  • variants: -v/--variants var1[,var2[,...]]

All of the arguments above accept a comma-separated list of items (but note that no spaces should appear around the commmas). Repeated invokation of an argument has the same effect. For example, -c g++,clang++ is the same as -c g++ -c clang++.

Any omitted argument will default to a list of a single item based on the current system (for example, omitting -s in linux yields an implicit -s linux whereas in windows yields an implicit -s windows; or omitting -a in a 64 bit processor system yields an implicit -a x86_64).

cmany will generate builds by combining every build item with every other build item of different class. The resulting builds have a name of the form {system}-{architecture}-{compiler}-{build_type}[-{variant}].

Since the number of combinations grows very quickly and not every combination will make sense, cmany has arguments to exclude certain combinations, either by the resulting build name (with a regex) or by the names of the items that a build would be composed of. Read more about it here.

The following sections address each of these build items in more detail.

Per-item flags

To make a build item bring with it a set of properties (which can be compiler flags, macros, cmake flags, or combination exclusion arguments), use the following syntax: 'item_name: <flag_specs>....' instead of just item_name. This will prompt cmany to use those flags whenever that build item is used in a build. For example, you can add a flag only to a certain build type:

$ cmany b --build-types Release,'Debug: --cxxflags "-Wall"'

Note the use of the quotes; this is necessary to have the arguments correctly parsed:

  • The outer quotes (single quotes in this case) are necessary for causing the full specification of the Debug build type to be considered at once.
  • The inner quotes around the -Wall flag in the Debug configuration are needed to prevent it from being parsed as an argument to cmany, which would cause an error.
  • The order of the quotes is irrelevant to cmany. The Debug configuration could also have been specified as "Debug: --cxxflags '-Wall'".
  • You can also escape the quotes using the backslash character. For example, you can do "Debug: --cxxflags \"-Wall\"" or 'Debug: --cxxflags \'-Wall\''.

See the cmany help on flags to discover what flags can be used with build items. Note also that exclusion flags can also be used as per-item flags.

When creating the flags for the build, the order in the final compile command is the following:

  1. command-level flags
  2. system flags
  3. architecture flags
  4. compiler flags
  5. build type flags
  6. variant flags

So command level flags come first and variant flags come last in the compiler command line. Note that flags from later build items override those of earlier build items. For example, variant flags override flags from the build type; these in turn override flags specified with the compiler, and so on.

Inheriting per-item flags

To make a build item inherit all the flags in another build item, reference the base item name prefixed with @. The result is that the inheriting item will have all the flags of the base item, plus its own flags inserted at the point where the @ reference occurs. combination flags are not inherited.

For example, note the @foo spec in the bar variant:

$ cmany b -v none \
          -v 'foo: --defines SOME_DEFINE=32 --cxxflags "-Os"' \
          -v 'bar: @foo --defines SOME_DEFINE=16 -cxxflags "-O2"'

With this command, bar will be now consist of -D SOME_DEFINE=32,SOME_DEFINE=16 -X "-Os","-O2"'.

Note

Order matters here: the place where the inheritance directive occurs is relevant. For example:

$ cmany b -v none \
         -v 'foo: --defines SOME_DEFINE=32 --cxxflags "-Os"' \
         -v 'bar: --defines SOME_DEFINE=16 -cxxflags "-O2" @foo'

will make bar consist instead of -D SOME_DEFINE=16,SOME_DEFINE=32 -X "-O2","-Os". So here SOME_DEFINE will have with a value of 16, as opposed to 32 which will be the value in the previous example. This happens because cmany will insert foo’s options right in the place where @foo appears.

Compilers

cmany defaults to CMake’s default compiler. To use different compilers, use --compilers/-c. Each argument given here must be an executable compiler found in your path, or an absolute path to the compiler.

The following command chooses clang++ instead of CMake’s default compiler:

$ cmany b -c clang++

If the directory is initially empty, this will be the result:

$ ls -1 build/*
build/linux-x86_64-clang++3.9-Release/

Note that cmany will query the compiler for a name and a version. This is for ensuring the use of different build trees for different versions of the same compiler. The logic for extracting the compiler name/version may fail in some cases, so open an issue if you see problems here.

Microsoft Visual Studio

Picking the Visual Studio version with CMake is harder than it should be. cmany tries to make this easier to do. For example, this will use Visual Studio 2015 in the native architecture:

$ cmany b -c vs2015
$ ls -1 build/*
build/windows-x86_64-vs2015-Release/

as opposed to the option required by CMake, which would be -G "Visual Studio 15 2017 Win64"). So if cmany is running in a 32 bit system, then the result of running the command above will be a 32 bit build instead:

$ cmany b -c vs2015
$ ls -1 build/*
build/windows-x86-vs2015-Release/

An explicit request for the target architecture may be made by appending a _32 or _64 suffix. For example, if Visual Studio 2017 in 32 bit mode is desired, then simply use vs2017_32:

$ cmany b -c vs2017_32
$ ls -1 build/*
build/windows-x86-vs2017-Release/

You can also choose the VS toolset to use in the compiler name. For example, compile with the clang frontend (equivalent in this case to cmake’s -T v141_clang_c2 option):

$ cmany b -c vs2017_clang
$ ls -1 build/*
build/windows-x86-vs2017_clang-Release/

cmany allows you to create any valid combination of the Visual Studio project versions (from vs2017 to vs2005), target architectures (32, 64, arm, ia64) and toolsets (from v141 to v80, with clang_c2 and xp variants). The general form for the cmany VS specification alias is:

<vs_project_version>[_<vs_platform_version>][_<vs_toolset_version>]

Note that the order must be exactly as given. Note also that the platform version or the toolset version can be omitted, in which case a sensible default will be used:

  • if the platform is omitted, then the current platform will be used
  • if the toolset is omitted, then the toolset of the given project version will be used.

Given the many VS versions, target architectures and toolsets, this creates hundreds of possible aliases, so read the complete documentation for Visual Studio.

Build types

cmany uses Release as the default build type. To set a different build type use --build-types/-t. The following command chooses a build type of Debug instead of Release:

$ cmany b -t Debug

If the directory is initially empty, this will be the result:

$ ls -1 build/*
build/linux-x86_64-g++6.1-Debug/

Note that the build naming scheme will cause build trees with different build types to be placed in different directories. Apart from producing a better organization of your builds, this saves you a full project rebuild when the build type changes (and the cmake generator is not a multi-config generator like MSVC).

Variants

cmany has variants for setting up a bundle of flags to be combined with all other build items.

A variant is a build item different from any other which uses a specific combination of flags via --cmake-vars/-V, --defines/-D, --cxxflags/-X, --cflags/-C. Like all other build items, it will be combined with other build items of different class. With the exception of the null variant, variants will usually have per-item flags.

The command option to setup a variant is --variant/-v and should be used as follows: --variant 'variant_name: <variant_specs>'. For example, assume a vanilla build:

$ cmany b

which will produce the following tree:

$ ls -1 build
build/linux-x86_64-clang3.9-Release/

If instead of this we want to produce two variants foo and bar with specific defines and compiler flags, the following command should be used:

$ cmany b --variant 'foo: --defines SOME_DEFINE=32 --cxxflags "-Os"' \
          --variant 'bar: --defines SOME_DEFINE=16 --cxxflags "-O2"'

or, in short form:

$ cmany b -v 'foo: -D SOME_DEFINE=32 -X "-Os"' \
          -v 'bar: -D SOME_DEFINE=16 -X "-O2"'

To be clear, the foo variant will be compiled with the preprocessor symbol named SOME_DEFINE defined to 32, and will use the -Os C++ compiler flag. In turn, the bar variant will be compiled with the preprocessor symbol named SOME_DEFINE defined to 16, and will use the -O2 C++ compiler flag. So instead of the build above, we now get:

$ ls -1 build
build/linux-x86_64-clang3.9-Release-bar/
build/linux-x86_64-clang3.9-Release-foo/

Variants will be combined, just like compilers or build types. So applying the former two variants to the 9-build example above will result in 18 builds (3 compilers * 3 build types * 2 variants)

$ cmany b -c clang++,g++,icpc -t Debug,Release,MinSizeRel \
          --variant 'foo: -D SOME_DEFINE=32 -X "-Os"' \
          --variant 'bar: -D SOME_DEFINE=16 -X "-O2"'
$ ls -1 build/
build/linux-x86_64-clang3.9-Debug-bar/
build/linux-x86_64-clang3.9-Debug-foo/
build/linux-x86_64-clang3.9-MinSizeRel-bar/
build/linux-x86_64-clang3.9-MinSizeRel-foo/
build/linux-x86_64-clang3.9-Release-bar/
build/linux-x86_64-clang3.9-Release-foo/
build/linux-x86_64-gcc6.1-Debug-bar/
build/linux-x86_64-gcc6.1-Debug-foo/
build/linux-x86_64-gcc6.1-MinSizeRel-bar/
build/linux-x86_64-gcc6.1-MinSizeRel-foo/
build/linux-x86_64-gcc6.1-Release-bar/
build/linux-x86_64-gcc6.1-Release-foo/
build/linux-x86_64-icc16.1-Debug-bar/
build/linux-x86_64-icc16.1-Debug-foo/
build/linux-x86_64-icc16.1-MinSizeRel-bar/
build/linux-x86_64-icc16.1-MinSizeRel-foo/
build/linux-x86_64-icc16.1-Release-bar/
build/linux-x86_64-icc16.1-Release-foo/

Note that like any other build item --variant/-v also accepts comma-separated arguments:

$ cmany b -c clang++,g++,icpc -t Debug,Release,MinSizeRel \
          --variant 'foo: -D SOME_DEFINE=32 -X "-Os"','bar: -D SOME_DEFINE=16 -X "-O2"'

Null variant

cmany will combine only the variants it is given. Notice above that the basic (variant-less) build linux-x86_64-clang3.9-Debug is not there. To retain the basic build without a variant suffix use the special name none:

$ cmany b -v none \
          -v 'foo: -D SOME_DEFINE=32 -X "-Os"' \
          -v 'bar: -D SOME_DEFINE=16 -X "-O2"'
$ ls -1 build
build/linux-x86_64-clang3.9-Release/
build/linux-x86_64-clang3.9-Release-bar/
build/linux-x86_64-clang3.9-Release-foo/

You can add flags to the none variant as well, and use inheritance at will:

$ cmany b -v 'none: -X "-Wall"' \
          -v 'foo: @none -D SOME_DEFINE=32 -X "-Os"' \
          -v 'bar: @none -D SOME_DEFINE=16 -X "-O2"'

Systems

The argument to specify system build items is -s/--systems. Systems are a special build item. For example, if you are on linux, omitting -s will default to -s linux, so using -s it is not really needed. But compiling for a different target system qualifies as cross compilation and requires a cmake toolchain file (for which cmany offers the -T/--toolchain flag).

Usually, a toolchain also fixes the compiler and maybe the processor architecture. So most of the time, whenever -s/--systems is used, it will bring with it a toolchain and will also require exclusion arguments to prevent combination of the target system with compilers or architectures different from those of the toolchain.

For example, consider this linux ARM gnueabihf cmake toolchain:

# arm-linux-gnueabihf.cmake

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_VERSION 1)

set(CMAKE_C_COMPILER   /usr/bin/arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabihf-g++)
set(CMAKE_STRIP        /usr/bin/arm-linux-gnueabihf-strip)

set(CMAKE_FIND_ROOT_PATH  /usr/arm-linux-gnueabihf)

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

(If you are using Ubuntu you can install these tools with sudo apt-get install binutils-arm-linux-gnueabihf g++-arm-linux-gnueabihf). When you want to compile your project only for linux OS and (armv5,armv7) architectures, this would be the command line:

$ cmany b --systems 'linux: -T arm-linux-gnueabihf.cmake' \
          --architectures 'armv5: -X "-march=armv5"' \
          --architectures 'armv7: -X "-march=armv7"'

which will produce the following builds:

linux-armv5-arm-linux-gnueabihf-g++5.4-Release
linux-armv7-arm-linux-gnueabihf-g++5.4-Release

If you want to build at the same time for x86 and x86_64, this command could be used (note the use of --exclude-builds):

$ cmany b --systems linux \
          --architectures x86,x86_64 \
          --systems 'linux_arm: -T arm-linux-gnueabihf.cmake -xa x86,x86_64' \
          --architectures 'armv5: -X "-march=armv5"' \
          --architectures 'armv7: -X "-march=armv7"' \
          --exclude-builds 'linux_arm-.*x86','linux-.*arm'

which produces the following builds:

linux-x86-g++5.4-Release
linux-x86_64-g++5.4-Release
linux_arm-armv5-arm-linux-gnueabihf-g++5.4-Release
linux_arm-armv7-arm-linux-gnueabihf-g++5.4-Release

The arm builds for linux now use a system named linux_arm to prevent ambiguity with the native linux system. The --exclude-builds is used to prevent the arm toolchain from being combined with x86 or x86_64 architectures and also to prevent the arm architectures from being used without a toolchain.

Architectures

Architectures are specified with the argument -a/--architectures. When the architecture argument is omitted, cmany will silently default to -a <current_architecture>.

Like with -s/--systems, architectures have some special properties:

  • When in a 64 bit system, asking for a x86 architecture when the compiler is a gcc-like compiler (ie, gcc, clang, icc, zapcc or similar) will result in the the compiler flag -m32 being added to CMAKE_CXX_FLAGS and CMAKE_C_FLAGS.
  • Conversely, when in a 32 bit system, asking for a x86_64 architecture with a gcc-like compiler will result in the flag -m64 being added to CMAKE_CXX_FLAGS and CMAKE_C_FLAGS.
  • When using Visual Studio, you can select the compiler and architecture at once. For example, using -c vs2015_32,vs2015_64 will compile both for x86 and x86_64, and is equivalent to -c vs2015 -a x86,x86_64.

Architectures other than x86/x86_64, as with -s/--systems, -a/--architectures will usually need cross-compilation and thus require toolchains. In fact the, command used in the example of the Systems section can be simplified if the toolchain is specified by architecture instead of the system, and the variants instead provide the -m compiler flags:

$ cmany b --architectures x86,x86_64,'arm: -T arm-linux-gnueabihf.cmake' \
          --variants 'none: -xa arm' \
          --variants 'armv5: -X "-march=armv5" -ia arm' \
          --variants 'armv7: -X "-march=armv7" -ia arm'

The -xa and the -ia arguments above are the short forms of respectively the exclusion arguments --exclude-architectures and --include-architectures. They are needed to prevent combination of the arm variants with the x86 architectures and vice-versa. The resulting builds are exactly the same as in that example, but are now named differently because of the variants:

linux-x86-g++5.4-Release
linux-x86_64-g++5.4-Release
linux-arm-arm-linux-gnueabihf-g++5.4-Release-armv5
linux-arm-arm-linux-gnueabihf-g++5.4-Release-armv7