当目标位于子目录中时,替代CMake POST_BUILD命令

时间:2016-10-27 21:02:26

标签: cmake

通常需要确保CMake构建项目在编译后在某个位置结束,并且add_custom_command(..POST_BUILD...)命令是实现该目的的常见设计模式:

add_custom_command(
  TARGET mytarget
  POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:mytarget> ${CMAKE_BINARY_DIR}/final_destination
)

遗憾的是,当有问题的目标位于相对于包含add_custom_command调用的文件的子目录中时,它不起作用,该调用是通过add_subdirectory()命令递归编译的。试图这样做会导致以下错误消息:

CMake Warning (dev) at CMakeLists.txt:4 (add_custom_command):
  Policy CMP0040 is not set: The target in the TARGET signature of
  add_custom_command() must exist.  Run "cmake --help-policy CMP0040" for
  policy details.  Use the cmake_policy command to set the policy and
  suppress this warning.

  TARGET 'mytarget' was not created in this directory.
This warning is for project developers.  Use -Wno-dev to suppress it.

在许多情况下,有一个简单的解决方法:只需确保add_custom_command()调用发生在子目录的CMakeLists.txt文件中,一切都会正常工作。

但是,这并不总是可行的!子目录可以是我们无法控制的外部依赖项的CMake项目。例如,将CMake递归编译与Git子模块相结合是很常见的,在这种情况下,无法永久存储子项目构建系统的修改。

我的问题归结为以下内容:CMake是否提供了另一种机制来创建一个目标,该目标将在重建子项目目标时自动触发,并且可用于将最终可执行文件或共享库复制到其他目标位置?

我的目标是自动发生,而无需专门用另一个目标调用'make'/'ninja'。此外,副本只应在实际需要时执行(根据cmake文档,某些add_custom_ *命令不会跟踪它们是否确实需要运行并保守地假设目标始终是陈旧的)。 p>

1 个答案:

答案 0 :(得分:4)

只需使用add_custom_commandadd_custom_target的通用组合,当第一个组合为第二个生成文件时:

# Because OUTPUT option may not use generator expressions,
# extract name of file from target's properties.
get_target_properties(mytarget_basename mytarget OUTPUT_NAME)
get_target_properties(mytarget_suffix mytarget SUFFIX)
set(mytarget_filename ${mytarget_basename}${mytarget_suffix})
# make copied file be dependent from one which is build.
# Note, that DEPENDS here creates dependencies both from the target
# and from the file it creates.
add_custom_command(OUTPUT
        ${CMAKE_BINARY_DIR}/final_destination/${mytarget_filename}
    COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:mytarget>
        ${CMAKE_BINARY_DIR}/final_destination
    DEPENDS mytarget
)
# Create target which consume the command via DEPENDS.
add_custom_target(copy_files ALL
    DEPENDS ${CMAKE_BINARY_DIR}/final_destination/${mytarget_filename}
)

与使用POST_BUILD相比,此代码使用其他目标。但是你别无选择:add_custom_command无法附加到在其他目录中创建的目标。

通常,不是将可执行文件/库复制到其他二进制目录中,而是通过CMAKE_<TYPE>_OUTPUT_DIRECTORY变量指定此目录更简单。