在 cmake 中展开包含生成器表达式的变量名称

Expand variable name containing a generator expression in cmake

在构建过程中,我设置了收集不同子项目构建输出的目录。目录设置为:

set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_LIST_DIR}/../build/bin/debug" )
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_LIST_DIR}/../build/bin/release" )

现在,我想根据其构建的配置将一些文件(qt 插件目录)复制到该目录。

我试过了:

    # copy qt plugins 
    add_custom_command( TARGET mytarget POST_BUILD
                    COMMAND ${CMAKE_COMMAND} -E copy_directory
                        "${QT_DIR}/../../../plugins"
                        "${$<UPPER_CASE:CMAKE_RUNTIME_OUTPUT_DIRECTORY_$<CONFIG> >}/plugins"
                    COMMAND_EXPAND_LISTS)

因此,我尝试构建一个等于变量名称的字符串,然后尝试按照此处所述展开它:。换句话说:我想要一个生成器表达式,它根据当前构建配置评估 CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUGCMAKE_RUNTIME_OUTPUT_DIRECTOR_RELEASE 的内容。

但是 运行 使用上述语句的 cmake 会导致错误: "CMakeLists.txt:112: error: Syntax error in cmake code at [..] when parsing string ${$<UPPER_CASE:CMAKE_RUNTIME_OUTPUT_DIRECTORY_$<CONFIG> >}/plugins Invalid character ('<') in a variable name: '$'

所以我的问题是,如何使用生成器表达式来访问相应的变量? (附加问题:是否有 another/better 方法来实现相同的目标?)

So my question is, how can I use a generator-expression to access the corresponding variable?

你不能。当前(CMake <=3.23)无法扩展名称由生成器表达式的值确定的变量。

Bonus question: is there another/better way to achieve the same goal?

是的,你快到了!您可以使用 $<TARGET_FILE_DIR:...>:

add_custom_command(
  TARGET mytarget POST_BUILD
  COMMAND
  ${CMAKE_COMMAND} -E copy_directory
  "${QT_DIR}/../../../plugins"
  "$<TARGET_FILE_DIR:mytarget>/plugins"
  VERBATIM
)

这是可行的,因为 TARGET_FILE_DIR 评估包含 mytarget 的可执行文件或库文件的实际目录,无论活动配置、属性 值等如何。

文档:https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#genex:TARGET_FILE_DIR


CMAKE_RUNTIME_OUTPUT_DIRECTORY_<CONFIG> 已经相对于二进制目录,因此您应该 而不是 尝试在其定义中计算二进制目录。此外,它还支持生成器表达式。因此,以下将 更健壮:

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin/$<LOWER_CASE:$<CONFIG>>"
    CACHE STRING "Common output directory for runtime artifacts")

这有很多具体的好处:

  1. 无需设置CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUGCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE
  2. 这将适用于 MinSizeRelRelWithDebInfo,以及您可能添加的任何自定义配置。
  3. 由于它被定义为缓存变量,因此可以覆盖它以进行调试/解决名称冲突等问题。

(3) 的更多上下文:大多数 CMAKE_* 变量打算 read-only 或 user-configurable(即在命令行、从 GUI 等)。通过 set(CACHE) 覆盖它们的默认值是一种礼貌的妥协。此规则的一个显着例外是 Qt 代码生成标志 (CMAKE_AUTO{MOC,RCC,UIC}) 的集合。通常必须为构建设置这些以生成可用的二进制文件。