cmake install(FILES ...)似乎不起作用

cza*_*ppa 4 c++ install cmake

我有一个用C++编写的项目,我正在使用cmake来构建它.该项目有许多子项目,其中一个是其他子项目所需的库.我可以使用add_library和INSTALL(TARGETS ...)编译并将.so移动到构建目录

但是我还需要将lib的头文件安装在build dir的include目录下.我使用install(FILES ...)来做它,但它似乎根本不做任何事情.

为了演示它,我通过qtcreator创建了一个测试项目,

& ls test
CMakeLists.txt empty.hh main.cpp

$ cat test/CMakeLists.txt
project(test)
cmake_minimum_required(VERSION 2.8)
install(FILES empty.hh DESTINATION include)
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})

$ cat test/main.cpp
#include

using namespace std;

int main()
{
cout << "Hello World!" << endl;
return 0;
}

$ cat test/empty.hh
#ifndef EMPTY_HH
#define EMPTY_HH

#endif // EMPTY_HH

If the files under "test" qtcreator will compile (by default) the files to test-build.
$ ls test-build/
CMakeCache.txt CMakeFiles Makefile cmake_install.cmake test test.cbp
$ ./test-build/test
Hello World!
Run Code Online (Sandbox Code Playgroud)

如您所见,没有包含目录或empty.hh文件.也尝试使用

install(FILES empty.hh DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
Run Code Online (Sandbox Code Playgroud)

但仍然看不到头文件.

$ cmake --help
cmake version 2.8.12
Run Code Online (Sandbox Code Playgroud)

如果您有任何想法,请告诉我.

Fra*_*ser 9

使用该install命令在构建时移动文件通常是一种糟糕的方法.该命令用于设置将在用户执行make install或等效时安装的文件和目标.由于你没有运行make install,我希望这就是install(FILES ...)命令看起来不起作用的原因.

这里有一些稍微不同的方法来完成这项工作.

如果你不需要,我建议不要移动标题.假设您的库被调用MyLib,那么您可以通过以下方式将这些标题作为MyLib目标的一部分提供target_include_directories:

target_include_directories(MyLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
Run Code Online (Sandbox Code Playgroud)

这意味着如果存在依赖目标,例如MyExe:

target_link_libraries(MyExe MyLib)
Run Code Online (Sandbox Code Playgroud)

然后它自动访问MyLib的源目录.


如果库的目录结构不适合将API标头与其他源和标头分开,则这可能不太理想.Say 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
Run Code Online (Sandbox Code Playgroud)

使用此结构,您可以指定

target_include_directories(MyLib PUBLIC  "${CMAKE_CURRENT_SOURCE_DIR}/include"
                                 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
Run Code Online (Sandbox Code Playgroud)

MyLib来源将能够包含#include "my_lib_detail.hh"#include "my_lib/my_lib_api.hh",但依赖目标的来源将只能包含#include "my_lib/my_lib_api.hh".


因此,如果MyLib只有一个扁平结构或者没有将内部标题与API标题分开,您可能需要将API标题复制到构建树中的某个位置,并将路径添加到target_include_directories调用中.在这种情况下,如果MyLib自身不需要访问复制的文件(只是源树中的原件),则可以使用INTERFACE而不是PUBLICtarget_include_directories调用中.

然而,这个问题的关键(并且回答我想到的实际问题)是将这些文件作为配置过程的一部分(当CMake运行时)或构建过程(当make运行时)复制 - 而不是作为安装过程的一部分.

所以,我们假设MyLib 没有上面显示的有用的目录结构,而是平坦的(即CMakeLists.txt和三个源文件都在同一个目录中).我们可以使用post-build命令将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)
Run Code Online (Sandbox Code Playgroud)

那么对于MyExeCMakeLists.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)
Run Code Online (Sandbox Code Playgroud)


这对于MSVC来说无法正常工作 - 您需要处理Windows导出库(有关详细信息,请参阅CMake wiki和文档GenerateExportHeader),但这只会涉及将以下内容添加到MyLibCMakeLists.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)
Run Code Online (Sandbox Code Playgroud)

如果确实需要,则必须更改INTERFACEPUBLICin target_include_directories(MyLib ...),因为MyLib它本身需要访问生成的文件"${CMAKE_BINARY_DIR}/include/my_lib/my_lib_export.hh".