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. Soset CL=/DMY_MACRO=1 %CL%
then invoke MSBuild to do its job.
With Makefiles: The generated makefiles use the
CFLAGS
andCXX_FLAGS
variables as makefiles are expected to do. So the build can be started bymake 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
How to Add a Timed Delay to a C++ Program
What Does '&' Do in a C++ Declaration
Why Is the New Random Library Better Than Std::Rand()
Taking the Address of a Temporary Object
How to Separate C++ Main Function and Classes from Objective-C And/Or C Routines at Compile and Link
How to Validate an Integer Input
Global Scope VS Global Namespace
When to Use Const and Const Reference in Function Args
Performance of Unsigned VS Signed Integers
Confusion Between C++ and Opengl Matrix Order (Row-Major VS Column-Major)
Is the Pass-By-Value-And-Then-Move Construct a Bad Idiom
How to Use Std::Async Without Waiting for the Future Limitation
Know If .Lib Is Static or Import
How to Compose Output Streams, So Output Goes Multiple Places at Once