繁体   English   中英

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

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

我有一个 C++ 项目,我在其中使用目录作为更多的组织元素——人们可能使用 Java 中的包或 PHP 中的目录的方式。 目录并不是自给自足的元素,而只是一种组织整个项目并防止我被来源淹没的方式。 如何构建我的 CMakeLists.txt 文件来处理这个问题? 制作目录库似乎不适合这里,因为它们都是相互依赖的,不打算以这种方式使用。

作为一个相关问题,我在 CMake 中看到的多个子目录的大多数示例(并且这些子目录不是很多)都忽略或掩盖了设置include_directories的问题,这是我一直遇到的问题. 没有组合我的源文件来确定哪个文件依赖于哪个目录以及在哪个目录中,无论如何将/src/下的所有目录设置为潜在的包含目录并让 CMake 计算出哪些实际上是依赖的?

这是一个示例结构:

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

等等等等。 如何构建我的CMakeLists.txt文件来处理这种结构?

由于项目中的目录结构只是为了让文件井井有条,一种方法是使用CMakeLists.txt自动查找src目录中的所有源文件,并将所有目录添加为包含头文件的目录. 以下 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})

这两个file(GLOB_RECURSE ...命令确定一套源文件和头文件。该foreach循环计算一组包含所有头文件的列表目录,其中的CONFIGURE_DEPENDS国旗在编译的时候告诉CMake的重新运行该命令的glob .

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

虽然@sakra 对这个问题给出了很好的答案,但我认为更深入地研究它更合适。

出于多种原因,我们希望将代码分成模块和库。 像代码封装、可重用性、更容易调试等。这个想法也会在编译过程中传播。

换句话说,我们想把编译过程分成几个小的编译步骤,每个步骤都属于一个模块。 所以每个模块都必须有自己的编译过程。 这就是我们为每个目录使用一个CMakeLists.txt文件的原因。 因此,每个目录都有自己的编译命令,并且在项目的根目录中会有一个主CMakeLists.txt文件。

这是一个例子。 考虑以下项目结构:

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

我们将有一个CmakeLists.txt每个目录。 第一个目录是src/文件夹所在项目的根目录。 这是该文件的内容:

cmake_minimum_required(VERSION 3.4)
project(multi_file)

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

add_subdirectory(src) 

接下来CMakeLists.txt将位于src/目录中:

add_subdirectory("sum")

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

最后一个将在sum/目录中:

add_library(sum SHARED sum.cpp)

我希望这有帮助。 我创建了一个github 存储库,以防您觉得需要查看代码或需要进一步解释。

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

看起来 CMake 允许您提供包含目录的列表: http : //www.cmake.org/cmake/help/cmake-2-8-docs.html#command : include_directories

所以像:

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

这些被传递给编译器,以便它可以找到头文件,并将为每个源文件传递。 所以你的任何源文件都应该能够包含任何头文件(我认为这就是你所要求的)。

与此类似,您应该能够在add_executable命令中列出所有源文件:

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

所以这将是一种让一切都构建起来的幼稚方式。 每个源文件都将被编译并在所有这些目录中查找头文件,然后将目标文件链接在一起。 考虑是否有任何方法可以简化这一点,这样您就不需要这么多包含文件夹,也许只有几个公共头文件需要被所有源文件引用。 如果事情变得更复杂,您可以将子层次结构构建到库等中。还可以考虑将源文件和头文件分开(例如在 src 和 include 中)。

暂无
暂无

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

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