ci_exec.parsers.cmake_parser

Module for CMake focused argument parser CMakeParser.

class CMakeParser(*, add_extra_args=True, shared_or_static_required=False, **kwargs)[source]

A CMake focused argument parser.

The goal of this parser is to fold some of the more common flags used by many CMake projects and parse them into cmake_configure_args and cmake_build_args automatically. Expected workflow is:

from ci_exec import CMakeParser, cd, which

parser = CMakeParser(description="Mylib CI Builder")
# ... add any extra arguments specific to project ...
# parser.add_argument("--foo", ...)

# Parse arguments.  cmake_{configure,build}_args are parsed for you, and are a
# list of strings (possibly empty).
args = parser.parse_args()
configure_args = args.cmake_configure_args
build_args = args.cmake_build_args

# Use the configure / build args created for you by CMakeParser.
cmake = which("cmake")
with cd("build", create=True):
    cmake("..", *configure_args)
    cmake("--build", ".", *build_args)

This is helpful for situations where how users are expected to interact with CMake changes depending on the generator chosen. A reputable example being the build type for single-config vs multi-config generators:

  • Single-config: configure with -DCMAKE_BUILD_TYPE=<build_type>

  • Multi-config: build with --config <build_type>

The command line arguments added here should be appropriate for most projects that obey typical CMake practices, but is as customizable as possible. Command-line argument values such as the help string or default value can be changed with set_argument(). Arguments added by this parser that are not desired can be removed using remove().

Note

The documentation makes a distinction between registered and unregistered arguments.

Registered

A flag that this parser adds in the constructor, and will later use to populate cmake_configure_args and cmake_build_args.

Unregistered

Any arguments that the user adds. This parser does not keep track of them (parser.add_argument("--foo", ...) in example above).

The registered command-line arguments added are as follows:

-G (args.generator) – default: Ninja

The CMake generator to use. Pass-through configure argument cmake -G. Generator choices are validated, however:

  1. Extra Generators are not supported.

  2. The now deprecated Visual Studio XX YYYY Win64 format with Win64 is parsed as an error. Users should take advantage of -A.

-A (args.architecture) – default: None

The CMake architecture to build. Pass-through configure argument cmake -A. Not validated, invalid arguments (e.g., -A provided when generator does not support it) will result in the cmake configure step failing.

-T (args.toolset) – default: None

The CMake toolset to use. Pass-through configure argument cmake -T. Not validated, invalid arguments (e.g., -T provided when generator does not support it) will result in the cmake configure step failing.

--shared (args.shared) – default: False

Add -DBUILD_SHARED_LIBS=ON to configure arguments? Conflicts with --static flag.

See also: shared_or_static_required constructor parameter.

--static (args.static) – default: False

Add -DBUILD_SHARED_LIBS=OFF to configure arguments? Conflicts with --shared flag.

See also: shared_or_static_required constructor parameter.

--cc (args.cc) – default: platform dependent

The C compiler to use. If the generator requested is a single-config generator, then the -DCMAKE_C_COMPILER={args.cc} configure argument. Multi-config generators such as Visual Studio or Xcode will ignore this flag.

Default: $CC environment variable if set, otherwise:

Platform

Default

Windows

cl.exe

Darwin

clang

Other

gcc

--cxx (args.cxx) – default: platform dependent

The C++ compiler to use. Like --cc, adds -DCMAKE_CXX_COMPILER={args.cxx} configure argument for single-config generators.

Default: $CXX environment variable if set, otherwise:

Platform

Default

Windows

cl.exe

Darwin

clang++

Other

g++

--build-type (args.build_type) – default: Release

For single-config generators, this will result in a configure argument of -DCMAKE_BUILD_TYPE={args.build_type}. For multi-config generators, results in ["--config", "{args.build_type}"] in the cmake_build_args.

Choices: Release, Debug, RelWithDebInfo, and MinSizeRel.

[extra_args] (args.extra_args) – default: []

By default, a positional argument with nargs="*" (meaning 0 or more) will be added. These are parsed as anything after the -- sequence, and will be added directly to cmake_configure_args. This supports users doing something like:

