92

I want to find all .c files under a directory and add them all to SRC files to compile in cmake. How can I do this in CMakeList.txt.

for regular makefiles I can create

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

but I couldn't get how to do something like this in CMakeList.txt.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • 6
    Note that "collect all source files with glob" is **not recommended** in CMake: *We do not recommend using `GLOB` to collect a list of source files from your source tree. If no `CMakeLists.txt` file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate.* -- from [documentation](https://cmake.org/cmake/help/v3.7/command/file.html) – Franklin Yu Jan 02 '17 at 23:39
  • @FranklinYu is there an alternative that does not require writing every file name manually? – Ciro Santilli OurBigBook.com Nov 22 '17 at 06:37
  • 2
    @Ciro If you want to avoid writing every file name, then I think `foreach` mentioned by OP is the way to go. However, CMake team seems to recommend *manually writing every file name*. – Franklin Yu Nov 22 '17 at 06:41
  • 20
    *manually writing every file name* ??? Seriously ? – kebs Mar 30 '18 at 12:57
  • Is there anything in the new versions of CMake that allow to auto-find the source files whenever you run make? – adentinger Jul 03 '18 at 13:39
  • 4
    @kebs Yes, seriously. – doug65536 Jul 20 '18 at 03:03

6 Answers6

88

How about the good old globbing?

FILE(GLOB MyCSources *.c)
ADD_EXECUTABLE(MyExecutable ${MyCSources})
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
Dat Chu
  • 10,822
  • 13
  • 58
  • 82
  • This works great, but does it avoid the caveat (that CMake won't know when new files are added) in the other two answers? – kylewm Apr 03 '12 at 00:08
  • 4
    No, it doesn't. You will still need to re-run CMake once a new file is added. – Dat Chu Apr 25 '12 at 18:24
  • 15
    (which ended up being fine for my needs... easier than editing the CMakeList every time you add a source file) – kylewm Apr 27 '12 at 22:45
  • 11
    There's also `GLOB_RECURSE` if you want to find the files recursively. – Emil Laine Jul 11 '16 at 14:45
  • wait a sec, if you make a big list manually, CMake *still* doesn't know you added a new file; and also, should headers be added too? – tofutim Apr 01 '18 at 07:06
  • 1
    If you manually type out each name, adding a file requires changing the CMakeLists.txt file. This will cause CMake to regenerate your project. You can glob the header files into another variable or into the same variable. ADD_EXECUTABLE doesn't care about header files. As long as the headers can be found in the INCLUDE_DIRECTORIES. – Dat Chu Apr 01 '18 at 07:38
  • 1
    @DavidFong - CONFIGURE_DEPENDS is inherently unreliable and its use is not condoned even by its own developers. Please see my answer for more detail. – Alex Reinking Aug 06 '22 at 23:35
70

Try this:

AUX_SOURCE_DIRECTORY

Find all source files in a directory.

AUX_SOURCE_DIRECTORY(dir VARIABLE) 

Collects the names of all the source files in the specified directory and stores the list in the variable provided. This command is intended to be used by projects that use explicit template instantiation. Template instantiation files can be stored in a "Templates" subdirectory and collected automatically using this command to avoid manually listing all instantiations.

It is tempting to use this command to avoid writing the list of source files for a library or executable target. While this seems to work, there is no way for CMake to generate a build system that knows when a new source file has been added. Normally the generated build system knows when it needs to rerun CMake because the CMakeLists.txt file is modified to add a new source. When the source is just added to the directory without modifying this file, one would have to manually rerun CMake to generate a build system incorporating the new file.

idmean
  • 14,540
  • 9
  • 54
  • 83
Catherine
  • 22,492
  • 3
  • 32
  • 47
  • 33
    make sure and read the last part that starts with "It is tempting to use this command to avoid..." – SaoPauloooo Oct 31 '11 at 19:21
  • 2
    @SaoPauloooo, as it's written next, "there is no way for Cmake to generate a buildsystem that knows when a new source file has been added". This command is the most close answer to OP's question. Fine for me. – Catherine Nov 01 '11 at 11:24
  • 1
    examples please – Dee May 18 '19 at 01:48
21

GLOB_RECURSE recursive example

It basically makes the * also go into subdirectories:

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

And then our sources could be located for example as:

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

And main.c uses #include "d/a.h" and a.c uses #include "a.h".

Using GLOB_RECURSE on the CMake toplevel (i.e. "*.c" instead of "src/*.c") is likely a bad idea, as it can pick up .c files generated by CMake itself which are placed under build/.

Runnable example on GitHub.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
17

The only correct answer is to not do this. This has been detailed in multiple answers here on SO. I will summarize here, in decreasing order of importance.

  1. The developers have explicitly stated1 that it is wrong to do this. That should give you pause. If you encounter an issue, the developers will likely not be receptive to fixing it for you, but will rather tell you to list your sources.
  2. The aux_source_directory function is outright incorrect since it cannot detect changes in the filesystem. For the same reason, using file(GLOB or file(GLOB_RECURSE without CONFIGURE_DEPENDS is outright incorrect.
  3. CONFIGURE_DEPENDS is not guaranteed to work. (See point 1)
    1. In fact, it was buggy on Windows before Ninja 1.10.2.
    2. It also breaks dry-run workflows since the glob checks run in a parent build and the child (real) build is invoked recursively.
  4. If globbing fails, you will have a difficult time figuring out which extra source file got added or removed.
  5. Globbing, especially recursive globbing, can be slow and gets worse the more files you have. Ext4's performance is typically acceptable, but NTFS's is bad, especially through Linux drivers. See: https://github.com/alexreinking/cmake-glob-performance/
  6. Globbing is particularly likely to fail when doing git bisects, switching branches, or performing other source control operations that move file timestamps backward.

1 Here's what the CMake developers have to say about it:

Note: We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate. The CONFIGURE_DEPENDS flag may not work reliably on all generators, or if a new generator is added in the future that cannot support it, projects using it will be stuck. Even if CONFIGURE_DEPENDS works reliably, there is still a cost to perform the check on every rebuild.

Alex Reinking
  • 16,724
  • 5
  • 52
  • 86
  • 11
    So what's the solution? List all files manually? – Rafael Almeida Apr 17 '21 at 20:10
  • 1
    When many developers drop a testcase file in a single directory, adding a line in CMakeLists.txt always lead to merge-conflicts. And then every developer has to rebase his branch. Globbing (and re-configure on add/delete) is the only option in that case. – sanjivgupta Dec 20 '22 at 15:57
  • @sanjivgupta - I have _never_ had that problem. Are you listing sources all on a single line? – Alex Reinking Dec 20 '22 at 16:47
  • Hi @AlexReinking e.g. In the tests/CMakeLists.txt developer1 on line 10: add_subdirectory(footestdir). Developer2 on line 10: add_subdirectory(bartestdir) – sanjivgupta Dec 20 '22 at 23:10
6

Yes, you have two options. Let's assume you the folder structure something similar to this.

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

If you are to use AUX_SOURCE_DIRECTORY you have to add CMakeLists.txt each one of sub directories. Then you have to include and link all those subdirectories. This is quite a difficult task. So you can you GLOB and do the job very easily. This is how it is done.

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

If you want to create a library using above source code this is the command:

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

If you want to create an executable file using above source code this is the command:

 ADD_EXECUTABLE(autopilot ${autopilot_sources})
Jomnipotent17
  • 451
  • 7
  • 23
GPrathap
  • 7,336
  • 7
  • 65
  • 83
0

You can use AUX_SOURCE_DIRECTORY as @whitequark described, but it won't really work as you expect, as CMake will be unable to determine when new files are added (which is kind of the whole point with using a wildcard).

JesperE
  • 63,317
  • 21
  • 138
  • 197
  • 2
    AUX_SOURCE_DIRECTORY is performed well for now. Thank you so much. AUX_SOURCE_DIRECTORY(${PROJECT_INC_DIR}control/src CTR_SOURCES) ADD_EXECUTABLE( ${EXE_NAME} ${CTR_SOURCES} ) –  Feb 01 '10 at 10:28