4.project_structure
How to structure your project
Recommended Project Structure (Conventional Example)
Organizing your CMake-based project following these conventions will help you easily read and manage other projects that follow similar patterns, avoid conflicts, and simplify your build system.
Example Directory Structure
- project
- .gitignore
- README.md
- LICENCE.md
- CMakeLists.txt
- cmake
- FindSomeLib.cmake
- something_else.cmake
- include
- project
- lib.hpp
- src
- CMakeLists.txt
- lib.cpp
- apps
- CMakeLists.txt
- app.cpp
- tests
- CMakeLists.txt
- testlib.cpp
- docs
- CMakeLists.txt
- extern
- googletest
- scripts
- helper.py
Key Points
-
Folder Names:
- The names like
test/vs.tests/orapps/may vary, and some projects may not have anapps/folder (e.g., for library-only projects). - There might be additional folders, such as a
python/folder for Python bindings or acmake/folder for helper CMake files (likeFind<library>.cmake).
- The names like
-
CMakeLists.txt Structure:
- CMake files are split across source directories (not in the
include/directories). This keeps theinclude/directory clean and avoids conflicts when copying to/usr/include. - You should use
add_subdirectory()to includeCMakeLists.txtfiles for subdirectories.
- CMake files are split across source directories (not in the
-
Helper CMake Modules:
- Place helper modules in the
cmake/folder, such asFind*.cmakefiles. - To include these in your CMake path:
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
- Place helper modules in the
-
Extern Folder for Dependencies:
- The
extern/folder should primarily contain git submodules to manage external dependencies, allowing easy version control and updates.
- The
-
.gitignore:
- Include
/build*in your.gitignoreso that users can create build directories inside the source directory for convenience. - While some packages discourage in-source builds, allowing this can simplify the build process without requiring a strict out-of-source build.
- Include
Enforcing Out-of-Source Builds
To require out-of-source builds, add this code to your CMakeLists.txt:
### Require out-of-source builds
file(TO_CMAKE_PATH "${PROJECT_BINARY_DIR}/CMakeLists.txt" LOC_PATH)
if(EXISTS "${LOC_PATH}")
message(FATAL_ERROR "You cannot build in a source directory (or any directory with a CMakeLists.txt file). Please make a build subdirectory. Feel free to remove CMakeCache.txt and CMakeFiles.")
endif()
This ensures that users create a separate build directory, avoiding conflicts with source files.
For an extended example project, check this link.