$ python .ci/build.py --shared
# args.extra_args = []

$ python .ci/build.py --shared -- -Werror=dev -DMYLIB_DEV=ON
# args.extra_args = ["-Werror=dev", "-DMYLIB_DEV=ON"]

$ python .ci/build.py --shared -- -DMYLIB_DEV=OFF
# args.extra_args = ["-DMYLIB_DEV=OFF"]

Note

This positional argument can be disabled two ways:

# Option 1: at construction.
parser = CMakeParser(add_extra_args=False)

# Option 2: set attribute to False *BEFORE* calling parse_args()
parser = CMakeParser()
parser.add_extra_args = False
args = parser.parse_args()

Since this is a positional argument consuming nargs="*", it must be added last in order for users to add their own positional arguments. The way this is implemented is by having parse_args() actually add the argument, which means:

  1. It must be disabled before parser.parse_args() is called to prevent.

  2. Unlike other arguments, it’s attributes such as default value of [] or help string cannot be changed.

Parameters
  • add_extra_args (bool) – Default: True, support [extra_args] CMake configure arguments at the end of the command-line, after the -- sequence (see above).

  • shared_or_static_required (bool) –

    Default: False. The --shared and --static flags are added using add_mutually_exclusive_group(), this is a pass-through parameter:

    shared_or_static = self.add_mutually_exclusive_group(
        required=shared_or_static_required
    )
    
    • When False, if neither --shared nor --static are supplied, then args.cmake_configure_args will not contain any -DBUILD_SHARED_LIBS=[val] entries.

    • When True, one of --shared or --static must be provided, meaning that args.cmake_configure_args will always contain either -DBUILD_SHARED_LIBS=ON or -DBUILD_SHARED_LIBS=OFF.

    Typically CMake projects will option(BUILD_SHARED_LIBS "Build shared libraries?" OFF), meaning that if not specified --static is implied. This is because the default behavior of add_library with no explicit SHARED|STATIC is STATIC. However, if a project defaults BUILD_SHARED_LIBS to ON, requiring --shared or --static be explicitly provided can help ensure that dependencies etc will all receive the same BUILD_SHARED_LIBS arguments.

  • **kwargs – All other parameters are forwarded to argparse.ArgumentParser. Note that every parameter to the CMakeParser class must be specified as a keyword-only argument. Positional arguments are disabled.

add_extra_args

Whether or not CMake configure arguments after -- sequence will be added.

Type

bool

flag_map

Mapping of string flag keys (e.g., "-G", or "--build-type") to the actual Action of all registered arguments. Direct usage discouraged by users, use get_argument() or set_argument() instead.

Type

dict

dest_map

Mapping of string dest keys (e.g., "generator" or "build_type") to the actual Action of all registered arguments. Direct usage discouraged by users, use get_argument() or set_argument() instead.

Type

dict

makefile_generators = {'Borland Makefiles', 'MSYS Makefiles', 'MinGW Makefiles', 'NMake Makefiles', 'NMake Makefiles JOM', 'Unix Makefiles', 'Watcom WMake'}

The Makefile Generators.

ninja_generator = {'Ninja'}

The Ninja Generator.

ninja_multi_generator = {'Ninja Multi-Config'}

The Ninja Multi-Config Generator.

visual_studio_generators = {'Visual Studio 10 2010', 'Visual Studio 11 2012', 'Visual Studio 12 2013', 'Visual Studio 14 2015', 'Visual Studio 15 2017', 'Visual Studio 16 2019', 'Visual Studio 17 2022', 'Visual Studio 9 2008'}

The Visual Studio Generators.

other_generators = {'Green Hills MULTI', 'Xcode'}

The Other Generators.

classmethod is_multi_config_generator(generator)[source]

Whether or not string generator is a multi-config generator.

classmethod is_single_config_generator(generator)[source]

Whether or not string generator is a single-config generator.

add_argument(*args, **kwargs)[source]

Add an argument to the parser.

Parameters
Returns

The return value of add_argument() (return value often not needed).

Return type

argparse.Action

