如何使用Cmake构建系统在目录中使用所有*.c文件?

53 makefile cmake

我想在目录下找到所有.c文件,并将它们全部添加到SRC文件以在cmake中编译.我怎么能在CMakeList.txt中这样做.

对于我可以创建的常规makefile

SPECIFIED_SRC_FILE  = $(foreach d,$(SPECIFIED_SRC_DIRS),$(wildcard $(addprefix $(d)/*,*.c)))
Run Code Online (Sandbox Code Playgroud)

但是我无法在CMakeList.txt中做到这样的事情.

Dat*_*Chu 56

这个好老的小圆棒怎么样?

FILE(GLOB MyCSources *.c)
ADD_EXECUTABLE(MyExecutable ${MyCSources})
Run Code Online (Sandbox Code Playgroud)

  • (最终满足我的需求......比每次添加源文件时编辑CMakeList更容易) (10认同)
  • 如果要以递归方式查找文件,还可以使用"GLOB_RECURSE". (9认同)
  • 不,不是。添加新文件后,您仍然需要重新运行CMake。 (2认同)

whi*_*ark 49

试试这个:

AUX_SOURCE_DIRECTORY

查找目录中的所有源文件.

AUX_SOURCE_DIRECTORY(dir VARIABLE) 
Run Code Online (Sandbox Code Playgroud)

收集指定目录中所有源文件的名称,并将列表存储在提供的变量中.此命令旨在供使用显式模板实例化的项目使用.模板实例化文件可以存储在"Templates"子目录中,并使用此命令自动收集,以避免手动列出所有实例化.

使用此命令避免编写库或可执行目标的源文件列表很有诱惑力.虽然这似乎有效,但CMake无法生成一个知道何时添加新源文件的构建系统.通常,生成的构建系统知道何时需要重新运行CMake,因为CMakeLists.txt文件被修改为添加新源.当源只是添加到目录而不修改此文件时,必须手动重新运行CMake以生成包含新文件的构建系统.

  • 确保并阅读以"使用此命令来避免......"的最后一部分. (16认同)
  • @SaoPauloooo,如下所述,“ Cmake无法生成知道何时添加新源文件的构建系统”。该命令是OP问题的最接近答案。对我来说没问题。 (2认同)
  • 请举例 (2认同)

Cir*_*四事件 14

GLOB_RECURSE 递归示例

它基本上使*也进入子目录:

cmake_minimum_required(VERSION 3.0)
file(GLOB_RECURSE SOURCES RELATIVE ${CMAKE_SOURCE_DIR} "src/*.c")
add_executable(main ${SOURCES})
Run Code Online (Sandbox Code Playgroud)

然后我们的来源可以定位为例如:

src/main.c
src/d/a.c
src/d/a.h
Run Code Online (Sandbox Code Playgroud)

main.c使用#include "d/a.h"a.c使用#include "a.h"

使用GLOB_RECURSE的CMake的顶层(即"*.c"代替"src/*.c")可能是一个糟糕的主意,因为它可以拿起.c其放置在通过自身的CMake生成的文件build/

GitHub 上的可运​​行示例。


GPr*_*hap 6

是的,您有两个选择。让我们假设您的文件夹结构与此类似。

??? autopilot
            ?   ??? _AutoPilot.cpp
            ?   ??? _AutoPilot.h
            ?   ??? action
            ?       ??? ActionBase.cpp
            ?       ??? ActionBase.h
            ?       ??? APcopter
            ?       ?   ??? APcopter_avoid.cpp
            ?       ?   ??? APcopter_avoid.h
Run Code Online (Sandbox Code Playgroud)

如果要使用AUX_SOURCE_DIRECTORY,则必须在每个子目录中添加 CMakeLists.txt。然后您必须包含并链接所有这些子目录。这是一项相当艰巨的任务。因此,您可以 GLOB 并非常轻松地完成工作。这是如何完成的。

  file(GLOB autopilot_sources ./**.cpp ./**.c)
  SET( autopilot ${autopilot_sources})  
Run Code Online (Sandbox Code Playgroud)

如果你想使用上面的源代码创建一个库,这是命令:

  ADD_LIBRARY ( autopilot  ${autopilot_sources})
  TARGET_LINK_LIBRARIES ( autopilot)  
Run Code Online (Sandbox Code Playgroud)

如果你想使用上面的源代码创建一个可执行文件,这是命令:

 ADD_EXECUTABLE(autopilot ${autopilot_sources})
Run Code Online (Sandbox Code Playgroud)

  • file(GLOB autopilot_sources ./**.cpp ./**.c) 在处理多个深度时可能更简单一些 (3认同)

Ale*_*ing 6

唯一正确的答案是没有做到这一点。这已在 SO 上的多个 答案中详细说明。我将在这里总结,按重要性降序排列。

  1. 开发人员已经明确说明1这样做是错误的。那应该让你停下来。如果您遇到问题,开发人员可能不会接受为您修复它,而是会告诉您列出您的来源。
  2. aux_source_directory函数完全不正确,因为它无法检测文件系统中的更改。出于同样的原因,使用file(GLOBfile(GLOB_RECURSE不使用CONFIGURE_DEPENDS是完全错误的。
  3. CONFIGURE_DEPENDS不能保证工作。(见第 1 点)
    1. 事实上,在 Ninja 1.10.2 之前,在 Windows 上是有问题的
    2. 由于 glob 检查在父构建中运行并且子(真实)构建是递归调用的,因此它还破坏了空运行的工作流程。
  4. 如果通配失败,您将很难确定添加或删除了哪些额外的源文件。
  5. 通配,尤其是递归通配,可能会很慢,而且随着您拥有的文件越多,情况会变得更糟。Ext4 的性能通常是可以接受的,但 NTFS 的性能很差,尤其是通过 Linux 驱动程序。参见:https : //github.com/alexreinking/cmake-glob-performance/
  6. 在执行 git 平分、切换分支或执行其他将文件时间戳向后移动的源代码控制操作时,globbing 特别容易失败。

1以下是 CMake 开发人员对此的看法:

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

  • 那么解决办法是什么呢?手动列出所有文件? (11认同)