Skip to content

target_compile_definitions: Diagnose incorrect usage of -D inside a genex

I tried using target_compile_definitions following this stackoverflow advice and I encountered an unintuitive behavior with unhelpful error messages. I believe the error messages can be improved.

The sample code is here:

cmake_minimum_required(VERSION 3.16)
project(sample1)

add_executable(sample1)
target_sources(sample1 PRIVATE main.cpp)
target_compile_definitions(sample1 PRIVATE $<$<CONFIG:Debug>:-DTEST_MACRO>>)

The compilation fails and the resulting output is not very helpful:

~/d/cmake-reproducers/build-sample1$ make
[ 50%] Building CXX object CMakeFiles/sample1.dir/main.cpp.o
<command-line>: warning: ISO C++11 requires whitespace after the macro name
[100%] Linking CXX executable sample1
c++: error: CMakeFiles/sample1.dir/main.cpp.o: No such file or directory
c++: fatal error: no input files
compilation terminated.
make[2]: *** [CMakeFiles/sample1.dir/build.make:84: sample1] Error 1
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/sample1.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

The problem here is that the target_compile_definitions parameter contains an extra >, which produced this compiler command line:

/usr/bin/c++  -D>   -o CMakeFiles/sample1.dir/main.cpp.o -c ~/d/cmake-reproducers/sample1/main.cpp

I believe the user experience can be improved. I see two ways in which it can be done:

  1. CMake can validate the parameters of target_compile_definitions so they don't contain special characters.
  2. CMake can escape the parameters of target_compile_definitions so the special characters don't break bash command line.

I believe the first approach is not portable because it depends on which generator is used. Different shells can use different special characters. So I see the second approach as preferable. CMake knows which generator is used and can escape target_compile_definitions for it appropriately.

There is also a second problem with target_compile_definitions. If I remove the extra > and configure with -DCMAKE_BUILD_TYPE=Debug, I get this command line:

target_compile_definitions(sample1 PRIVATE $<$<CONFIG:Debug>:-DTEST_MACRO>)

[ 50%] Building CXX object CMakeFiles/sample2.dir/main.cpp.o
/usr/bin/c++  -D-DTEST_MACRO  -g   -o CMakeFiles/sample2.dir/main.cpp.o -c ~/d/cmake-reproducers/sample2/main.cpp

I don't know for sure, but the explanation I came up for myself is that CMake adds -D before evaluating generator expressions. Perhaps the order should be inversed: the generator expressions should be evaluated first and then -D is added.

Thank you in advance. If needed I'm happy to provide any additional information or a sample project.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information