具有重复编译标志的CMake生成器表达式



我正在尝试使用CMake生成器表达式进行依赖于编译器的配置。该配置的一部分是使用include目录列表设置编译器标志,类似于CMake在其文档中的内容。然而,由于某种原因,JOIN表达式在这种情况下不能正常工作。下面是一个简化的例子:

cmake_minimum_required(VERSION 3.6)
project(NinjaPlayground)
add_executable(NinjaPlayground main.cpp)
list(APPEND LIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/libraryOne/include")
list(APPEND LIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/librartTwo/include")
target_compile_options(NinjaPlayground PRIVATE
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-isystem $<JOIN:${LIB_INCLUDE_DIRS}, -isystem >>
$<$<CXX_COMPILER_ID:MSVC>:-experimental:external -external:w -external:I $<JOIN:${LIB_INCLUDE_DIRS}, -external:I >>)

如果我在UNIX系统中构建它,则此配置生成的命令如下所示:

/usr/bin/c++-isystem /home/the-dreams-wind/Documents/Ninja/libraryOne/include /home/the-dreams-wind/Documents/Ninja/librartTwo/include-MD -MT CMakeFiles/NinjaPlayground.dir/main.cpp.o -MF CMakeFiles/NinjaPlayground.dir/main.cpp.o.d -o CMakeFiles/NinjaPlayground.dir/main.cpp.o -c ../main.cpp

正如你所看到的,列表被扩展了,但联接表达式忽略了它

target_compile_options(NinjaPlayground PRIVATE
"$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-isystem $<JOIN:${LIB_INCLUDE_DIRS}, -isystem >>"
"$<$<CXX_COMPILER_ID:MSVC>:-experimental:external -external:w -external:I $<JOIN:${LIB_INCLUDE_DIRS}, -external:I >>")

它正确地连接字符串,但将引号保留在参数列表中:

/usr/bin/c++"-isystem /home/the-dreams-wind/Documents/Ninja/libraryOne/include -isystem /home/the-dreams-wind/Documents/Ninja/librartTwo/include"-MD -MT CMakeFiles/NinjaPlayground.dir/main.cpp.o -MF CMakeFiles/NinjaPlayground.dir/main.cpp.o.d -o CMakeFiles/NinjaPlayground.dir/main.cpp.o -c ../main.cpp

MSVC也会出现同样的问题。需要明确的是,我预期的结果应该是这样的:

/usr/bin/c++-isystem /home/the-dreams-wind/Documents/Ninja/libraryOne/include -isystem /home/the-dreams-wind/Documents/Ninja/librartTwo/include-MD -MT CMakeFiles/NinjaPlayground.dir/main.cpp.o -MF CMakeFiles/NinjaPlayground.dir/main.cpp.o.d -o CMakeFiles/NinjaPlayground.dir/main.cpp.o -c ../main.cpp

我知道我可以循环浏览列表并逐个添加选项,但我想了解我在这里缺少了什么?

玩了一段时间后,发现问题归结为空间和参数重复数据消除。部分地,可以通过移除选项(例如-systemi(与其参数(路径(之间的空间来处理它。然而,有些标志无法避免重复(如-Xclang选项(。为了抑制重复数据消除,CMake 3.12中引入了前缀SHELL:。它保留空间,正确解析参数,可以这样使用:

target_compile_options(NinjaPlayground PRIVATE
"$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:SHELL:-isystem$<JOIN:${LIB_INCLUDE_DIRS}, -isystem>>"
"$<$<CXX_COMPILER_ID:MSVC>:SHELL:-experimental:external -external:w -external:I$<JOIN:${LIB_INCLUDE_DIRS}, -external:I>>")

最新更新