【问题标题】:CMake - dependencies (headers) between apps/libraries in same projectCMake - 同一项目中的应用程序/库之间的依赖项(标头)
【发布时间】:2012-06-28 07:21:29
【问题描述】:

我的项目结构如下:

  • CMakeLists.txt
    • lib1/CMakeLists.txt 和 lib 的所有 cpp 和头文件
    • lib2/CMakeLists.txt 和 lib 的所有 cpp 和头文件
    • app/CMakeLists.txt 以及应用的所有cpp和头文件

主要的 CMakeLists.txt 看起来像:

PROJECT( ${PROJECT_NAME} )
add_subdirectory(lib1)
add_subdirectory(lib2)
add_subdirectory(app)

lib1/CMakeLists.txt 看起来像(剥离):

SET(SOURCE
file.cpp
)
SET(HEADERS
    some_lib_header.h
)
add_library( lib1 ${SOURCE} ${HEADERS} )

除了 ADD_EXECUTABLE 之外,应用程序的外观相同:

SET(SOURCE
main.cpp
)
SET(HEADERS
    some_header.h
)
add_library( lib1 ${SOURCE} ${HEADERS} )
ADD_EXECUTABLE( app ${SOURCE} ${HEADERS} )

我发现这种设置运行良好,因为这样,我可以生成一个包含所有这三个项目的 Visual Studio 解决方案文件。但我的问题是我的应用程序包含 lib1 的头文件(以及 lib2 的头文件,这取决于 lib1)。当我这样做时

$mkdir build
$cd build
$cmake -C ..\myproject

它会根据我的需要生成源外的 VS .sln 文件,但应用程序无法编译,因为它找不到 lib1 的头文件(显然)。

现在我阅读并尝试了很多东西,比如 TARGET_LINK_LIBRARIES( app lib1 )(它让应用程序与 lib1 链接,但没有解决标头包含问题),以及 CMakeLists.txt 中各种变体中的 add_subdirectory( ../lib1 ) app (都抛出了我无法修复的错误),还有 find_package (我猜这是错误的方法)。

那么我该如何解决这个(我猜很简单......)问题?

【问题讨论】:

    标签: c++ visual-studio-2010 dependencies cmake header-files


    【解决方案1】:

    这是一种可能的解决方案:

    根 CMakeLists.txt:

    cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
    project(${PROJECT_NAME})
    add_subdirectory(lib1)
    add_subdirectory(lib2)
    add_subdirectory(app)
    


    lib1/CMakeLists.txt:

    project(Lib1)
    add_library(lib1 lib1.cpp lib1.h)
    


    lib2/CMakeLists.txt:

    project(Lib2)
    add_library(lib2 lib2.cpp lib2.h)
    
    # Add /lib1 to #include search path
    include_directories(${Lib1_SOURCE_DIR})
    # Specify lib2's dependency on lib1
    target_link_libraries(lib2 lib1)
    


    app/CMakeLists.txt:

    project(App)
    add_executable(app main.cpp some_header.h)
    
    # Add /lib1 and /lib2 to #include search path
    include_directories(${Lib1_SOURCE_DIR} ${Lib2_SOURCE_DIR})
    # Specify app's dependency on lib2.
    # lib2's dependency on lib1 is automatically added.
    target_link_libraries(app lib2)
    


    这里有很多不同的方法可以达到相同的最终结果。对于一个相对较小的项目,我可能只使用一个 CMakeLists.txt:

    cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
    project(Test)
    
    add_library(lib1 lib1/lib1.cpp lib1/lib1.h)
    add_library(lib2 lib2/lib2.cpp lib2/lib2.h)
    add_executable(app app/main.cpp app/some_header.h)
    
    include_directories(${CMAKE_SOURCE_DIR}/lib1 ${CMAKE_SOURCE_DIR}/lib2)
    
    target_link_libraries(lib2 lib1)
    target_link_libraries(app lib2)
    


    有关相关命令及其原理的更多信息,请运行:

    cmake --help-command add_subdirectory
    cmake --help-command include_directories
    cmake --help-command target_link_libraries
    

    【讨论】:

    • 项目很大,所以我不喜欢一个 CMakeLists.txt。
    • 您提出的第一个解决方案有一个问题:您在每个 lib/app CMakeLists.txt 文件的开头指定了一个项目(...)。那不是很糟糕的风格,我应该在根 CMakeLists.txt 中只使用一次 project(...) 吗?此外,如果我在每个 CMakeLists.txt 文件中使用 project(...),CMake 会为每个项目生成一个 .sln 文件(除了包含所有项目的根 .sln 之外)和其他不必要的东西,这是一种从未使用过的开销,也可能不是最佳解决方案?
    • @Ela782 是的 - 不用担心。除了最小的项目之外,多个 CMakeLists.txt 文件可以很好地简化任何事情。
    • @Ela782 不 - 只有一个顶级 .sln add_subdirectory 的文档很好地解释了这一点。
    • 只要我添加一个例如“project(App)”到我的应用程序 CMakeLists.txt,我还在 app-dir 中获得了第二个 sln 文件,以及其他一些文件。造成这种情况的不是 add_subdirectory。
    【解决方案2】:
    Project
     CMakeLists.txt
     \-lib1
       CMakeLists.txt
       \- include \ lib1
       \- src
     \-lib2
       CMakeLists.txt
       \- include \ lib2
       \- src
     \-app
       CMakeLists.txt
       \- src
    

    假设依赖如下:

    lib1 ---> lib2 ---> app 
       \--------------> app
    

    类似这样的:

    CMakeLists.txt:

    add_subdirectory(lib1)
    add_subdirectory(lib2)
    add_subdirectory(app)
    

    lib1/CMakeLists.txt:

      file(GLOB_RECURSE _HDRS "include/*.hpp")
      file(GLOB_RECURSE _SRCS "src/*.[hc]pp")
      add_library(lib1 ${_HDRS} ${_SRCS})
      #target_link_libraries(lib1)
      target_include_directories(lib1 PUBLIC include)
    
      install(TARGETS lib1 DESTINATION lib)
      install(FILES ${_HDRS} DESTINATION include/lib1)
    

    lib2/CMakeLists.txt:

      file(GLOB_RECURSE _HDRS "include/*.hpp")
      file(GLOB_RECURSE _SRCS "src/*.[hc]pp")
      add_library(lib2 ${_HDRS} ${_SRCS})
      target_link_libraries(lib2 lib1)
      target_include_directories(lib2 PUBLIC include)
    
      install(TARGETS lib2 DESTINATION lib)
      install(FILES ${_HDRS} DESTINATION include/lib2)
    

    所以在 lib2/src/file.cpp 你可以做#include <lib1/header.hpp>

    app/CMakeLists.txt:

      file(GLOB_RECURSE _SRCS "src/*.[hc]pp")
      add_executable(app ${_SRCS})
      target_link_libraries(app lib1 lib2)
    
      install(TARGETS app DESTINATION bin)
    

    所以在 app/src/file.cpp 你可以做#include <lib1/header.hpp>#include <lib2/header.hpp>

    神奇的是target_include_directories 将“include”目录附加到目标,因此在与它链接时,您也可以拉出包含目录;)

    【讨论】:

    • 唯一遗憾的是 cmake 不安装目标的标头,所以你需要一个丑陋的额外 install(files ...) 我已经尝试 PUBLIC_HEADER DESTINATION include/libinstall(TARGETS ...) 内没有成功
    • 这是一种更合适的实现方式,因为这里不必手动列出依赖标头
    猜你喜欢
    • 2012-02-22
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-17
    相关资源
    最近更新 更多