Documents Help

CMake

All content should be viewed as targets and dependencies.

CMakeLists.txt basics

cmake_minimum_required(VERSION 3.27) project( CMakeLearn LANGUAGES CXX C DESCRIPTION "a test project" VERSION 0.0.1 ) set(CMAKE_CXX_STANDARD 20) add_executable(CMakeLearn src/main.cpp include/engine.h) target_include_directories(CMakeLearn PRIVATE include)

We should create a CMakeLists.txt under the project directory, if you use CLion ,it will be generated automatically.

The project name is required ,other items are optional.

The modifier PUBLIC means deep search the path,but PRIVATE is not.

We should create a directory for libs,and add a CMakeLists.txt in it.

add_subdirectory() # if 3rdlibs contains a proj made with cmakelists,just use this to add it .

In our main CMakeLists.txt ,add this to our project also.

target_link_libraries(CMakeLearn PUBLIC $3rdlibs's project name$)#link 3rdlibs to our project

example

For example ,we want to use absl .Create a directory named 3rdlibs under the root dir.

And create a CMakeLists.txt under 3rdlibs .(Because absl already has CMakeLists.txt, so we do not need to create a new one)

add_subdirectory(abseil-cpp) target_link_libraries(CMakeLearn PUBLIC absl)

Complete CMakeLists.txt contents

cmake_minimum_required(VERSION 3.27) project(CMakeLearn) set(CMAKE_CXX_STANDARD 20) add_subdirectory(3rdlibs) add_library(CMakeLearn STATIC src/main.cpp) target_include_directories(CMakeLearn PUBLIC include) target_link_libraries(CMakeLearn PUBLIC absl)

The add_subdirectory add the 3rdlibs ,and the target_link_libraries link the absl ,the name absl can be found in the CMakeLists.txt in abseil-cpp

C make1
C make2

For example, Eigen ,we put it in directory 3rdlibs.

Create a CMakeLists.txt in Eigen ,like following:

add_library(Eigen INTERFACE) target_include_directories(Eigen INTERFACE ./) target_compile_features(Eigen INTERFACE cxx_std_20)

And in 3rdlibs 's CMakeLists.txt ,add following:

add_subdirectory(Eigen)

And in main CMakeLists.txt ,add following:

target_link_libraries(CMakeLearn PUBLIC Eigen)

Up to now ,we take a look at main CMakeLists.txt.

cmake_minimum_required(VERSION 3.27) project(CMakeLearn) set(CMAKE_CXX_STANDARD 20) add_subdirectory(3rdlibs) add_library(CMakeLearn STATIC src/main.cpp) target_include_directories(CMakeLearn PUBLIC include) target_compile_features(CMakeLearn PRIVATE cxx_std_20) #target_link_libraries(CMakeLearn PUBLIC absl) target_link_libraries(CMakeLearn PUBLIC Eigen)

For example: mono ,and in 3rdlibs:

add_subdirectory(Eigen) add_subdirectory(mono)

In mono:

set(MONO_PATH "" CACHE PATH "the C# mono path") message("your mono path is ${MONO_PATH}") add_library(mono SHARED IMPORTED GLOBAL) set(mono_dll "${MONO_PATH}/bin/mono-2.0-sgen.dll" CACHE INTERNAL "the mono dll path") target_include_directories(mono INTERFACE "${MONO_PATH}/include/mono-2.0") set_target_properties(mono PROPERTIES IMPORTED_LOCATION "${MONO_PATH}/bin/mono-2.0-sgen.dll" IMPORTED_IMPLIB "${MONO_PATH}/lib/mono-2.0-sgen.lib" )

If other dlls,we create a directory named such as temp ,and add a find_temp.cmake ,and add it to 3rdlibs.

#add_subdirectory(abseil-cpp) add_subdirectory(Eigen) add_subdirectory(mono) include(temp/fine_temp.cmake)

Package all *.cpp

If we have lots of .cpp files,we can use aux_source_directory to package them all.

aux_source_directory(./src engine_src) add_library(CMakeLearn STATIC ${engine_src} )

Package all *.h

file(GLOB engine_header_files ./include/core/*.h) message("header files: ${engine_header_files}")

or

file(GLOB_RECURSE engine_header_all_files ./include/*.h)

Up to now ,our main CMakeLists.txt is as follows:

cmake_minimum_required(VERSION 3.27) project(CMakeLearn) #set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_STANDARD 20) set(engine_name CMakeLearn) #set(xx 123 CACHE) #set(XX_PATH "" CACHE PATH) add_subdirectory(3rdlibs) aux_source_directory(./src engine_src) message("source files: ${engine_src}") foreach (var ${engine_src}) message(${var}) endforeach () file(GLOB engine_header_files ./include/core/*.h) message("header files: ${engine_header_files}") add_library(CMakeLearn STATIC ${engine_src} ${engine_header_files} ) target_include_directories(CMakeLearn PUBLIC include) target_compile_features(CMakeLearn PRIVATE cxx_std_20) target_precompile_headers(CMakeLearn PUBLIC ./include/pch.h) #target_link_libraries(CMakeLearn PUBLIC absl) target_link_libraries(CMakeLearn PUBLIC Eigen) option(ENGINE_BUILD_TEST "should build unit test" OFF) if (PROJECT_IS_TOP_LEVEL OR ENGINE_BUILD_TEST) include(CTest) enable_testing() add_subdirectory(unittest) endif ()

Precompile headers

We create a PCH.h in directory include

#ifndef CMAKELEARN_PCH_H #define CMAKELEARN_PCH_H #endif //CMAKELEARN_PCH_H #pragma once #include "Eigen" #include <iostream> //etc include files

In main CMakeLists.txt:

target_precompile_headers(CMakeLearn PUBLIC ./include/pch.h)

In unittest\CMakeLists.txt

target_precompile_headers(cgmath REUSE_FROM CMakeLearn)

UnitTest

include(CTest) enable_testing() add_subdirectory(unittest)

We should create a directory such as named unittest ,and put a CMakeLists.txt here also.

unittest\CMakeLists.txt

add_executable(cgmath ./cgmath.cpp) add_test(NAME cgmath COMMAND $<TARGET_FILE:cgmath>) target_link_libraries(cgmath PRIVATE CMakeLearn)

And we should know that CMake is built based on target.

Command basics

Function

Command

Compile command

cmake -S . -B cmake-build

Open sln

start .\cmake-build\CMakeLearn.sln

Project type

cmake -G

Generate ninja

cmake -S . -B cmake-build -G"Ninja"

Build

cmake --build .\cmake-build\

Run

.\cmake-build\Debug\CMakeLearn.exe

Compile command

cmake -S . -B cmake-build
Meaning

S stands for source and specifies the location of CMakeLists.txt.

B stands for build

cmake-build is the build directory name.

output

PS C:\Users\22153\Documents\Local Projects\CMakeLearn> cmake -S . -B cmake-build -- Building for: Visual Studio 17 2022 -- The CXX compiler identification is MSVC 19.37.32822.0 -- The C compiler identification is MSVC 19.37.32822.0 -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.37.32822/bin/Hostx64/x64/cl.exe - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.37.32822/bin/Hostx64/x64/cl.exe - skipped -- Detecting C compile features -- Detecting C compile features - done -- Configuring done (2.6s) -- Generating done (0.0s) -- Build files have been written to: C:/Users/22153/Documents/Local Projects/CMakeLearn/cmake-build

We should know that CMake is a project generator,not a compiler.

Open sln

And we can use this command to open the sln.

start .\cmake-build\CMakeLearn.sln

output

PS C:\Users\22153\Documents\Local Projects\CMakeLearn> start .\cmake-build\CMakeLearn.sln

Generate different project type

we can use the following command in terminal to look all types we can generate.

cmake -G

output

PS C:\Users\22153\Documents\Local Projects\CMakeLearn> cmake -G CMake Error: No generator specified for -G Generators * Visual Studio 17 2022 = Generates Visual Studio 2022 project files. Use -A option to specify architecture. Visual Studio 16 2019 = Generates Visual Studio 2019 project files. Use -A option to specify architecture. Visual Studio 15 2017 [arch] = Generates Visual Studio 2017 project files. Optional [arch] can be "Win64" or "ARM". Visual Studio 14 2015 [arch] = Generates Visual Studio 2015 project files. Optional [arch] can be "Win64" or "ARM". Visual Studio 12 2013 [arch] = Generates Visual Studio 2013 project files. Optional [arch] can be "Win64" or "ARM". Visual Studio 11 2012 [arch] = Deprecated. Generates Visual Studio 2012 project files. Optional [arch] can be "Win64" or "ARM". Visual Studio 9 2008 [arch] = Deprecated. Generates Visual Studio 2008 project files. Optional [arch] can be "Win64" or "IA64". Borland Makefiles = Generates Borland makefiles. NMake Makefiles = Generates NMake makefiles. NMake Makefiles JOM = Generates JOM makefiles. MSYS Makefiles = Generates MSYS makefiles. MinGW Makefiles = Generates a make file for use with mingw32-make. Green Hills MULTI = Generates Green Hills MULTI files (experimental, work-in-progress). Unix Makefiles = Generates standard UNIX makefiles. Ninja = Generates build.ninja files. Ninja Multi-Config = Generates build-<Config>.ninja files. Watcom WMake = Generates Watcom WMake makefiles. CodeBlocks - MinGW Makefiles = Generates CodeBlocks project files (deprecated). CodeBlocks - NMake Makefiles = Generates CodeBlocks project files (deprecated). CodeBlocks - NMake Makefiles JOM = Generates CodeBlocks project files (deprecated). CodeBlocks - Ninja = Generates CodeBlocks project files (deprecated). CodeBlocks - Unix Makefiles = Generates CodeBlocks project files (deprecated). CodeLite - MinGW Makefiles = Generates CodeLite project files (deprecated). CodeLite - NMake Makefiles = Generates CodeLite project files (deprecated). CodeLite - Ninja = Generates CodeLite project files (deprecated). CodeLite - Unix Makefiles = Generates CodeLite project files (deprecated). Eclipse CDT4 - NMake Makefiles = Generates Eclipse CDT 4.0 project files (deprecated). Eclipse CDT4 - MinGW Makefiles = Generates Eclipse CDT 4.0 project files (deprecated). Eclipse CDT4 - Ninja = Generates Eclipse CDT 4.0 project files (deprecated). Eclipse CDT4 - Unix Makefiles= Generates Eclipse CDT 4.0 project files (deprecated). Kate - MinGW Makefiles = Generates Kate project files (deprecated). Kate - NMake Makefiles = Generates Kate project files (deprecated). Kate - Ninja = Generates Kate project files (deprecated). Kate - Ninja Multi-Config = Generates Kate project files (deprecated). Kate - Unix Makefiles = Generates Kate project files (deprecated). Sublime Text 2 - MinGW Makefiles = Generates Sublime Text 2 project files (deprecated). Sublime Text 2 - NMake Makefiles = Generates Sublime Text 2 project files (deprecated). Sublime Text 2 - Ninja = Generates Sublime Text 2 project files (deprecated). Sublime Text 2 - Unix Makefiles = Generates Sublime Text 2 project files (deprecated).

The front has a star means it is the default type.

Such as ninja

cmake -S . -B cmake-build -G"Ninja"

Compile project

cd .\cmake-build\ cd ..
cmake --build .\cmake-build\

output

PS C:\Users\22153\Documents\Local Projects\CMakeLearn> cmake --build .\cmake-build\ MSBuild version 17.7.2+d6990bcfa for .NET Framework 1>Checking Build System Building Custom Rule C:/Users/22153/Documents/Local Projects/CMakeLearn/CMakeLists.txt main.cpp CMakeLearn.vcxproj -> C:\Users\22153\Documents\Local Projects\CMakeLearn\cmake-build\Debug\CMakeLearn.exe Building Custom Rule C:/Users/22153/Documents/Local Projects/CMakeLearn/CMakeLists.txt

Run

and we can use this to run the exe

PS C:\Users\22153\Documents\Local Projects\CMakeLearn> .\cmake-build\Debug\CMakeLearn.exe Hello, World!

and the ALL_BUILD ,the ZERO_CHECK is the VS only has.

if we use ninja or makefile,we need to add a command in CMakeLists.txt

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

and if we want to specify compile version

target_compile_features(CMakeLearn PRIVATE cxx_std_20)

Reuse syntax

In unittest\CMakeLists.txt

#define AddTest(x) macro(AddTest target_name) add_executable(${target_name} ./${target_name}.cpp) add_test(NAME ${target_name} COMMAND $<TARGET_FILE:${target_name}>) target_link_libraries(${target_name} PRIVATE CMakeLearn) target_precompile_headers(${target_name} REUSE_FROM CMakeLearn) endmacro() AddTest(cgmath) # AddTest(geom) # add_executable(cgmath ./cgmath.cpp) # add_test(NAME cgmath COMMAND $<TARGET_FILE:cgmath>) # target_link_libraries(cgmath PRIVATE CMakeLearn) # target_precompile_headers(cgmath REUSE_FROM CMakeLearn)

Compile ON & OFF

Allow user to choose whether something compile or not .

In main CMakeLists.txt

option(ENGINE_BUILD_TEST "should build unit test" OFF) # include(CTest) # enable_testing() # add_subdirectory(unittest) if (ENGINE_BUILD_TEST) include(CTest) enable_testing() add_subdirectory(unittest) endif ()

After this,we can use CMake GUI to control whether compile this ON or OFF.

We can also use terminal:

cmake -S . -B .\cmake-build\ -DENGINE_BUILD_TEST=ON

output

PS C:\Users\22153\Documents\Local Projects\CMakeLearn> cmake -S . -B .\cmake-build\ -DENGINE_BUILD_TEST=OFF -- Configuring done (0.0s) -- Generating done (0.0s) -- Build files have been written to: C:/Users/22153/Documents/Local Projects/CMakeLearn/cmake-build

Set Command

set(engine_name CMakeLearn)

In other locations,we can use ${engine_name} to replace name of this target.

CACHE

set(xx 123 CACHE) set(XX_PATH "" CACHE PATH "path of XX")

If we use cache,data can be persisted in the GUI.

TOP_LEVEL

If other users do not want to run our test,we could do this.

if (PROJECT_IS_TOP_LEVEL OR ENGINE_BUILD_TEST) include(CTest) enable_testing() add_subdirectory(unittest) endif ()
message("source files: ${engine_src}")

Foreach syntax:

aux_source_directory(./src engine_src) message("source files: ${engine_src}") foreach (var in ${engine_src}) message(${var}) endforeach ()

or

foreach (var ${engine_src}) message(${var}) endforeach ()

Sandbox

We could create a directory named sandbox under the root,and create a main.cpp and a CMakeLists.txt under it.

add_executable(sandbox main.cpp) target_link_libraries(sandbox PRIVATE ${engine_name}) add_custom_command(TARGET sandbox POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${mono_dll} $<TARGET_FILE_DIR:sandbox> )

In root directory ,our main CMakeLists.txt.

add_subdirectory(sandbox)

CMake communicate with *.cpp

For example,in mono\CMakeLists.txt

target_compile_definitions(mono INTERFACE MONO_PATH = "${MONO_PATH}")

It just like

#define MONO_PATH

We can use it directly in *.cpp.

Last modified: 02 July 2024