Introduction¶
CMake is flexible¶
CMake is a highly flexible build system, but hard to use.
You might:
- Manually write many
custom targetsto help cmake build up its dependency graph to build anything you like. - Use ExternalProject to pull projects from github, build and install to any directory you like
But ...
- Being flexible means being frustrated to get it configured right - You don’t know the best practice while having no the time to skim through all approaches
- Being flexible preserves way too much functionalities, and you’re simply writing code to choose what you want indeed
What reason.cmake can and cannot solve¶
Solve it:
- Simplify the whole CMake process
- Smooth
CMakeLists.txtwriting - Unify C++ project structures
- Enable modular CMake
find_pacageexperience - Free programmers from remembering the
include-directoriesandextra linkdependencies - Automatically build package for package-manager
- deb
- rpm (TODO)
Not solved:
- C++ language level modules
- Modules is already proposed for C++ (Modules), but not yet adopted
- Clang has already implemented it (Modules in Clang)
- CMake’s
find_packageandadd_subdirectoryis not the final solution
- ABI incompatibility
Convensions¶
- reason_install
- reason uses
Unix Directory Tree Convensionbin # for executablesinclude # for header fileslib # for static and shared librariesshare # CMake package info for find_package
- reason uses
- reason_add_library
- Specify
STATICto build${TARGET}_sas static library - Specify
SHAREDto build${TARGET}_das dynamic library - Both for building both
- Specify
3. Parameter INC_DIRS in reason_add_executable, reason_add_library and reaso
n_install
- reason will use
target_include_directoriesto include these dirs for the target to build only. No other targets will be polluted.reason_installwill copy all files and directories in these directories
Typical reason.cmake C++ project¶
- A C++ project with internal dependencies
Foo ├── CMakeLists.txt ├── deps │ ├── module1 │ │ ├── CMakeLists.txt │ │ ├── include │ │ │ └── module1 │ │ │ └── ... // ... headers for module 1 ... │ │ ├── src │ │ │ └── ... // ... module 1 source files ... │ │ └── test │ │ └── ... // ... module 1 test files ... │ ├── module2 │ │ ├── CMakeLists.txt │ │ ├── include │ │ ├── src │ │ └── test │ └── ... // ... many other modules ... ├── include │ └── foo │ └── ... // ... the projects's headers ... ├── src // ... project's source ... └── test // ... project's test ...
Declare
Fooproject to depend onmodule1with one command:add_subdirectory(module1)You can automatically include dependencies’
include-directories, and link tolink-librariesvia simplyLINKS:# Just 'LINKS' module1_s, and reason will help you find out # what directories 'module1_s' includes and what libraries # it links reason_add_library(STATIC foo SRC "src/foo_src.cpp" LINKS module1_s)
- A C++ project with cross dependencies
Foo-project ├── CMakeLists.txt // just use 'add_subdirectory' to specify the build sequence │ common │ ├── CMakeLists.txt │ ├── include │ │ └── common │ │ └── ... // ... headers for module common ... │ ├── src │ │ └── ... // ... module common source files ... │ └── test │ └── ... // ... module common test files ... ├── Bar-project // ... some projects like Foo project specified in 1 │ ├── CMakeLists.txt │ ├── deps // ... other internal deps ... │ ├── include │ ├── src │ └── test ├── Baz-project │ ├── CMakeLists.txt │ └── ... // ... other directories ... └── ... // ... other projects ...
Use
add_subdirectoryin the topCMakeLists.txtto specify the dependency sequence
- for example, add
commonfirstFor
Bar-project, you may justLINKScommon_s, orcommon_d:reason_add_executable(TARGET "bar" SRC "src/main.cpp" LINKS common_s)