C++ 带有子目录的 CMake

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42744315/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 15:30:57  来源:igfitidea点击:

CMake with subdirectories

c++buildcmakedirectory

提问by Van-Sama

I'm trying to set up my project to compile correctly using CMake.

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

My directory looks like this:

我的目录是这样的:

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

My sub-directories will definitely grow as my project grows larger and figured CMake would probably a good idea to learn. At the moment I can only get CMake to work with no sub-directories inside my src/. However, I do expect this project to grow into many sub-directories.

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

Would I need multiple CMakeLists.txtinside each directory with .cpp files? Can anyone point me in the right direction?

我是否需要在每个包含 .cpp 文件的目录中使用多个CMakeLists.txt?任何人都可以指出我正确的方向吗?

Thank you!

谢谢!

采纳答案by The Quantum Physicist

Your project does not seem to need multiple CMakeLists.txt. The purpose of having multiple CMakeLists.txt multiple times is multi-fold, but it doesn't seem to fit in your project. For example, one benefit would be hierarchical organization, so that you can separate different unitsto be built separately, and linked eventually.

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

Example

例子

Consider the situation if you have another directory in your root called tests. That directory contains unit tests that you want the developer to have the choice whether to compile it or not. In that case, you put one CMakeLists.txt in tests, and you enable this in your primary CMakeLists.txt with a add_subdirectory(tests)as so:

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

if(testing_enabled)
    add_subdirectory(tests)
endif()

In tests, there would be another CMakeLists.txt. This way, you separate concerns. The development of your unit tests is independent of the development of your project, and also the build process is separate.

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

Another example

另一个例子

Consider the situation if you have two libraries where the user can choose from. In this case, you have in your roottwo directories, lib1and lib2. Now you can do something like this in your primary CMakeLists.txt:

如果您有两个可供用户选择的库,请考虑这种情况。在这种情况下,你在你的root两个目录,lib1lib2。现在你可以在你的主要 CMakeLists.txt 中做这样的事情:

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

And both lib1and lib2directories contain CMakeLists.txt.

而且两者lib1lib2目录中包含的CMakeLists.txt。

回答by Craig Scott

I'll refer you to this articlefor an in-depth discussion of the two main approaches, but there's a few ways you could structure a project such as this.

我将向您推荐这篇文章,以深入讨论这两种主要方法,但您可以通过多种方式构建这样的项目。

  • One CMakeLists.txt file at the top level which lists all the source files out in all the different subdirectories. You typically only see this for very simple projects.
  • One CMakeLists.txt file in each directory, each one brought in by its parent using add_subdirectory(). This approach is very common.
  • One CMakeLists.txt file at the top level, each subdirectory having its own file that lists its own source files and targets. The top level CMakeLists.txt file brings in the subdirectory files with include(). Less common, but can have advantages over the other two.
  • 顶层的一个 CMakeLists.txt 文件列出了所有不同子目录中的所有源文件。您通常只会在非常简单的项目中看到这一点。
  • 每个目录中有一个 CMakeLists.txt 文件,每个文件都由其父目录使用add_subdirectory(). 这种方法很常见。
  • 顶层有一个 CMakeLists.txt 文件,每个子目录都有自己的文件,其中列出了自己的源文件和目标。顶级 CMakeLists.txt 文件引入带有include(). 不太常见,但可以比其他两个有优势。

Each has its pros and cons. Having just one top level CMakeLists.txt file would only be recommended if there were very few files and subdirectories. Once the project grows, keeping everything in the top level can become too much and make the resultant CMakeLists.txt file harder to follow. It also has the disadvantage that a change for a file addition or removal isn't restricted to a particular directory. That may not seem like a big deal, but if multiple people are working on a project and you want to easily see what part of a project someone else's changes affect (e.g. in a git history), it is harder. This is especially true if you both add/remove a file, thereby both change the top level CMakeLists.txt file and have the possibility of a conflict.

每个都有其优点和缺点。只有在文件和子目录很少的情况下,才建议使用一个顶级 CMakeLists.txt 文件。一旦项目增长,将所有内容都保留在顶层可能会变得太多,并使生成的 CMakeLists.txt 文件更难以遵循。它还有一个缺点,即文件添加或删除的更改不限于特定目录。这可能看起来没什么大不了的,但是如果有多个人在一个项目上工作,并且您想轻松查看其他人的更改影响了项目的哪个部分(例如在 git 历史中),那就更难了。如果您都添加/删除文件,从而更改顶级 CMakeLists.txt 文件并有可能发生冲突,则尤其如此。

Once a project becomes non-trivial in size, most choose to add a CMakeLists.txt file in each subdirectory and use add_subdirectory()to bring them all together. @TheQuantumPhysicist's answer gives a good example of how this can be useful, so I won't repeat most of those details here. This structure offers you the ability to turn on/off whole sections of the build tree easily, but more importantly it gives each subdirectory its own variable scope. This can be important if you want to set variables, etc. in one part of the source tree but not have those changes visible in another part (think compiler flags which you only want to apply to one section of a complex directory structure).

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

The third option of one top level CMakeLists.txt file with each subdirectory providing a file brought in by include()is less common, but it has similarities to using one CMakeLists.txt file in each subdirectory. Both localise details about files in a directory to a CMakeLists.txt or other similarly named file in just that directory. Changes therefore become easier to merge and to understand in version control histories, etc. One thing that this third approach allows which the second doesn't is to use target_link_libraries()a bit more freely when using target_sources()to specify the source files in each subdirectory. The article linked at the top of this answer goes into detail about why target_sources()can be advantageous and it's at the heart of why this third method may well be desirable for many projects.

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

Lastly, I'd suggest you don't pick up the habit of putting your build tree inside your source tree. Rather, create your build tree(s) as siblings of the source tree. Aim to keep your source tree untouched by a build. All it takes is to have someone create a directory in the source tree with the same name as whatever you've used for the build tree for things to go awry (I've seen this more than once!). You may also want to set up multiple build trees for the one source tree, such as one for a Debug build and another as a Release build, so having these outside the source tree also helps keep your source tree less cluttered.

最后,我建议您不要养成将构建树放在源代码树中的习惯。相反,将构建树创建为源树的兄弟。旨在使您的源代码树不受构建影响。所需要的只是让某人在源树中创建一个与您用于构建树的名称相同的目录,以免出现问题(我已经不止一次看到过这种情况!)。您可能还想为一个源代码树设置多个构建树,例如一个用于调试构建,另一个作为发布构建,因此将它们放在源树之外还有助于保持源树不那么混乱。