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:
- CMake can validate the parameters of
target_compile_definitions
so they don't contain special characters. - 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.