【问题标题】:Single CMakeLists.txt enough for my project?单个 CMakeLists.txt 足以满足我的项目吗?
【发布时间】:2018-12-14 03:03:00
【问题描述】:

我正在尝试将我的旧 CMake 移植到现代 CMake(CMake 3.0.2 或更高版本)。在旧设计中,我有多个 CMakelists.txt,每个目录都包含一个 CMakeLists.txt 文件。

我当前项目的目录结构如下:

.
├── VizSim.cpp
├── algo
├── contacts
│   ├── BoundingVolumeHierarchies
│   │   └── AABBTree.h
│   └── SpatialPartitoning
├── geom
│   └── Geometry.h
├── math
│   ├── Tolerance.h
│   ├── Vector3.cpp
│   └── Vector3.h
├── mesh
│   ├── Edge.h
│   ├── Face.h
│   ├── Mesh.cpp
│   ├── Mesh.h
│   └── Node.h
├── util
|   |__ Defines.h
|   |__ Math.h
|
└── viz
    └── Renderer.h

我打算做的只是使用一个 CMakelists.txt 并将所有 cpp 文件放在 SOURCE 中,并将所有头文件放在 HEADER 中并使用 add_executable。

set (SOURCE
    ${SOURCE}
    ${CMAKE_CURRENT_SOURCE_DIR}/src/mesh/Mesh.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/math/Vector3.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/VizSim.cpp
    ....
)

set (HEADER
    ${HEADER}
    ${CMAKE_CURRENT_SOURCE_DIR}/src/mesh/Mesh.h
    ${CMAKE_CURRENT_SOURCE_DIR}/src/math/Vector3.h
    .... 
)

add_library(${PROJECT_NAME} SHARED ${SOURCE})

如果使用单个 CMakeLists.txt 是一种好习惯,我会担心这样做。那么单个 CMakeLists.txt 就足够了吗,还是我需要为每个文件夹创建一个 CMakeLists.txt?

我只能想到在我的项目中有多个 CMakeLists.txt 的一个很好的理由,那就是模块化。

考虑到我的项目最终会成长。

【问题讨论】:

  • AFAK,不管模块化,我想不出任何理由使用多个 CMakeLists.txt
  • 我同意@WeiGuo:通常情况下,每个库(项目)都有一个CMakeLists.txt,源代码在一个目录中。其中一些库有很多文件,我将其中一些文件分隔在子目录中。在这种情况下,我使用与您类似的方法(除了一个例外,我为不同的目录引入了多个变量并添加了语句以让 cmake 为 VS 生成多个子文件夹)。
  • @Scheff 谢谢你的回答。所以我应该使用一个 CMakeLists.txt。但是当你说“我为不同的目录引入了多个变量并添加了语句让 cmake 为 VS 生成多个子文件夹”时是什么意思你如何告诉 cmake 生成多个子文件夹。你能不能给我一点提示我怎么能做到这一点。这就是你的意思吗stackoverflow.com/questions/7787823/…
  • 这就是你的意思stackoverflow.com/questions/7787823/… 类似。 ;-)
  • 你如何告诉 cmake 生成多个子文件夹。 对不起,你误会了。我的意思是 VisualStudio 的可视化项目树中的子文件夹。将源文件分离到目录是由我完成的(我不希望 cmake 对此进行任何更改)。 ;-)

标签: cmake


【解决方案1】:

评论有点长——所以我把它作为一个答案:

在我的一个项目(图书馆)中,我有很多资源,因此我开始将其中一些移动到子目录util

为此,我制作了单独的变量:

