CMake - 根据另一个目标制作整个子树?

时间:2018-02-13 12:07:34

标签: cmake dependencies targets

考虑像这样的项目布局:

CMakeLists.txt
  |
  |------/Project1
  |        |
  |        |-----CMakeLists.txt
  |        |
  |        |-----/Project1.lib1  //needs Project3.lib1
  |        |        |
  |        |        |-----CMakeLists.txt
  |        |        |-----lib1.cpp
  |        |
  |        |-----/Project1.lib2  //needs Project3.lib1
  |        |-----/Project1.lib3
  |        |-----...
  |        |-----/Project1.libn  //some need Project3.lib1
  |
  |------/Project2  //Totally independent
  |        |
  |        |-----/Project2.lib1
  |        |-----/Project2.lib2
  |
  |------/Project3
           |
           |-----/Project3.lib1

当然,所有子目录都有CMakeLists.txt和代码文件。每个CMakeLists.txt都使用 add_subdirectory 抓取所有相应的子目录。

每个ProjectX.libY的CMakeLists都有一个 add_library(name srcs),其中一些依赖于 Project3.lib1 。 不幸的是, Project1 非常不稳定且很大,而且事情变化很快。那里有很多子项目,我担心有人可能会忘记保持Project3的依赖项是最新的。在Project1上遍布一千个add_dependencies(Project1.libY Project3.lib1)将会非常痛苦。 特别是当涉及到Multicore(make -j8)时,正确的依赖树是必不可少的。否则,我们可能遇到 Project1.libY 退出的零星问题,因为 Project3 尚未构建,但需要。 所以我想做的是告诉CMAKE甚至不进入Project1-Folder,只要Project3还没有构建/更新。像

这样的东西
//Project1/CMakeLists.txt
#...
Project (Project1)
add_dependencies (Project1 Project3)
# or add_dependencies (Project1 Project3.lib1)
#...

你们有什么线索让我知道如何实现这个目标?

Thanx很多!

1 个答案:

答案 0 :(得分:1)

首先:尽可能优先target_link_libraries优先于add_dependencies。特别是在表达库之间的依赖关系时,它几乎总是更好的工具。如果您有充分的理由(例如,您依赖的目标不会生成自己的任何可跟踪的构建工件),则只能使用add_dependencies

我知道这种情况会在大多数程序员中引发DRY反射,但请记住,构建系统代码与普通代码有不同的权衡。更明确的通常会提高整个系统的可维护性,即使这意味着在构建脚本中重复了很多东西。

另请注意,CMake的设计目的是将目标作为组织构建的基本概念。因此,如果您不小心,从构建树的物理布局确定依赖关系可能会导致长期严重的麻烦。所以即使你绝对确定你想要不必重复写出依赖关系,基于定义目标的目录这样做可能不是最好的方法。

所有这一切,如果您仍然相信您想要做的事情确实是您项目的正确解决方案,link_libraries就是这样做的。

作为最后警告,我给你留下link_libraries手册中的引用:

  

注意:应尽可能首选target_link_libraries()命令。库依赖项是自动链接的,所以   很少需要目录范围的链接库规范。

您在示例中提到,并非所有Project1.libN都真正依赖Project3。这清楚地表明您应该基于每个目标明确地建模依赖关系。正如您自己所说,依赖树反映项目的实际依赖关系至关重要。确保这一点的唯一方法是正确编写所有内容,并确保您的开发人员也了解如何执行此操作。