我使用CMake生成跨平台构建配置。对于项目的工作,我需要复制额外的预编译库到二进制目录。因此,我使用这样的脚本来构建这个项目:
cmake_minimum_required(VERSION 3.17)
project(foo)
add_executable(bar foobar.cpp)
# Doing some logic to find library files...
list(APPEND DBG_LIBRARIES_LIST "lib1" "lib2")
list(APPEND REL_LIBRARIES_LIST "lib1" "lib2")
# Joining all libraries with " " character to be parsed as different program arguments
list(JOIN DBG_LIBRARIES_LIST " " DEBUG_LIBRARIES)
list(JOIN REL_LIBRARIES_LIST " " RELEASE_LIBRARIES)
add_custom_command(TARGET bar POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<IF:$<CONFIG:Debug>,${DEBUG_LIBRARIES},${RELEASE_LIBRARIES}>
$<TARGET_FILE_DIR:estareng>
)
在我使用VS16在Windows上生成这样的项目后,我的构建后事件包含这样的行:
cmake -E copy_if_different "lib1 lib2" someprojdir
如果我尝试使用$<JOIN:$<IF:$<CONFIG:Debug>,${DEBUG_LIBRARIES_LIST},${RELEASE_LIBRARIES_LIST}>," ">
加入列表,我只是在构建后事件中获得原始生成器表达式。
注意:在GNU/Linux上,使用makefiles或Ninja都可以正常工作
这应该可以工作:
cmake_minimum_required(VERSION 3.18)
project(test)
add_executable(bar foobar.cpp)
list(APPEND DBG_LIBRARIES "lib1" "lib2")
list(APPEND REL_LIBRARIES "lib1" "lib2")
add_custom_command(
TARGET bar POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"$<IF:$<CONFIG:Debug>,${DBG_LIBRARIES},${REL_LIBRARIES}>"
"$<TARGET_FILE_DIR:bar>"
COMMAND_EXPAND_LISTS
VERBATIM
)
设置VERBATIM
后,COMMAND
的每个参数都被认为是一个单个命令行参数,即使里面有空格或分号。如果没有这个选项,对COMMAND
的参数的解释是平台特定的。正如你所注意到的,这有时意味着在空格上分词,而其他时候则不是。
教训1:您应该始终使用VERBATIM
选项与add_custom_command
。
但是,不要忘记在此发生之前CMake自己的参数拆分运行。因此,如果没有$<IF:...>
周围的双引号,DBG_LIBRARIES
和REL_LIBRARIES
中的分号将把它分割成add_custom_command
的许多参数,其中没有一个是完整的生成器表达式。这就是为什么你会看到&;raw&;命令行上的生成器表达式。
2课:总是将单个参数与变量展开括在双引号中。
最后,我们传递COMMAND_EXPAND_LISTS
,这样在生成器表达式处理之后,任何包含;
的参数都会在;
上被分割成多个参数。