How to Define a C++ Preprocessor MACro Through the Command Line with Cmake

How to define a C++ preprocessor macro through the command line with CMake?

The motivation behind the question was to batch build 3rd party libraries, which is why I wanted to avoid modifying CMakeLists. So years later, even though I don't need that anymore, I figured out that it's easily achievable by means external to CMake:

  • Invoke CMake as usual, no special flags.

  • Then:

    • With MSVC: The compiler reads the CL environment variable to get extra command line arguments. So

        set CL=/DMY_MACRO=1 %CL%

      then invoke MSBuild to do its job.

    • With Makefiles: The generated makefiles use the CFLAGS and CXX_FLAGS variables as makefiles are expected to do. So the build can be started by

        make CXX_FLAGS=-DMY_MACRO=1

      or by setting the corresponding environment variables.

Define preprocessor macro through CMake?

For a long time, CMake had the add_definitions command for this purpose. However, recently the command has been superseded by a more fine grained approach (separate commands for compile definitions, include directories, and compiler options).

An example using the new add_compile_definitions:

add_compile_definitions(OPENCV_VERSION=${OpenCV_VERSION})
add_compile_definitions(WITH_OPENCV2)

Or:

add_compile_definitions(OPENCV_VERSION=${OpenCV_VERSION} WITH_OPENCV2)

The good part about this is that it circumvents the shabby trickery CMake has in place for add_definitions. CMake is such a shabby system, but they are finally finding some sanity.

Find more explanation on which commands to use for compiler flags here: https://cmake.org/cmake/help/latest/command/add_definitions.html

Likewise, you can do this per-target as explained in Jim Hunziker's answer.

Use value from C/C++ macro in CMake

I'd go with file(READ ...) to read the header followed by string(REGEX ...) to extract desired define.

Example code:

file(READ "foo.h" header)
string(REGEX MATCH "#define FOO_MAJOR_VERSION [0-9]+" macrodef "${header}")
string(REGEX MATCH "[0-9]+" FooMajorVersion "${macrodef}")

How to add macro's definition in cmake?

Take a look at add_definitions, which will add your definitions to your compiler command line, e.g. -D with gcc, or /D with MSVC. Try something like:

add_definitions( -DBOOST_FILESYSTEM_VERSION=2 )

In your case, I would definitely go with the add_definition method, but an alternative may to take a look at configure_file. Then you can create a header-file template, which will be filled with cmake-values and include this in your source files. This can be useful if you have many, many configurable parameters which are determined by CMake.

Preprocessor definitions not propagating from CMake to Unix Makefiles

As @steveire mentioned, an SSCCE would be helpful. Nonetheless, there's a good chance that the problem is related to the order/location of your add_subdirectory calls in relation to the add_definitions calls.



First, just to be clear, variables set by CMake don't have any bearing on preprocessor definitions unless you explicitly tie them together. What I mean is that if you call

cmake -DTOPPINGS=Haggis .

or have set(TOPPINGS Haggis) in your CMakeLists.txt, the preprocessor won't see any Haggis unless you also have something like

add_definitions(-DTOPPINGS=${TOPPINGS})



OK, so for an example, consider the following CMakeLists.txt:

cmake_minimum_required(VERSION 3.1)
project(MyTest)
add_executable(MyTestExe main.cpp)
add_subdirectory(One)
add_definitions(-DTOPPINGS=Haggis)
add_subdirectory(Two)
target_link_libraries(MyTestExe One Two)

In this case, targets defined in the CMakeLists.txt of subdir "One" won't have TOPPINGS as a PP definition since add_subdirectory(One) comes before the add_definitions call. If "One" sets any PP definitions using add_definitions, they won't propagate back up to the top-level or to "Two".

However, since add_subdirectory(Two) comes after the add_definitions call, all targets defined in there (and any of its subdirs) will have TOPPINGS as a PP definition.

Finally, the target MyTestExe will also have TOPPINGS as a PP definition, regardless of where the add_executable call comes in relation to the add_definitions call.



Some of this confusion can possibly be avoided by using target_compile_definitions instead of add_definitions. This gives much more fine-grained control of PP definitions; we don't want haggis leaking everywhere!

Say we remove the line add_definitions(-DTOPPINGS=Haggis) from the CMakeLists.txt. Now in the CMakeLists.txt of subdir "Two", we can do:

add_library(Two two.hpp two.cpp)
# Note, we don't need to use -D here, but it doesn't matter if you do
target_compile_definitions(Two PUBLIC TOPPINGS=Haggis PRIVATE SIDE=Whisky)

This causes the PP definitions TOPPINGS and SIDE to be applied to the single target library Two, regardless of how many other targets we may define in the same CMakeList.txt.

Since TOPPINGS is declared as PUBLIC, it causes CMake to apply it to any other target which links Two. We're doing that in the top-level CMakeLists.txt when we call target_link_libraries(MyTestExe One Two), so MyTestExe will also have TOPPINGS as a PP definition, but it won't have SIDE since that's PRIVATE to Two.

How to declare a function like macro using CMake

From the Visual Studio documentation on /D:

The /D option doesn't support function-like macro definitions. To insert definitions that can't be defined on the command line, consider the /FI (Name forced include file) compiler option.

For completeness, GCC does support defining function macros from the commandline:

If you wish to define a function-like macro on the command line, write its argument list with surrounding parentheses before the equals sign (if any). Parentheses are meaningful to most shells, so you should quote the option. With sh and csh, -D'name(args…)=definition' works.

Can CMake custom help text(like AC_ARG_WITH)?

There is option() command that declares bool variable and sets description text for it.

There is no way to show it with cmake command, but you can run cmake-gui or ccmake, which display all options along with descriptions.



Related Topics



Leave a reply



Submit