具有多个可执行文件的CMake共享库

时间:2015-10-30 19:01:52

标签: cmake

我的项目包含几个共享一些常用代码的可执行文件。我想将公共代码放在可执行文件可以链接到的静态库中。 (公共代码非常小,我不想处理共享库。)

源树看起来像这样:

  • 项目
    • 的CMakeLists.txt
    • 共同
      • 的CMakeLists.txt
      • SRC
      • 包括
    • APP1
      • SRC
      • 的CMakeLists.txt
    • APP2
      • SRC
      • 的CMakeLists.txt

app1和app2都取决于共同的代码。

此公共代码非常特定于应用程序,并且永远不需要由此目录树之外的其他项目使用。出于这个原因,我宁愿不在任何类型的全球位置安装库。

顶级CMakeLists.txt文件只添加子目录:

project(toplevel)
cmake_minimum_required(VERSION 3.1)

add_subdirectory(common)
add_subdirectory(app1)
add_subdirectory(app2)

公共库的CMakeLists.txt文件创建静态库并设置包含目录:

add_library(common STATIC common.cpp) 
target_include_directories(common PUBLIC "${CMAKE_CURRENT_LIST_DIR}/include")

可执行文件的文件如下所示:

project(app1)
cmake_minimum_required(VERSION 3.1)

add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} common)

现在提出我的问题。如果我从顶级项目目录运行CMake,我可以构建app1和app2并且它们可以成功构建。但是,如果我想构建这些项目中的单个项目(例如,通过从app1运行CMake)而不是从顶级目录构建,我会收到错误,因为common/include未添加到标题搜索路径

我明白为什么会这样。对于app1或app2,CMakeLists.txt文件中没有任何内容可以"拉入"共同。这只在顶层完成。

有没有解决方法,或者这种行为通常被认为是可接受的?关于我的设置是次优的吗?我认为,如果我们开始开发越来越多使用这个公共库的可执行文件,那么能够单独构建项目而不是从顶级构建项目会很好,但也许这是我不应该做的事情。 #39;关注。

2 个答案:

答案 0 :(得分:9)

当你设置你的构建环境时,你应该考虑以下三个主题(除了其他主题,但是对于这个讨论/答案,我将它减少到我认为在这里相关的三个主题):

  1. Dependecies / Coupling
  2. 部署
  3. “强耦合”

    我开始认为add_subdirectory()命令支持“强耦合”,并且您当前的设置隐含支持:

    • 经常更改的common
    • 所有应用的单一部署(流程和时间)
    • 一个团队致力于完整的源代码库
      • IDE会在一个解决方案中显示所有内容
      • 您为所有内容生成一个构建环境

    “松耦合”

    如果您想要更多"loose coupling",您可以使用其他语言的外部脚本或使用CMake的ExternalProject_Add()宏。因此,如果您将common库(可能甚至包括“二进制交付”)和每个app设置为您支持的单独项目:

    • 不常更改common
      • 可能有自己的发布周期
    • 每个应用程序的独立开发/部署周期
    • 由不同开发人员组成的团队app

    两者的混合

    因此,您可以看到有很多事情需要考虑,CMake可以为您提供各种方法的支持。考虑到您的项目可能处于早期阶段,您可能采用混合方法(不立即解除common库的分离):

    <强>的CMakeLists.txt

    project(toplevel)
    cmake_minimum_required(VERSION 3.1)
    
    include(ExternalProject)
    
    ExternalProject_Add(
        app1 
        SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/app1"
        PREFIX app1
        INSTALL_COMMAND ""
    )
    ExternalProject_Add(
        app2 
        SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/app2"
        PREFIX app2
        INSTALL_COMMAND ""
    )
    

    <强> APP1 /的CMakeLists.txt

    project(app1)
    cmake_minimum_required(VERSION 3.1)
    
    add_subdirectory(../common common)
    
    add_executable(${PROJECT_NAME} src/main.cpp)
    target_link_libraries(${PROJECT_NAME} common)
    

    这实际上会生成三个构建环境。一个直接在二进制输出目录中,一个在app1app2个子目录中。

    在这种方法中,您可能需要考虑常见的CMake工具链文件。

    <强>参考

答案 1 :(得分:5)

You should use project() command in subdirectories only if this subproject is intended to be built both as standalone and as a part of toplevel project. This is the case for LLVM and Clang, for example: Clang can be compiled separately, but when LLVM build system detects Clang source, it includes its targets too.

In your case you don't need subprojects. To compile only app1 or app2 target issue make app1/make app2 in projects build dir.