【问题标题】:In cmake, how to specify dependencies of subdirectories in a scalable way?在cmake中,如何以可扩展的方式指定子目录的依赖关系?
【发布时间】:2012-03-15 10:35:19
【问题描述】:

假设源代码树是这样的结构:

/
 |- lib1
 |  |- src.cpp
 |  |- lib1.h
 |  |- CMakeLists.txt
 |
 |- lib2
 |  |- src.cpp
 |  |- lib2.h
 |  |- CMakeLists.txt
 |
 |- lib3
 |  |- src.cpp
 |  |- lib3.h
 |  |- CMakeLists.txt
 |
 |- app
 |  |- src.cpp
 |  |- CMakeLists.txt
 |
 |- CMakeLists.txt

假设:

  1. lib1 有函数 f();
  2. lib2 有函数 g() 使用 f();
  3. app/src.cpp 使用函数 g();
  4. 没有人使用 lib3。

我想要:

  1. 在 app/CMakeLists.txt 中,它只链接到 lib2。这里的逻辑是,app/src.cpp 只使用了 g(),所以在编写 app/src.cpp 时,我们不能指定对 lib1 的依赖,因为它是 lib2 的实现细节。所以按照这个逻辑,app/CMakeLists.txt中不能有lib1的相关内容,即既不是lib1的include_directories,也不是lib1的add_subdirectory,也不是lib1的target_link_libraries等。
  2. 由于没有人使用 lib3,它甚至不会被构建。这需要自动完成。所以为 lib1 和 lib2 而不是 lib3 手动 add_subdirectory 不是一个聪明的方法。您可以想象,如果我们有一个非常大的源代码树,它具有复杂的树结构和依赖关系,并且在数百个不同的子目录中有数百个可执行文件。如果我只想构建其中的几个,那么我根本不想费心构建未使用的库。

所以我的问题是:有没有办法以可扩展的方式编写 CMakeLists.txt 文件以满足上述要求?如果没有,那么是否有一些类似的工具可以做到这一点?

谢谢。

【问题讨论】:

    标签: c++ cmake build-automation


    【解决方案1】:

    对于第 1 个问题:

    lib2/CMakeLists.txt 你应该这样写:

    target_link_libraries(lib2 lib1)
    

    在 app/CMakeLists.txt 中:

    target_link_libraries(app lib2)
    

    现在,如果您尝试构建应用程序,CMake 将检查 lib2 是否是最新的,如果不是 - 重建 lib1 和 lib2。

    对于第 2 个问题:

    您可以使用基于option() 变量的if() 块来保护add_subdirectory(lib3) 调用。

    另一种方式 - 在 lib3/CMakeLists.txt 中:

    add_library(lib3 ${SRCS} EXCLUDE_FROM_ALL)
    

    这将使 CMake 不会将 lib3 目标添加到 all 目标中。如果您尝试构建依赖于它的东西,或者手动发出make lib3,这个目标仍然会被构建。

    【讨论】:

    • 这并不能解决我的问题。在您的解决方案中,您需要在顶级CMakeLists.txt中的add_subdirectory(lib2)之前添加_subdirectory(lib1),否则lib2/CMakeLists.txt怎么知道项目lib1的存在?这是不可扩展的,因为有数十个子目录,我需要找出它们的依赖关系并正确排序。此外,依赖于 lib1 的 lib2 是 lib2 的实现细节,因此让顶级 CMakeLists.txt 知道这一点在逻辑上是有问题的。此外,随着项目的迭代,依赖关系可能会发生变化,您需要对它们进行重新排序。
    • 您可以按任何顺序调用add_subdirectory(),而无需关心部门。无论如何,您都需要target_link_libraries()。还是你要彻底摆脱根 CMakeFiles.txt?
    • 正如@arrowdodger 所指出的,问题#1 的答案是正确的,并且不涉及管理开销。 Cmake 将找出构建库的正确顺序。
    • 如何将 lib1 头文件提供给 lib2 在链接之前构建 lib2 所需的文件?
    【解决方案2】:

    如果库属于第 3 方或第 2 方,即您不能或不想修复它们的构建方式,那么您可能更喜欢 ExternalProject_Add 而不是 add_subdirectory

    ExternalProject_Add(lib1 /home/me/projects/my_project/lib1 EXCLUDE_FROM_ALL TRUE)
    ExternalProject_Add(lib2 /home/me/projects/my_project/lib2 DEPENDS lib1 EXCLUDE_FROM_ALL TRUE)
    ExternalProject_Add(lib3 /home/me/projects/my_project/lib3 EXCLUDE_FROM_ALL TRUE)
    

    每次调用都会创建一个由第一个参数命名的目标。此目标可用作依赖项。 DEPENDS 关键字位于外部项目依赖项列表之前。 EXCLUDE_FROM_ALL TRUE 表示默认情况下不会构建目标。

    确保此项目已正确安装到可到达的位置,以便在构建后相互查看。

    文档:https://cmake.org/cmake/help/latest/module/ExternalProject.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-05
      • 2012-09-22
      • 1970-01-01
      • 2014-10-07
      • 1970-01-01
      • 2011-11-19
      • 2010-11-20
      相关资源
      最近更新 更多