Build CMake:如何最好地构建多个(可选)子项目?

Build CMake:如何最好地构建多个(可选)子项目?,build,cmake,modularity,Build,Cmake,Modularity,设想一个包含多个组件的整体项目: 基本的 木卫一 网 app-a app-b app-c 现在,让我们假设web依赖于io,而io依赖于basic,所有这些东西都在一个repo中,并有一个CMakeLists.txt将它们构建为共享库 如果这三个应用程序都是可选的,并且在构建时可能不存在,我应该如何设置才能构建这三个应用程序? 一个想法是在主repo中有一个空的“apps”目录,我们可以将任何我们想要的app repo克隆到其中。我们的主CMakeLists.txt文件可以使用GLOB查找所

设想一个包含多个组件的整体项目:

  • 基本的
  • 木卫一
  • app-a
  • app-b
  • app-c
现在,让我们假设web依赖于io,而io依赖于basic,所有这些东西都在一个repo中,并有一个CMakeLists.txt将它们构建为共享库

如果这三个应用程序都是可选的,并且在构建时可能不存在,我应该如何设置才能构建这三个应用程序?

一个想法是在主repo中有一个空的“apps”目录,我们可以将任何我们想要的app repo克隆到其中。我们的主CMakeLists.txt文件可以使用GLOB查找所有应用程序目录并构建它们(不知道会有多少)。这种方法的问题包括:

  • 显然,当你只说
    make
    时,CMake不会重新启用,所以如果你添加了一个新应用,你必须再次运行
    CMake
  • 它对进行构建的人施加特定的结构
  • 现在还不清楚一个人是如何将一个应用程序复制成两个克隆,然后根据同一个库构建分别构建这两个应用程序的

一般概念类似于传统的递归CMake项目,但较低级别的模块不一定事先知道哪些较高级别的模块将使用它们。但是,我不想要求用户在固定位置安装较低级别的库(例如
/usr/local/lib
)。但是,我确实希望通过调用
make
来注意整个项目中已更改的依赖项,这样,如果我正在构建一个应用程序,但已更改了其中一个低级库,则所有内容都将适当地重新编译。

具有多个CMakeLists.txt

许多开源项目采用这种方法(LibOpenJPEG、LibPNG、poppler等)。查看他们的CMakeLists.txt,了解他们是如何做到这一点的


基本上允许您根据需要切换功能。

我的第一个想法是使用CMake导入/导出目标功能

有一个用于
basic
io
web
的CMakeLists.txt和一个引用这些内容的CMakeLists.txt。然后,您可以使用CMake导出功能导出这些目标,然后应用程序项目可以导入
CMake目标

首先构建库项目时,应用程序项目应该能够自动查找已编译的库(无需将库安装到
/usr/local/lib
),否则可以始终设置适当的CMake变量以指示正确的目录


当这样做时,应用程序项目中的
make
将不会在库项目中执行
make
,您必须自己解决这个问题。

我看到了两种额外的方法。一种是简单地将basic、io和web作为每个应用程序的子模块。是的,存在代码重复和磁盘空间浪费,但实现起来非常简单,并保证每个应用程序的不同编译器设置不会在共享库中相互干扰。我想这使得图书馆不再被共享,但也许这在2011年不会有什么大不了的。RAM和磁盘已经变得更便宜了,但工程时间却没有,而且源代码的共享可以说比二进制文件的共享更具可移植性


另一种方法是在问题中指定布局,并在每个子目录中设置CMakeLists.txt文件。basic、io和web中的CMakeLists.txt文件生成独立的共享库。每个应用程序目录中的CMakeLists.txt文件使用add_subdirectory()命令拉入每个共享库。然后,您可以下拉所有库目录和您想要的任何应用程序,并从每个应用程序目录中启动构建。

我最后做了我在问题中概述的事情,即签入一个空目录(包含一个忽略所有内容的.gitignore文件),并告诉CMake全局删除任何目录(由用户放入其中)。然后我可以说cmake myrootdir,它确实找到了所有不同的组件。这或多或少是可行的。但它确实有一些副作用,比如像BuildBot这样的一些第三方工具需要一个更传统的项目结构,这使得将其他工具与这种安排集成起来需要更多的工作。

工具p提供实用程序,您可以在其中创建项目的独立模块,并使用ccmake命令有选择地启用和禁用它们


完全公开:我是该项目的开发人员。

您可以使用
添加子目录来实现此目的


问得好。我正在为同一个问题寻找解决方案。检查。它说到点子上了吗?@Antonio:我不知道……我自己用下面的答案中解释的解决方案解决了这个问题。你的链接似乎有点相关,但可能与我原来的问题有点不同。不管怎样,它现在已经离我远去了。:)“我同意共享源代码很重要,所以让我们明确一点:你是在建议在repo之间复制/粘贴代码吗?远不是这样,”约翰·兹温克说。我建议每个应用程序都有三个子模块,每个库(basic、io、web)有一个子模块,每种类型的子模块都从相应的远程应用程序中提取。一般来说,我认为复制和粘贴源代码违反了“不要重复你自己”的准则,但是如果复制是由像git这样的VCS管理的,它会变得更加安全,因为VCS有助于传播更改。这是我们首先使用版本控制系统的主要原因之一。那么,如果导出的目标尚未安装,如何导入它们呢?这与我这里的问题有关:CMake已经有了嵌套项目的工具,所以这似乎不是最好的solution@monokrome用于嵌套项目的工具是什么?2014年我写答案时,这些工具存在吗?如果没有,请