【问题标题】:Generator Expression for install() commandsinstall() 命令的生成器表达式
【发布时间】:2015-04-30 14:55:46
【问题描述】:

CMake 3.2.2 的文档指出,可以将生成器表达式用于install(<FILES|PROGRAMS> ...) 签名。我试图在install() 的其他签名中使用生成器表达式,但显然它不起作用。我想做这样的事情:

install(TARGETS foo EXPORT fooConfig
        RUNTIME DESTINATION "Bin/$<CONFIG>"
        LIBRARY DESTINATION "Lib/$<CONFIG>"
        ARCHIVE DESTINATION "Lib/$<CONFIG>"

我也尝试过多次这样调用install()

install(TARGETS foo EXPORT fooConfig
        RUNTIME DESTINATION "Bin/Debug" CONFIGURATIONS Debug
        LIBRARY DESTINATION "Lib/Debug" CONFIGURATIONS Debug
        ARCHIVE DESTINATION "Lib/Debug" CONFIGURATIONS Debug
install(TARGETS foo EXPORT fooConfig
        RUNTIME DESTINATION "Bin/Release" CONFIGURATIONS Release
        LIBRARY DESTINATION "Lib/Release" CONFIGURATIONS Release
        ARCHIVE DESTINATION "Lib/Release" CONFIGURATIONS Release
install(TARGETS foo EXPORT fooConfig
        RUNTIME DESTINATION "Bin/MinSizeRel" CONFIGURATIONS MinSizeRel
        LIBRARY DESTINATION "Lib/MinSizeRel" CONFIGURATIONS MinSizeRel
        ARCHIVE DESTINATION "Lib/MinSizeRel" CONFIGURATIONS MinSizeRel
install(TARGETS foo EXPORT fooConfig
        RUNTIME DESTINATION "Bin/RelWithDebInfo" CONFIGURATIONS RelWithDebInfo
        LIBRARY DESTINATION "Lib/RelWithDebInfo" CONFIGURATIONS RelWithDebInfo
        ARCHIVE DESTINATION "Lib/RelWithDebInfo" CONFIGURATIONS RelWithDebInfo

这会导致 CMake 发出错误,类似于 在 'fooConfig' 中多次导出目标 'foo'

如果不更新 CMake 缓存并重新运行构建,我也无法在此处使用 CMAKE_BUILD_TYPE。而不是这样,我想使用 Visual Studio 批量构建功能,它为我构建多个配置。

我也尝试了一个小技巧。我注意到 CMake 生成的INSTALL 项目只是简单地调用带有参数-DBUILD_TYPE=$(Configuration) 的CMake 脚本${CMAKE_BINARY_DIR}/cmake_install.cmake。所以我尝试了以下方法:

install(TARGETS foo EXPORT fooConfig
        RUNTIME DESTINATION "Bin/\${BUILD_TYPE}"
        LIBRARY DESTINATION "Lib/\${BUILD_TYPE}"
        ARCHIVE DESTINATION "Lib/\${BUILD_TYPE}"

这实际上对安装很有效。但是,已安装的导出脚本,即install(EXPORT fooConfig DESTINATION .) 的输出现在也尝试使用${BUILD_TYPE},在用户包含该脚本时未设置...

如果有人知道实现我目标的另一种方法,请告诉我。

【问题讨论】:

    标签: cmake


    【解决方案1】:

    不幸的是,install 命令只支持要安装的文件列表的生成器表达式,但不支持目标目录。

    我建议坚持你的小技巧,但使用CMAKE_INSTALL_CONFIG_NAME 而不是CMAKE_BUILD_TYPE,即:

    install(TARGETS foo EXPORT fooConfig
            RUNTIME DESTINATION "Bin/\${CMAKE_INSTALL_CONFIG_NAME}"
            LIBRARY DESTINATION "Lib/\${CMAKE_INSTALL_CONFIG_NAME}"
            ARCHIVE DESTINATION "Lib/\${CMAKE_INSTALL_CONFIG_NAME}"
    

    CMAKE_INSTALL_CONFIG_NAME 设置为用于在生成的cmake_install.cmake 脚本中安装的实际构建配置。

    生成的导出脚本(例如,fooConfig-debug.cmake)可以通过在安装过程中添加补丁脚本来自动修复。在源目录下生成文件patch_export_files.cmake,内容如下:

    file(GLOB_RECURSE _configFiles "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/fooConfig-*.cmake")
    foreach(_configFile ${_configFiles})
        file (READ "${_configFile}" _contents)
        string (REGEX MATCH "configuration \"[A-Za-z]+\"" _configName "${_contents}")
        if (_configName MATCHES "\"([A-Za-z]+)\"")
            message(STATUS "Patching: ${_configFile}")
            string (REPLACE "\${CMAKE_INSTALL_CONFIG_NAME}" "${CMAKE_MATCH_1}" _patchedContents "${_contents}")
            file (WRITE "${_configFile}" "${_patchedContents}")
        endif()
    endforeach()
    

    补丁脚本需要在安装时通过在install(EXPORT ...之后添加install(SCRIPT ...调用来运行:

    install(EXPORT fooConfig DESTINATION .)
    ...
    install(SCRIPT patch_export_files.cmake)
    

    补丁脚本首先从其头部注释中解析生成的导出脚本有效的配置,然后将每次使用${CMAKE_INSTALL_CONFIG_NAME}替换为配置名称。

    【讨论】:

    • 我预计我必须做这样的事情......很遗憾 CMake 不支持这样的事情。在他们的问题跟踪系统中,我看到他们最近为所有 install() 签名的 DESTINATION 参数实现了生成器表达式,但尚未正式发布此功能。所以对于未来的用户:最新版本的 CMake (>3.2.2) 可能已经支持生成器表达式,而不是 install(FILES)。
    【解决方案2】:

    我正在开发一个需要使用不同配置进行构建的项目。我实现这一目标的方法是使用“ExternalProject”。

    我创建了一个示例存储库来向您展示这个想法: https://github.com/mpaluru/cmake_multiple_build_configs_example

    (Linux 是我最常使用的环境,无法访问 Visual Studio。) 如果您在顶级 CMakeLists.txt 中传递 -G 标志,您应该能够生成您的 VS 文件。我已经在 Linux 上对此进行了测试,并且“make -j”工作正常。 Debug 和 Release 配置都是并行构建的。

    总结: 您创建一个新的超级构建项目,该项目使用具有不同 CMAKE_BUILD_TYPE 的 ExternalProject_Add 调用您的项目。

    并且根据构建类型,您传递不同的定义,或者进行不同的安装。

    【讨论】:

    • ExternalProject 是个好主意,但这需要我更改现有的源代码树,对吧?
    • 否和是。这取决于您当前项目的配置方式。如果你已经根据变量 CMAKE_BUILD_TYPE 做了不同的事情,你根本不需要修改现有的项目。正如我在示例代码中指出的那样,您所做的就是创建一个新的包装器项目。
    • 但是这个包装器项目必须存在于现有代码之外,至少比原始源根目录高一级。或者有什么方法可以将这个包装器直接合并到根目录中?也许通过多重包含?
    • 是的,没错。你可以让它在同一级别上工作,但它可能有点太老套了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-11
    • 1970-01-01
    • 2022-12-03
    • 2017-12-08
    • 2016-04-27
    • 1970-01-01
    相关资源
    最近更新 更多