Raises
  • ValueError – If cmake_configure_args or cmake_build_args are in the positional *args. These are reserved attribute names that get populated after parsing the arguments.

  • ValueError – If add_extra_args is True, then extra_args is also reserved and a value error will be raised if it is found in the positional *args.

get_argument(arg)[source]

Get the Action instance for the specified argument.

Parameters

arg (str) – The command-line flag (e.g., "-G", "--shared") or the dest (e.g., "generator", "shared") to look for.

Returns

The argument action instance (created from add_argument()). If arg does not describe a command-line flag or dest, None is returned.

Return type

argparse.Action or None

parse_args(args=None, namespace=None)[source]

Parse the command-line arguments.

Typically, no arguments are needed:

parser = CMakeParser()
# ... add your own arguments ...
args = parser.parse_args()  # uses sys.argv
Parameters
Returns

The parsed command-line arguments in a wrapper struct. Will also have cmake_configure_args and cmake_build_args (both will be lists of strings) attributes populated.

Return type

argparse.Namespace

remove(*args)[source]

Remove any registered argument(s).

This method may be used to remove any arguments not desired. Only arguments that have been created by instantiating a CMakeParser can be removed.

Example:

parser = CMakeParser()
parser.remove("--shared", "--static")  # Remove by flags, or
parser.remove("shared", "static")      # remove by dest.
Parameters

*args (str) – Arguments to remove, listed by either flag or dest names. See CMakeParser docs for all flags / dest names added.

Raises
  • ValueError – If "-G" or "generator" in args. The generator argument may not be removed.

  • ValueError – If "extra_args" in args. This is to be prevented from being added, see parse_args().

  • ValueError – If any arguments requested to be removed have not been found. This should only happen if (a) there was a typo, or (b) a user tries to remove an argument that was not registered.

set_argument(arg, **attrs)[source]

Set attributes for arg argument.

Example:

parser = CMakeParser()

# Change default generator from Ninja to Unix Makefiles.
parser.set_argument("generator", default="Unix Makefiles")

# Change default build type from Release to Debug, only allow Release and
# Debug builds (only as demonstration...not useful in practice).
parser.set_argument("build_type", choices={"Release", "Debug"},
                    default="Debug")
Parameters
  • arg (str) – May either be the command-line flag (e.g., "--shared" or "-G"), or the dest of the argument (e.g., "shared" or "generator").

  • **attrs

    The attributes to set. Only the following attributes are allowed to be changed via this method:

    • default: value returned if not specified on command-line.

    • choices: the list of valid values to validate against.

    • required: whether user must specify.

    • help: the help string for the argument.

    • metavar: how the argument is displayed in usage.

    Note

    Other values such as dest or nargs are disallowed from being changed as doing so will break all functionality this class provides.

Raises
  • ValueError – If the argument described by arg cannot be found.

  • ValueError – The keys of **attrs are not supported to be changed. E.g., dest may not be changed.

  • ValueErrorarg in {"-G", "generator"} and "choices" in attrs. The generator choices may not be changed (detection of single vs multi config generators will not be reliable).

Tests

Tests for the ci_exec.parsers.cmake_parser module.

default_cc_cxx()[source]

Return the default (cc, cxx) for the current platform.

test_cmake_parser_is_x_config_generator()[source]

Validate is_single_config_generator() and is_multi_config_generator().

test_cmake_parser_defaults()[source]

Validate the CMakeParser defaults are as expected.

test_cmake_parser_add_argument_failues()[source]

Validate add_argument() fails with expected names.

test_cmake_parser_get_argument()[source]

Validate get_argument() finds both flag and dest names.

test_cmake_parser_remove()[source]

Validate remove() can remove registered arguments (except for generator).

test_cmake_parser_set_argument()[source]

Validate set_argument() can set supported attributes.

test_cmake_parser_extra_args()[source]

Validate add_extra_args works as described.

test_cmake_parser_shared_or_static(capsys)[source]

Validate --shared and --static CMakeParser options.

test_cmake_parser_parse_args_cmake_configure_args()[source]

Validate parse_args works as expected.

test_cmake_parser_single_vs_multi_configure_build_args()[source]

Validate that single vs multi config generators affect configure / build args.