Lesson 19 · Organize your project

Why not file(GLOB)

The warning against file(GLOB) in the official docs, explained. And the explicit source-list workflow that never surprises you.

You will be tempted to write this:

Don't do this
file(GLOB SOURCES src/*.cpp) # do not add_executable(app ${SOURCES})

It looks convenient. New files are picked up automatically. But the official documentation explicitly recommends against it. Here is why, and what to do instead.

What the docs say

The failure mode. You add foo.cpp to src/, rebuild, and nothing happens. No error, no new file in the build. Just silent nothing. Because the build system only re-runs CMake when its inputs, the CMakeLists.txt files, change. Not when the filesystem changes.

The suggested fix, CONFIGURE_DEPENDS, has its own problems. It is not reliable on every generator, and even where it works it slows every build with a scan. So it is discouraged too.

Why

A build system that silently misses files is worse than one that requires a one-line edit. The explicit list makes every change visible and reviewable. “I added foo.cpp” appears as a real diff in git. GLOB trades a few seconds of typing for invisible build breaks. Bad trade.

The workflow

src/
├── CMakeLists.txt
├── main.cpp
├── parser.cpp
└── ui.cpp
src/CMakeLists.txt
# Explicit list. Adding a file means adding one line here. add_executable(app main.cpp parser.cpp ui.cpp )

Adding a file means adding one line and reconfiguring, which happens automatically when CMakeLists.txt changes, remember lesson 4. That is the entire cost, and it is the price of never being silently wrong.

target_sources, list sources next to the code

For libraries spread over directories, target_sources keeps the list where the code lives:

libs/calc/CMakeLists.txt
add_library(calc STATIC) target_sources(calc PRIVATE calc.cpp util.cpp ) target_include_directories(calc PUBLIC include)

Note

With target_sources(... PRIVATE), the add-a-file edit happens in the same file as the code. No need to touch the add_library line at all.

The honest exceptions

  • CMakeLists.txt is generated by a build system that owns the file list, for example Qt’s automoc-style tooling, or qt_add_executable with qt_add_resources. Then GLOB is fine, because something else regenerates your CMake files reliably.
  • install(DIRECTORY ...) and other copying uses of GLOB (headers, data) are fine. The warning targets source files for compilation, because only those trigger the rebuild problem.

Pitfall

If you inherit a project using file(GLOB ...) without CONFIGURE_DEPENDS, a fresh clone may build a different set of files than your local checkout. Classic “works here, broken in CI” material. Exactly the class of bug the explicit list eliminates.

Read the docs