如何使用多个相互依赖的子目录构建一个c++项目?

时间:2022-09-11 16:31:23

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. 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? Making the directories libraries doesn't seem to fit here, since they are all interdependent and not intended to be used that way.

我有一个c++项目,在这个项目中,我更多地使用目录作为组织元素——就像在Java中使用包或者在PHP中使用目录一样。目录不打算是自给自足的元素,而只是一种组织整个项目的方式,使我不至于被来源压得喘不过气来。我如何构建我的CMakeLists。txt文件来处理这个?使目录库看起来不适合这里,因为它们都是相互依赖的,不打算这样使用。

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. 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?

作为一个相关的问题,我在CMake中看到的许多子目录的例子(这些例子并不多)都忽略或掩盖了设置include_directory的问题,这是我一直遇到的问题。除了将我的源文件合并到确定哪个文件取决于哪个目录和在哪个目录中,是否有必要在/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文件来处理这种结构?

2 个解决方案

#1


51  

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. The following CMake file may serve as a starting point:

由于项目中的目录结构只是用来组织文件的,所以一种方法是使用CMakeLists。txt,自动查找src目录中的所有源文件,并将所有目录添加为包含有头文件的目录。以下CMake文件可以作为起点:

cmake_minimum_required(VERSION 3.0)

project (Foo)

file(GLOB_RECURSE Foo_SOURCES "src/*.cpp")
file(GLOB_RECURSE Foo_HEADERS "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.

这两个文件(GLOB_RECURSE…命令确定源文件和头文件的集合。foreach循环从所有头文件的列表中计算包含目录集。

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. You manually have to re-create your build files then.

计算源文件集的一个缺点是CMake不会自动检测何时将新文件添加到源树中。您需要手动重新创建构建文件。

#2


2  

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. Organizing source and include files in different directories is pretty much the norm.

我不是CMake方面的专家,但是由于没有其他的答案,我将查看文档并尝试一下。在不同的目录中组织源文件和包含文件是很常见的。

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#命令:include_directory

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_executivecommand中列出所有源文件:

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 (e.g. in src and include).

这是一种让所有东西都建起来的幼稚方式。将编译每个源文件,并在所有这些目录中查找头文件,然后将对象文件链接到一起。考虑一下,如果有什么方法可以简化这个过程,使您不需要那么多的include文件夹,那么可能只有几个公共的头文件需要被所有源文件引用。如果事情变得更复杂,您可以将子层次结构设置到库中等等。还可以考虑分离源文件和头文件(例如在src和include中)。

#1


51  

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. The following CMake file may serve as a starting point:

由于项目中的目录结构只是用来组织文件的,所以一种方法是使用CMakeLists。txt,自动查找src目录中的所有源文件,并将所有目录添加为包含有头文件的目录。以下CMake文件可以作为起点:

cmake_minimum_required(VERSION 3.0)

project (Foo)

file(GLOB_RECURSE Foo_SOURCES "src/*.cpp")
file(GLOB_RECURSE Foo_HEADERS "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.

这两个文件(GLOB_RECURSE…命令确定源文件和头文件的集合。foreach循环从所有头文件的列表中计算包含目录集。

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. You manually have to re-create your build files then.

计算源文件集的一个缺点是CMake不会自动检测何时将新文件添加到源树中。您需要手动重新创建构建文件。

#2


2  

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. Organizing source and include files in different directories is pretty much the norm.

我不是CMake方面的专家,但是由于没有其他的答案,我将查看文档并尝试一下。在不同的目录中组织源文件和包含文件是很常见的。

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#命令:include_directory

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_executivecommand中列出所有源文件:

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 (e.g. in src and include).

这是一种让所有东西都建起来的幼稚方式。将编译每个源文件,并在所有这些目录中查找头文件,然后将对象文件链接到一起。考虑一下,如果有什么方法可以简化这个过程,使您不需要那么多的include文件夹,那么可能只有几个公共的头文件需要被所有源文件引用。如果事情变得更复杂,您可以将子层次结构设置到库中等等。还可以考虑分离源文件和头文件(例如在src和include中)。