使用子目录进行CMake

时间:2017-03-12 06:03:45

标签: c++ build cmake directory

我正在尝试使用CMake设置我的项目以正确编译。

我的目录如下所示:

root
 |- bin
 |   |- // Where I want to build CMake from - using 'cmake ..'
 |- build
 |   |-
 |- include
 |   |- database
 |   |    |- database.h
 |- src
     |- database
     |    |- database.cpp
     |- main
          |- main.cpp

我的子目录肯定会随着我的项目变大而增长,并认为CMake可能是个好主意。目前我只能让CMake在我的src /中没有子目录。但是,我确实希望这个项目成长为许多子目录。

我需要在.cpp文件的每个目录中使用多个 CMakeLists.txt 吗?有人能指出我正确的方向吗?

谢谢!

2 个答案:

答案 0 :(得分:14)

我将引用您this article深入讨论两种主要方法,但有几种方法可以构建这样的项目。

  • 顶级的一个CMakeLists.txt文件,列出了所有不同子目录中的所有源文件。您通常只会在非常简单的项目中看到这一点。
  • 每个目录中的一个CMakeLists.txt文件,每个目录由其父级使用add_subdirectory()引入。这种方法很常见。
  • 顶级的一个CMakeLists.txt文件,每个子目录都有自己的文件,列出了自己的源文件和目标。顶级CMakeLists.txt文件带有include()的子目录文件。不太常见,但可以优于其他两个。

每个都有其优点和缺点。只有一个顶级CMakeLists.txt文件才会被推荐,如果只有很少的文件和子目录。一旦项目增长,将所有内容保持在最高级别可能会变得太多,并使得生成的CMakeLists.txt文件更难以遵循。它还有一个缺点,即文件添加或删除的更改不限于特定目录。这可能看起来不是什么大问题,但如果有多个人正在开展一个项目并且你想轻易看到别人的变化对项目的哪个部分产生影响(例如在git历史中),那就更难了。如果您同时添加/删除文件,则会更改顶级CMakeLists.txt文件并可能发生冲突。

一旦项目变得非常简单,大多数人都选择在每个子目录中添加一个CMakeLists.txt文件,并使用add_subdirectory()将它们组合在一起。 @TheQuantumPhysicist的答案给出了一个很好的例子,说明这是如何有用的,所以我不会在这里重复大部分细节。这种结构使您能够轻松地打开/关闭构建树的整个部分,但更重要的是,它为每个子目录提供了自己的变量范围。如果要在源树的一个部分中设置变量等,而不是在另一个部分中显示这些更改,则这很重要(想想您只想应用于复杂目录结构的一个部分的编译器标记)。 / p>

一个顶级CMakeLists.txt文件的第三个选项,每个子目录提供include()引入的文件不太常见,但它与在每个子目录中使用一个CMakeLists.txt文件有相似之处。两者都将有关目录中文件的详细信息本地化到CMakeLists.txt或该目录中的其他类似命名文件。因此,更改在版本控制历史记录等中变得更容易合并和理解。第三种方法允许的第二种方法是使用target_link_libraries()指定时更自由地使用target_sources()每个子目录中的源文件。本回答顶部链接的文章详细介绍了为什么target_sources()可能是有利的,并且为什么第三种方法可能适用于许多项目的核心原因。

最后,我建议你不要养成将构建树放在源代码树中的习惯。而是将您的构建树创建为源树的兄弟姐妹。旨在保持源树不受构建的影响。所需要的只是让某人在源树中创建一个目录,其名称与您用于构建树的任何内容相同,以便出现错误(我不止一次看过这个!)。您可能还希望为一个源树设置多个构建树,例如一个用于Debug构建,另一个构建为Release构建,因此在源树外部使用这些树也有助于保持源树不那么混乱。

答案 1 :(得分:9)

您的项目似乎不需要多个CMakeLists.txt。多次使用多个CMakeLists.txt的目的是多方面的,但它似乎并不适合您的项目。例如,一个好处是层次结构组织,因此您可以将不同的 单元 分开构建,并最终链接。

示例

如果您的根目录中有另一个名为tests的目录,请考虑这种情况。该目录包含您希望开发人员可以选择是否编译它的单元测试。在这种情况下,您将一个CMakeLists.txt放在tests中,然后在主CMakeLists.txt中使用add_subdirectory(tests)启用此功能,如下所示:

if(testing_enabled)
    add_subdirectory(tests)
endif()

tests中,会有另一个CMakeLists.txt。这样,您可以分开关注点。单元测试的开发独立于项目的开发,构建过程也是独立的。

另一个例子

如果您有两个用户可以选择的库,请考虑这种情况。在这种情况下,您有root个目录lib1lib2。现在,您可以在主CMakeLists.txt中执行类似的操作:

if(IWantLib1)
    add_subdirectory(lib1)
else()
    add_subdirectory(lib2)
endif()

lib1lib2目录都包含CMakeLists.txt。