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文件创build静态库并设置包含目录:

 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,我可以构buildapp1和app2,并成功构build。 但是,如果我想要构build这些项目中的一个(例如通过从app1运行CMake)而不是从顶层目录构build,则会出现错误,因为common/include不会添加到标头searchpath中。

我明白为什么会发生这种情况。 CMakeLists.txt文件中没有任何“引入”常见的app1或app2。 这只在顶层完成。

有没有办法解决这个问题,或者这种行为通常被认为是可以接受的? 是关于我的设置次优? 我只是想,如果我们开始开发使用这个通用库的越来越多的可执行文件,那么能够单独构build项目而不是从顶层构build项目会很好,但也许这是我不应该做的关心。

只有当这个子项目打算作为独立项目和顶层项目的一部分build立时,你应该在子目录中使用project()命令。 例如,LLVM和Clang就是这种情况:Clang可以单独编译,但是当LLVM构build系统检测到Clang源时,它也包含它的目标。

在你的情况下,你不需要子项目。 仅编译app1app2目标问题在项目中创buildmake app1 / make app2构build目录。

当你设置你的构build环境时,你应该考虑以下三个主题(除了其他人之外,对于这个讨论/回答,我把它缩小到了三个我认为与此相关的部分):

  1. 依赖/耦合
  2. 部署
  3. 小组

“强耦合”

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

  • 一个经常变化的common图书馆
  • 针对所有应用的单个部署(stream程和时间安排)
  • 一个团队在完整的源代码基础上工作
    • IDE将在一个解决scheme中显示所有内容
    • 你为每件事生成一个构build环境

“松耦合”

如果你想要更多的“松耦合”,你可以使用其他语言的外部脚本或使用CMake的ExternalProject_Add()macros。 所以,如果你设置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) ExternalProject_Add(app2 SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/app2 PREFIX app2) 

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) 

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

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

参考

  • 在CMake项目中使用CMake启用的库(II)
  • CMake:如何设置Source,Library和CMakeLists.txt的依赖关系?