与子目录CMake

Van*_*Van 15 c++ directory build cmake

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

我的目录如下所示:

root
 |- bin
 |   |- // Where I want to build CMake from - using 'cmake ..'
 |- build
 |   |-
 |- include
 |   |- database
 |   |    |- database.h
 |- src
     |- database
     |    |- database.cpp
     |- main
          |- main.cpp
Run Code Online (Sandbox Code Playgroud)

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

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

谢谢!

Cra*_*ott 23

我将向您介绍这篇文章,以深入讨论这两种主要方法,但是有一些方法可以构建这样的项目.

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

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

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

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

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

  • 是的,我已经假设你的意思是你在 `build` 目录而不是 `bin` 中运行 CMake。通常的方法是从构建目录运行 CMake。可以从任何地方运行 CMake,并且仍然使用未记录的 `-B` 选项将特定目录用作构建目录,但除非有充分理由,否则我不建议您这样做。 (2认同)

The*_*ist 14

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

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

if(testing_enabled)
    add_subdirectory(tests)
endif()
Run Code Online (Sandbox Code Playgroud)

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

另一个例子

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

if(IWantLib1)
    add_subdirectory(lib1)
else()
    add_subdirectory(lib2)
endif()
Run Code Online (Sandbox Code Playgroud)

两个lib1lib2目录都包含CMakeLists.txt.