Introduction¶
CMake is flexible¶
CMake is a highly flexible build system, but hard to use.
You might:
- Manually write many
custom targets
to 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.txt
writing - Unify C++ project structures
- Enable modular CMake
find_pacage
experience - Free programmers from remembering the
include-directories
andextra link
dependencies - 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_package
andadd_subdirectory
is not the final solution
- ABI incompatibility
Convensions¶
- reason_install
- reason uses
Unix Directory Tree Convension
bin # for executables
include # for header files
lib # for static and shared libraries
share # CMake package info for find_package
- reason uses
- reason_add_library
- Specify
STATIC
to build${TARGET}_s
as static library - Specify
SHARED
to build${TARGET}_d
as 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_directories
to include these dirs for the target to build only. No other targets will be polluted.reason_install
will 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
Foo
project to depend onmodule1
with one command:add_subdirectory(module1)You can automatically include dependencies’
include-directories
, and link tolink-libraries
via 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_subdirectory
in the topCMakeLists.txt
to specify the dependency sequence
- for example, add
common
firstFor
Bar-project
, you may justLINKS
common_s
, orcommon_d
:reason_add_executable(TARGET "bar" SRC "src/main.cpp" LINKS common_s)