在CMake的构建后步骤中将目标文件复制到另一个位置

48

我有一个动态库,根据配置而有不同的名称,由CMake脚本指定:

set_target_properties(${name} PROPERTIES OUTPUT_NAME ${outputName}64)
set_target_properties(${name} PROPERTIES DEBUG_OUTPUT_NAME ${outputName}64_d)

最终结果是,我的发行版和调试版的名称不同。我想将生成的库作为后构建步骤复制到另一个目录中,但是CMake-Fu的祝福并没有对我生效。

我尝试了这样做:

GET_TARGET_PROPERTY(origfile mylibrary LOCATION)
STRING(REGEX REPLACE "/" "\\\\" origfile ${origfile})

set(targetfile my_target_path\\${CMAKE_CFG_INTDIR}\\)
STRING(REGEX REPLACE "/" "\\\\" targetfile ${targetfile})

add_custom_command(TARGET mylibrary POST_BUILD
    COMMAND copy ${origfile} ${targetfile}
)
这对于发布版本运行良好,但对于调试,源代码没有包含我预期的“_d”。 如何获取目标的输出路径,以便我可以复制该文件? 注意: 如上面的片段所示,目前这是针对Windows/Visual Studio的,但我希望这也适用于OS X/Xcode/make。 注意: 我需要将库放置在额外的目录中,该目录作为几个依赖于此库的其他项目的输出目录,使得这些项目能够在运行时加载库。 另一个可接受的解决方案是能够创建一个自定义目标来进行复制,以便其他项目可以依赖于此项目,而此项目则依赖于该库。
3个回答

75

应优先使用生成器表达式,而不是使用已过时的LOCATION属性:

add_custom_command(TARGET mylibrary POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:mylibrary> ${targetfile}
)

你也可以通过设置目标属性RUNTIME_OUTPUT_DIRECTORY直接在目标目录中生成exe,而不是复制它。 这具有每个配置选项(例如RUNTIME_OUTPUT_DIRECTORY_DEBUG)。

set_target_properties(mylibrary PROPERTIES
                      RUNTIME_OUTPUT_DIRECTORY_DEBUG <debug path>
                      RUNTIME_OUTPUT_DIRECTORY_RELEASE <release path>
)

获取更多详细信息请运行:

cmake --help-property "RUNTIME_OUTPUT_DIRECTORY"
cmake --help-property "RUNTIME_OUTPUT_DIRECTORY_<CONFIG>"

此外,即使在Windows系统中也应该能够使用前斜杠作为路径分隔符。


2
如果你的目标是Xcode或Visual Studio,你可能想使用RUNTIME_OUTPUT_DIRECTORY,让IDE负责附加正确的配置(就像你运行@Fraser添加的帮助命令时发现的那样)。 - Joe Steele
1
警告:此问题特别涉及动态库,正如“cmake --help-property "RUNTIME_OUTPUT_DIRECTORY"”所指出的那样,在Windows上它们的工作方式有根本性的不同。在Windows上,您会得到一个.LIB文件和一个.DLL文件,而.DLL文件被视为运行时组件(因此DLL遵循“RUNTIME_OUTPUT_DIRECTORY”)。在Linux上,.so文件结合了链接器和加载器(ld和ld.so)的两个角色,因此它不会被复制到“RUNTIME_OUTPUT_DIRECTORY”。 - MSalters
差劲的回答。以下链接提供了更好、更清晰的解释:https://thomas.trocha.com/blog/cmake--copy-files-after-build/ - flm
有没有可能使用导入的库来完成它,例如使用 include_external_msproject?当我尝试使用 set_target_properties 设置目标属性到我的库和/或添加 add_custom_command 时,要求的库不会复制到输出目录中吗? - Yuriy Rusinov

16

POST_BUILD命令中使用生成器表达式,而不是手动计算输出路径。这些表达式可以根据配置自适应。例如:

add_custom_command(TARGET mylibrary POST_BUILD 
  COMMAND "${CMAKE_COMMAND}" -E copy 
     "$<TARGET_FILE:mylibrary>"
     "my_target_path/$<CONFIGURATION>/$<TARGET_FILE_NAME:mylibrary>" 
  COMMENT "Copying to output directory")

5
其他答案不太清楚...
假设你正在构建一个可执行文件test_base.exe,以下步骤将会构建该可执行文件,并将.exe文件复制到基本的“build”目录:
add_executable(test_base "")
target_sources(test_base
    PRIVATE
        catch_main.cpp
        catch_tests.cpp
        sc_main.cpp
)
target_link_libraries(test_base PRIVATE Catch2 systemc)

add_custom_command(TARGET test_base POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:test_base> ${PROJECT_BINARY_DIR}/test_base.exe
    COMMENT "Created ${PROJECT_BINARY_DIR}/test_base.exe"
)

所以,运行后你的项目将拥有以下内容: <项目目录>/build/test_base.exe

请问$<TARGET_FILE:test_base>是什么意思?这是CMake语法吗?! - Ebrahim Karimi
是的,那是标准的CMake语法。它被称为“生成器表达式”,https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html。 - driedler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接