file(GLOB headers *.h)
file(GLOB sources *.cc)
file(GLOB utilHeaders
  RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
  ${CMAKE_CURRENT_SOURCE_DIR}/util/*.h)
file(GLOB utilSources
  RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
  ${CMAKE_CURRENT_SOURCE_DIR}/util/*.cc)

为了使它在 VisualStudio 中看起来更漂亮/更方便,我插入了source_groups,它会在 VS 项目中生成适当的子文件夹。我相信它们被称为“过滤器”。

source_group("Header Files\\Utilities" FILES ${utilHeaders})
source_group("Source Files\\Utilities" FILES ${utilSources})

当然,我必须考虑变量utilHeadersutilSources 以及必须提供源代码的位置:

add_library(libName
  ${sources} ${headers}
  ${utilSources} ${utilHeaders})

就是这样。


Fred 在他的评论中提醒,我不应该忘记提到file(GLOB 有一定的弱点(尽管我发现它在我们的日常工作中非常有价值)。 CMake doc.中甚至提到了这一点:

注意:我们不建议使用 GLOB 从源代码树中收集源文件列表。如果在添加或删除源时没有 CMakeLists.txt 文件更改,则生成的构建系统无法知道何时要求 CMake 重新生成。 CONFIGURE_DEPENDS 标志可能无法在所有生成器上可靠地工作,或者如果将来添加不能支持它的新生成器,使用它的项目将被卡住。即使CONFIGURE_DEPENDS 工作可靠,每次重建都需要进行检查。

因此,使用file(GLOB,您永远不要忘记在添加、移动或删除文件后重新运行 CMake。另一种选择是直接在生成的内置脚本(例如 VS 项目文件)中添加、移动、删除文件,并依赖于 CMake 的下一次重新运行将覆盖这些文件的事实。最后但同样重要的是,git pull 是值得考虑重新运行 CMake 的其他内容。

【讨论】:

  • 那么根据文件所在的子目录的名称将文件放在变量中的意义何在。这只是为了VS还是有其他原因。我问是因为我使用 vim 作为我的 IDE。
  • @pokche 额外的变量utilHeaders/utilSources 在那里是因为相应的。列表被使用了两次(一次在source_group,一次在add_library)。
  • @pokche 我只是想如何在多个目录中用file(GLOB 填充一个变量。在简要查看 CMake 文档后。我看到这应该工作。因此,这不是多个变量可以提供帮助的另一个原因。可能是,它更容易阅读,但我不确定。 ;-)
  • 关于使用 GLOB:cmake.org/cmake/help/latest/command/file.html 注意我们不建议使用 GLOB 从源代码树中收集源文件列表。如果在添加或删除源时没有 CMakeLists.txt 文件更改,则生成的构建系统无法知道何时要求 CMake 重新生成。 CONFIGURE_DEPENDS 标志可能无法在所有生成器上可靠地工作,或者如果将来添加不能支持它的新生成器,使用它的项目将被卡住。即使 CONFIGURE_DEPENDS 工作可靠,每次重建时执行检查仍然需要成本。
  • @Scheff 我明白你在说什么。但它假定文件夹中的每个文件实际上都用于目标,但情况可能并非如此(当然不是多平台项目,不想为库的每个平台特定文件都有单独的文件夹)。我不怀疑您会发现它“在日常工作中”很有用,但对我来说,这只是使用 CMake 的一种错误方式,导致我使用的生成器出现太多问题。我添加评论不是因为您的意识,而是为了告知其他人使用此方法的问题。
【解决方案2】:

我总是推荐每个目录一个 CMakeList.txt 文件。我的理由:

  • locality:将所有内容保存在同一个文件夹中。这包括构建系统的相关部分。我讨厌它导航到根文件夹以查看如何调用库或目标。
  • 构建工件和相关构建代码的分离:测试属于test,库属于lib,二进制文件属于bin,文档属于doc,实用程序属于utils。这可能因项目而异。当我必须对文档进行更改时,我为什么要翻阅几十个不相关的 CMake 代码?只需查看正确的 CMakeLists.txt。
  • 避免处理路径:在大多数情况下,可以避免包括${CMAKE_CURRENT_SOURCE_DIR} 之类的相对或绝对路径。这会导致可维护的构建代码并减少错误路径造成的错误。尤其是外源构建,无论如何都应该使用它。
  • 错误的本地化:如果发生 CMake 错误,则更容易定位问题。通常可以排除子目录作为第一个解决方法。

【讨论】:

  • 本地化是否适用于项目的子文件夹,如 algo、contacts、geom .. 等?
  • @mato。我首先会质疑这么多子文件夹是否有意义。拥有一两个文件对结构没有帮助,只会增加混乱。
  • 我同意。最后一个问题,假设网格子文件夹确实有意义,因为它会增长并且外部的一些人可以将它用作库。所以mesh文件夹包含CMakeLists.txt?因为有了这个逻辑,任何可能被外部用户用作库的文件夹最终都可能拥有 CMakeLists.txt。
  • @mato:取决于你的意见。只有当单个文件最终出现在库中(甚至是 CMake 对象库)时,我才会为单个文件创建一个文件夹。
  • 我的程序很小,我想要一个用于所有子目录的 cmakelists.txt
猜你喜欢
  • 2020-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-07
  • 1970-01-01
  • 2016-07-27
  • 2020-08-17
相关资源
最近更新 更多