Note: Although upper, lower and mixed case commands are supported by CMake, lower case commands are preferred and will be used throughout the tutorial.
Any project’s top most CMakeLists.txt must start by specifying a minimum CMake version using the cmake_minimum_required() command. This establishes policy settings and ensures that the following CMake functions are run with a compatible version of CMake.
To start a project, we use the project() command to set the project name. This call is required with every project and should be called soon after cmake_minimum_required(). As we will see later, this command can also be used to specify other project level information such as the language or version number.
Finally, the add_executable() command tells CMake to create an executable using the specified source code files.
# Generate build files
cmake /path/to/CMakeLists.txt
# Compile/link
cmake --build .CMake Configuration
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
project(Tutorial VERSION 1.0)
configure_file(TutorialConfig.h.in TutorialConfig.h)
cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR)
Target
add_executable(myExecutable main.cpp)
add_library(libA sourceA.cpp)
add_library(libB sourceB.cpp sourceB_impl.cpp)
add_library(libC sourceC.cpp)
target_link_libraries(myExecutable libA)
target_link_libraries(libA libB) target_link_libraries(libB libC)
This is a classic way of creating targets. Here we have an executable called myExecutable and three libraries libA, libB and libC. For now we know, that in order to build myExecutable we have to link with libA, for building libA we have to link with libB and for building libB we have to link with libC. The last one has no dependencies.
Modern CMake introduced also new keywords, that specify visibility of the given target property: PRIVATE, PUBLIC, INTERFACE. If none is provided, then PUBLIC is assumed. Their meanings are as follows:
PRIVATEproperty is only for the internal usage by the property owner,PUBLICproperty is for both internal usage by the property owner and for other targets that use it (link with it),INTERFACEproperty is only for usage by other libraries.
Targets that don’t produce any binaries (e.g. header-only libraries) can have only
INTERFACEproperties and can only useINTERFACElinking. This is quite understandable, because there is no “internal” part in such targets, soPRIVATEkeyword doesn’t mean anything.
what is the visibility of the newly obtained set of properties (by libA)? Answer is simple: it’s the same as the specifier used in target_link_libraries() for that target. So if libA links as PRIVATE with libB, then all PUBLIC and INTERFACE properties of libB become PRIVATE properties of libA. Similarly, if it links as PUBLIC, then all PUBLIC and INTERFACE properties of libB become PUBLIC in libA. The same goes for INTERFACE linking.
Library
- Make it a library
add_library(MathFunctions mysqrt.cxx) - (Optional):
add_subdirectory(MathFunctions)(need aCMakeLists.txtin the sub-directory) - Link library to the target
target_link_libraries(Tutorial PUBLIC MathFunctions) - Specify the library’s header file location
target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/MathFunctions")
Optional Library
- Add an option to the top-level
CMakeLists.txtfileoption(USE_MYMATH "Use tutorial provided math implementation" ON). - Use
if()to leverage options
if(USE_MYMATH)
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()
- Change the library name
target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS}).
Linking
add_executable(cmake_testapp main.cpp)
add_library(test_library STATIC calc.cpp)
include_directories(includes/math)
include_directories(includes/general)
find_library(TEST_LIBRARY test_library lib) target_link_libraries(cmake_testapp LINK_PUBLIC &{TEST_LIBRARY}) # after add_executable
- We used
target_include_directories()to specify where the executable target should look for include files.- The
INTERFACE,PUBLICandPRIVATEkeywords are required to specify the scope of the following arguments.PRIVATEandPUBLICitems will populate theINCLUDE_DIRECTORIESproperty of<target>.PUBLICandINTERFACEitems will populate theINTERFACE_INCLUDE_DIRECTORIESproperty of<target>. The following arguments specify include directories.
- The
Variable
PROJECT_BINARY_DIR: Full path to build directory for project.