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 theDebug
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:
- command-level flags
- system flags
- architecture flags
- compiler flags
- build type flags
- 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 toCMAKE_CXX_FLAGS
andCMAKE_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 toCMAKE_CXX_FLAGS
andCMAKE_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 forx86
andx86_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