如何通过CMake add_compile_definitions正确传递编译选项列表?
解决CMake编译选项作为字符串宏传递给C++代码的错误
问题重现
用户编写的CMakeLists.txt片段:
add_executable(hello main.cpp) set(helloCompileOptions -Wall -Wextra -O3 -Wno-narrowing -ffast-math -march=native) target_compile_options(hello PRIVATE ${helloCompileOptions}) target_compile_features(hello PUBLIC cxx_std_23) add_compile_definitions(COMPILE_OPTIONS="${helloCompileOptions}")
编译时出现如下错误:
[build]
:1:9: error: macro name must be an identifier
[build] 1 | #define -O3 1
[build] | ^
[build]:2:9: error: macro name must be an identifier
[build] 2 | #define -Wextra 1
[build] | ^
...
错误原因
add_compile_definitions会将空格视为宏定义的分隔符,当传递COMPILE_OPTIONS="${helloCompileOptions}"时,CMake会把列表展开后的空格当作分隔,生成多个非法的宏定义(比如-O3不是合法的C标识符),导致编译报错。
解决方案
方法一:使用$<JOIN>生成带引号的字符串(CMake 3.12+支持)
利用CMake的生成器表达式$<JOIN>将编译选项列表拼接成单个字符串,再传递给target_compile_definitions:
add_executable(hello main.cpp) set(helloCompileOptions -Wall -Wextra -O3 -Wno-narrowing -ffast-math -march=native) target_compile_options(hello PRIVATE ${helloCompileOptions}) target_compile_features(hello PUBLIC cxx_std_23) target_compile_definitions(hello PRIVATE COMPILE_OPTIONS="$<JOIN:${helloCompileOptions}, >" )
方法二:先拼接字符串再传递
用string(JOIN)提前将列表转为单个字符串,再通过add_compile_definitions传递:
add_executable(hello main.cpp) set(helloCompileOptions -Wall -Wextra -O3 -Wno-narrowing -ffast-math -march=native) target_compile_options(hello PRIVATE ${helloCompileOptions}) target_compile_features(hello PUBLIC cxx_std_23) # 将列表元素用空格拼接成单个字符串 string(JOIN " " helloCompileOptionsStr ${helloCompileOptions}) add_compile_definitions(COMPILE_OPTIONS="${helloCompileOptionsStr}")
效果验证
处理后,CMake会生成正确的宏定义:
#define COMPILE_OPTIONS "-Wall -Wextra -O3 -Wno-narrowing -ffast-math -march=native"
C++代码中直接使用COMPILE_OPTIONS即可获取编译选项的字符串。
内容的提问来源于stack exchange,提问作者Paul Jurczak
相关产品推荐
相关产品推荐

