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

问题描述 投票:0回答:6

我想找到一个目录下的所有.c文件,并将它们全部添加到src文件中,以便在cmake中编译。我怎样才能在 CMakeList.txt 中做到这一点。

对于常规 makefile,我可以创建

SPECIFIED_SRC_FILE  = $(foreach d,$(SPECIFIED_SRC_DIRS),$(wildcard $(addprefix $(d)/*,*.c)))

但我不知道如何在 CMakeList.txt 中执行类似的操作。

makefile cmake
6个回答
89
投票

那古老的通配符怎么样?

FILE(GLOB MyCSources *.c)
ADD_EXECUTABLE(MyExecutable ${MyCSources})

70
投票

试试这个:

AUX_SOURCE_DIRECTORY

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

AUX_SOURCE_DIRECTORY(dir VARIABLE) 

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

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


22
投票

GLOB_RECURSE
递归示例

它基本上使

*
也进入子目录:

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

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

src/main.c
src/d/a.c
src/d/a.h

并且

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

在 CMake 顶层使用

GLOB_RECURSE
(即
"*.c"
而不是
"src/*.c"
)可能是一个坏主意,因为它可以拾取 CMake 本身生成的
.c
文件,这些文件放置在
build/
下。

可运行示例在 GitHub 上


19
投票

唯一正确答案是不这样做。这已在 multiple answers 中详细介绍。我将在这里总结,按重要性降序排列。

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

明确列出您的来源。


1 以下是 CMake 开发人员对此的评价:

注意: 我们不建议使用 GLOB 从源代码树中收集源文件列表。如果添加或删除源时 CMakeLists.txt 文件没有更改,则生成的构建系统无法知道何时要求 CMake 重新生成。

CONFIGURE_DEPENDS
标志可能无法在所有生成器上可靠地工作,或者如果将来添加不支持它的新生成器,则使用它的项目将被卡住。即使
CONFIGURE_DEPENDS
工作可靠,每次重建时仍然需要执行检查。


7
投票

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

├── autopilot
            │   ├── _AutoPilot.cpp
            │   ├── _AutoPilot.h
            │   └── action
            │       ├── ActionBase.cpp
            │       ├── ActionBase.h
            │       ├── APcopter
            │       │   ├── APcopter_avoid.cpp
            │       │   ├── APcopter_avoid.h

如果您要使用

AUX_SOURCE_DIRECTORY
,您必须在每个子目录中添加CMakeLists.txt。然后您必须包含并链接所有这些子目录。这是一项相当艰巨的任务。因此您可以通过 GLOB 轻松完成工作。就是这样完成的。

  file(GLOB autopilot_sources ./**.cpp ./**.c)
  SET( autopilot ${autopilot_sources})  

如果您想使用上述源代码创建库,请使用以下命令:

  ADD_LIBRARY ( autopilot  ${autopilot_sources})
  TARGET_LINK_LIBRARIES ( autopilot)  

如果您想使用上面的源代码创建可执行文件,请使用以下命令:

 ADD_EXECUTABLE(autopilot ${autopilot_sources})

0
投票

您可以按照 @whitequark 的描述使用

AUX_SOURCE_DIRECTORY
,但它不会真正按照您的预期工作,因为 CMake 将无法确定何时添加新文件(这就是使用通配符的全部要点)。

© www.soinside.com 2019 - 2024. All rights reserved.