使用install 命令在构建时移动文件通常是一种不好的方法。该命令旨在用于设置将在用户执行make install 或等效操作时安装的文件和目标。由于您没有运行 make install,我希望这就是 install(FILES ...) 命令似乎不起作用的原因。
这里有一些稍微不同的方法来完成这项工作。
如果您不需要,我建议不要移动标题。假设您的库名为MyLib,那么您可以通过target_include_directories 将这些标头作为MyLib 目标的一部分提供:
target_include_directories(MyLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
这意味着如果有一个依赖目标,例如MyExe:
target_link_libraries(MyExe MyLib)
然后它会自动访问MyLib的源目录。
如果库的目录结构不适合将 API 标头与其余的源和标头分开,这可能不太理想。假设MyLib 由以下文件组成:my_lib.cpp、my_lib_api.hh(API 标头 - 供其他项目包含)和 my_lib_detail.hh(其他项目不包含)。理想的结构将 API 标头与其他标头分开,例如
/my_lib
- CMakeLists.txt
- src/
- my_lib.cpp
- my_lib_detail.hh
- include/
- my_lib/
- my_lib_api.hh
有了这个结构,你可以指定
target_include_directories(MyLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include"
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
和MyLib 源将能够包含#include "my_lib_detail.hh" 和#include "my_lib/my_lib_api.hh",但依赖目标的源将只能包含#include "my_lib/my_lib_api.hh"。
因此,如果MyLib 只是一个扁平结构或没有将内部标头与 API 标头分开,您可能需要将 API 标头复制到构建树中的某个位置并添加 that 路径拨打target_include_directories 电话。在这种情况下,如果MyLib 本身不需要访问复制的文件(只是源树中的原始文件),您可以在target_include_directories 调用中使用INTERFACE 而不是PUBLIC。
但是,这个问题的症结(以及我想回答您的实际问题)是将这些文件复制为配置过程(当 CMake 运行时)或构建过程(当 make 运行时)的一部分 - 而不是作为安装过程。
所以,让我们假设MyLib 没有 具有上面显示的有用目录结构,而是扁平的(即 CMakeLists.txt 和三个源文件都在同一个目录中)。我们可以使用构建后命令将 API 标头复制到构建树:
project(my_lib)
cmake_minimum_required(VERSION 2.8.12.2) # for 'target_include_directories'
add_library(MyLib SHARED my_lib.cpp my_lib_api.hh my_lib_detail.hh)
target_include_directories(MyLib INTERFACE "${CMAKE_BINARY_DIR}/include"
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/include/my_lib")
add_custom_command(TARGET MyLib POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/my_lib_api.hh"
"${CMAKE_BINARY_DIR}/include/my_lib"
COMMENT "Copying MyLib public headers to ${CMAKE_BINARY_DIR}/include/my_lib"
VERBATIM)
那么对于MyExe的CMakeLists.txt,你可以这样做:
project(my_exe)
cmake_minimum_required(VERSION 2.8.12.2)
add_executable(MyExe main.cpp)
target_link_libraries(MyExe MyLib)
# Copy MyLib.so to this build dir to allow MyExe to find it at runtime
add_custom_command(TARGET MyExe POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<TARGET_FILE:MyLib>"
"$<TARGET_FILE_DIR:MyExe>"
VERBATIM)
这不适用于 MSVC - 您需要处理 Windows 导出库(有关更多详细信息,请参阅 CMake wiki 和 GenerateExportHeader 的文档),但它只涉及添加关注MyLib的CMakeLists.txt:
include(GenerateExportHeader)
generate_export_header(MyLib
BASE_NAME MyLib
EXPORT_MACRO_NAME MyLib_EXPORT
EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/include/my_lib/my_lib_export.hh"
STATIC_DEFINE MyLib_BUILT_AS_STATIC)
如果您确实需要这个,您必须将target_include_directories(MyLib ...) 中的INTERFACE 更改为PUBLIC,因为MyLib 本身需要访问生成的文件"${CMAKE_BINARY_DIR}/include/my_lib/my_lib_export.hh"。