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
| File | Job |
|---|---|
Top-level CMakeLists.txt | Sets the minimum version, names the project, enables options, and calls add_subdirectory() for the rest (lesson 15). |
src/CMakeLists.txt | Builds your libraries and the executable from the code in src/. |
include/ | Public headers, in a folder named after your project or library. |
tests/CMakeLists.txt | Adds the tests (lesson 25). |
The top-level file
CMakeLists.txtcmake_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.txtper 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_executableforadd_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.cppfiles force consumers to depend on your internal folder layout. Public goes ininclude/<name>/. Private stays insrc/.
Read the docs