Lesson 5 · Foundations

Anatomy of a CMake project

The standard project layout used by real CMake projects. Where each file goes, and why the structure is the same whether you have 3 files or 3,000.

Every CMake project has the same skeleton. Learn this layout once. You will recognize it in every open-source project you clone.

The standard layout

myapp/
├── CMakeLists.txt            # top level. The director.
├── .gitignore                # at least: build/
├── src/                      # your code
│   ├── CMakeLists.txt
│   └── main.cpp
├── include/
│   └── myapp/                # public headers, one folder per library
│       └── version.h
└── tests/                    # tests (lesson 25)
    ├── CMakeLists.txt
    └── test_main.cpp

Why

A fixed, boring layout is a feature. Anyone can open your project and find the code, the headers and the tests in seconds. CMake itself does not require any of this, but the ecosystem does. Copy this shape and you will never confuse anyone, including yourself.

Who writes what

FileJob
Top-level CMakeLists.txtSets the minimum version, names the project, enables options, and calls add_subdirectory() for the rest (lesson 15).
src/CMakeLists.txtBuilds your libraries and the executable from the code in src/.
include/Public headers, in a folder named after your project or library.
tests/CMakeLists.txtAdds the tests (lesson 25).

The top-level file

CMakeLists.txt
cmake_minimum_required(VERSION 4.4) # VERSION flows into installers, packaging and generated headers. # LANGUAGES tells CMake which compilers to look for. project(myapp VERSION 1.2.0 LANGUAGES CXX) # One folder, one responsibility. Subdirectories add their own targets. add_subdirectory(src) add_subdirectory(tests)

And the src level:

src/CMakeLists.txt
# The executable lives next to its code. add_executable(myapp main.cpp)

Note

Projects use one CMakeLists.txt per directory instead of one giant file. It is easier to read, and, as lesson 15 shows, each subdirectory gets its own clean scope.

Why include/myapp/ and not include/

Headers go in a folder named after the library, so that every include in your code is unambiguous:

src/main.cpp
#include "myapp/version.h" // always namespaced. No clashes, ever.

When myapp is installed and other projects include it, they write #include <myapp/version.h>. The folder name makes it obvious where the header came from. Lesson 9 shows how to wire this up with target_include_directories.

Tip

If you are building a library instead of an app, the layout is identical. You just swap add_executable for add_library, which is lesson 8.

Pitfall

Do not put headers inside src/ unless they are private to the implementation. Public headers that live next to .cpp files force consumers to depend on your internal folder layout. Public goes in include/<name>/. Private stays in src/.

Read the docs