简体   繁体   English

如何构建具有多个相互依赖的子目录的 C++ 项目?

[英]How can I build a C++ project with multiple interdependent subdirectories?

I have a C++ project where I've used directories as more of an organizational element -- the way one might use packages in Java or directories in PHP.我有一个 C++ 项目,我在其中使用目录作为更多的组织元素——人们可能使用 Java 中的包或 PHP 中的目录的方式。 Directories are not intended to be self-sufficient elements, but rather just a way of organizing the whole of the project and keeping me from being overwhelmed by sources.目录并不是自给自足的元素,而只是一种组织整个项目并防止我被来源淹没的方式。 How can I construct my CMakeLists.txt files to deal with this?如何构建我的 CMakeLists.txt 文件来处理这个问题? Making the directories libraries doesn't seem to fit here, since they are all interdependent and not intended to be used that way.制作目录库似乎不适合这里,因为它们都是相互依赖的,不打算以这种方式使用。

As a related issue, most of the examples I've seen of multiple subdirectories in CMake (and there aren't very many of those) have ignored or glossed over the issue of setting include_directories , which is something I've been having trouble with.作为一个相关问题,我在 CMake 中看到的多个子目录的大多数示例(并且这些子目录不是很多)都忽略或掩盖了设置include_directories的问题,这是我一直遇到的问题. Short of combing my source files to determine which file depends on which and in what directory, is there anyway to just set all directories under /src/ as potential include directories and let CMake work out which ones are actually dependent?没有组合我的源文件来确定哪个文件依赖于哪个目录以及在哪个目录中,无论如何将/src/下的所有目录设置为潜在的包含目录并让 CMake 计算出哪些实际上是依赖的?

Here's an example structure:这是一个示例结构:

--src
  --top1
    --mid1
      --bot1
        --src1.cpp
        --hdr1.h
      --bot2
        --src2.cpp
        --hdr2.h
    --mid2
      --bot3
        --src3.cpp
        --src4.cpp
        --hdr3.h
  --top2
    --mid3
      --src5.cpp
      --hdr4.h

So on and so forth.等等等等。 How can I structure my CMakeLists.txt files to handle this sort of structure?如何构建我的CMakeLists.txt文件来处理这种结构?

Since the directory structure in your project is just there to keep your files organized, one approach is to have a CMakeLists.txt that automatically finds all sources files in the src directory and also adds all directories as include directories that have a header file in them.由于项目中的目录结构只是为了让文件井井有条,一种方法是使用CMakeLists.txt自动查找src目录中的所有源文件,并将所有目录添加为包含头文件的目录. The following CMake file may serve as a starting point:以下 CMake 文件可以作为起点:

cmake_minimum_required(VERSION 3.12)

project (Foo)

file (GLOB_RECURSE Foo_SOURCES CONFIGURE_DEPENDS "src/*.cpp")
file (GLOB_RECURSE Foo_HEADERS CONFIGURE_DEPENDS "src/*.h")

set (Foo_INCLUDE_DIRS "")
foreach (_headerFile ${Foo_HEADERS})
    get_filename_component(_dir ${_headerFile} PATH)
    list (APPEND Foo_INCLUDE_DIRS ${_dir})
endforeach()
list (REMOVE_DUPLICATES Foo_INCLUDE_DIRS)

add_executable(FooExe ${Foo_SOURCES})
target_include_directories(FooExe PRIVATE ${Foo_INCLUDE_DIRS})

