在cmake中,如何以可伸缩的方式指定子目录的依赖关系

In cmake, how to specify dependencies of subdirectories in a scalable way?

本文关键字:方式指 子目录 关系 依赖 可伸缩 cmake      更新时间:2023-10-16

假设源树的结构如下:

/
 |- 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_directions,也不包括lib1的add_subdirectory,也不包含lib2的target_link_libraries等
  2. 由于没有人使用lib3,它甚至不会被构建。这需要自动完成。因此,为lib1和lib2手动添加subdirectory,而不是为lib3手动添加。您可以想象,如果我们有一个非常大的源树,具有复杂的树结构和依赖关系,并且在数百个不同的子目录中有数百个可执行文件。如果我只想构建其中的几个,那么我根本不想麻烦构建未使用的库

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

谢谢。

对于1个问题:

lib2/CMakeLists.txt中,您应该放置以下内容:

target_link_libraries(lib2 lib1)

和应用程序内/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不将CCD_ 5靶添加到CCD_ 6靶中。如果您试图根据该目标构建某些内容,或者手动发布make lib3,则仍将构建该目标。

如果库属于第三方或第二方,即您不能或不想修复它们的构建方式,那么您可能更喜欢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