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

vwhgwdsa  于 5个月前  发布在  其他
关注(0)|答案(3)|浏览(101)

我有一个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文件来处理这种结构?

cbeh67ev

cbeh67ev1#

由于项目中的目录结构只是为了保持文件的组织性,一种方法是使用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不会自动检测到新文件何时添加到源树中。您必须手动重新创建构建文件。

hgb9j2n6

hgb9j2n62#

虽然@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 repository,以防你觉得你需要看代码或者需要进一步的解释。

e4eetjau

e4eetjau3#

我不是CMake方面的Maven,但既然没有其他答案,我就看看文档并给予尝试。
看起来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中)。

相关问题