The two file(GLOB_RECURSE ... commands determine the set of source and header files. The foreach loop computes the set of include directories from the list of all header files. The CONFIGURE_DEPENDS flags tells CMake to re-run the glob command at build time.这两个file(GLOB_RECURSE ...命令确定一套源文件和头文件。该foreach循环计算一组包含所有头文件的列表目录,其中的CONFIGURE_DEPENDS国旗在编译的时候告诉CMake的重新运行该命令的glob .

One drawback with computing the set of source files is that CMake will not automatically detect when new files are added to your source tree.计算源文件集的一个缺点是 CMake 不会自动检测何时将新文件添加到您的源代码树中。 You manually have to re-create your build files then.然后您必须手动重新创建构建文件。

Though @sakra gave a good answer to this question, I believe it is more proper to approach it more in depth.虽然@sakra 对这个问题给出了很好的答案,但我认为更深入地研究它更合适。

We want to separate our code into modules and libraries for many reasons.出于多种原因,我们希望将代码分成模块和库。 Like code encapsulation, re usability, easier debugging etc. This idea would propagate in compiling process too.像代码封装、可重用性、更容易调试等。这个想法也会在编译过程中传播。

In other word, we want to divide the compilation process into little compilation steps, each belong to one module.换句话说,我们想把编译过程分成几个小的编译步骤,每个步骤都属于一个模块。 So every module must have its own compilation procedure.所以每个模块都必须有自己的编译过程。 This is why we use one CMakeLists.txt file per directory.这就是我们为每个目录使用一个CMakeLists.txt文件的原因。 Hence every directory would have its own compilation commands and there would be one master CMakeLists.txt file in the root directory of your project.因此,每个目录都有自己的编译命令,并且在项目的根目录中会有一个主CMakeLists.txt文件。

Here is an example.这是一个例子。 Consider the following structure of a project:考虑以下项目结构:

src/
|
- main.cpp
|
_sum/
    |
    - sum.h
    |
    - sum.cpp

We would have one CmakeLists.txt Per directory.我们将有一个CmakeLists.txt每个目录。 First directory is the root directory of the project which src/ folder is in it.第一个目录是src/文件夹所在项目的根目录。 here is content for that file:这是该文件的内容:

cmake_minimum_required(VERSION 3.4)
project(multi_file)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "-Wall")

add_subdirectory(src) 

Next CMakeLists.txt would located in src/ directory:接下来CMakeLists.txt将位于src/目录中:

add_subdirectory("sum")

add_executable(out main.cpp)
target_link_libraries(out sum)

And the last one will be in the sum/ directory:最后一个将在sum/目录中:

add_library(sum SHARED sum.cpp)

I hope this helps.我希望这有帮助。 I created a github repository in case you feel you need to see the code or you need further explanation.我创建了一个github 存储库,以防您觉得需要查看代码或需要进一步解释。

I'm not an expert on CMake but since there are no other answers I'll take a look at the documentaton and give it a go.我不是 CMake 的专家,但由于没有其他答案,我将查看文档并试一试。 Organizing source and include files in different directories is pretty much the norm.在不同目录中组织源文件和包含文件几乎是常态。

It looks like CMake allows you to give a list of include directories: http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:include_directories看起来 CMake 允许您提供包含目录的列表: http : //www.cmake.org/cmake/help/cmake-2-8-docs.html#command : include_directories

So something like:所以像:

include_directories("src/top1/mid1/bot1" "src/top1/mid1/bot2/" ... )

These are passed to the compiler so it can find the header files and will be passed for each of the source files.这些被传递给编译器,以便它可以找到头文件,并将为每个源文件传递。 So any of your source files should be able to include any of the header files (which I think is what you're asking for).所以你的任何源文件都应该能够包含任何头文件(我认为这就是你所要求的)。

Similar to that you should be able to list all your source files in the add_executable command:与此类似,您应该能够在add_executable命令中列出所有源文件:

add_executable(name "src/top1/mid1/bot1/src1.cpp" "src/top1/id1/bot2/src2.cpp" ...)

So this would be a naive way of getting everything to build.所以这将是一种让一切都构建起来的幼稚方式。 Each source file will be compiled and will look for headers in all those directories and then the object files will get linked together.每个源文件都将被编译并在所有这些目录中查找头文件,然后将目标文件链接在一起。 Consider if there is any way of simplifying this such that you don't need so many include folders, maybe there are only a few common header files that need to be referenced by all source files.考虑是否有任何方法可以简化这一点,这样您就不需要这么多包含文件夹,也许只有几个公共头文件需要被所有源文件引用。 If things get more complex you can buiild sub-hierarchies into libraries etc. Also consider seperating source files and headers (eg in src and include).如果事情变得更复杂,您可以将子层次结构构建到库等中。还可以考虑将源文件和头文件分开(例如在 src 和 include 中)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM