【问题标题】:cmake install(FILES ...) doesn't seem to be workingcmake install(FILES ...) 似乎没有工作
【发布时间】:2014-12-27 09:23:42
【问题描述】:

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

但是我还需要将 lib 的头文件安装在构建目录的包含目录下。 我使用 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!

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

install(FILES empty.hh DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

但还是看不到头文件。

$ cmake --help
cmake version 2.8.12

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

【问题讨论】:

    标签: c++ cmake installation


    【解决方案1】:

    使用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 wikiGenerateExportHeader 的文档),但它只涉及添加关注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"

    【讨论】:

    • 嗨弗雷泽,谢谢你。不幸的是,我无法尝试这个,因为我没有 cmake 2.8.12.2 。但是您的解决方案似乎很有希望,我稍后会尝试。在此之前,我将使用 file(COPY) 将头文件复制到所需的位置。再次感谢!
    • 感谢您的详细解答。如果您的 MyLib 实际上是二进制文件(不是库),但您仍想使用标头,该怎么办? target_link_libraries(MyExe MyLib) 在这种情况下不起作用“EXECUTABLE 类型的目标 MyLib 可能无法链接到另一个”
    猜你喜欢
    • 1970-01-01
    • 2013-11-25
    • 2017-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多