Cmake construction engineering design -- cmake writing rules

Cmake commands do not distinguish between write down and write down, such as message, set and other commands; However, cmake variables are case sensitive.
For a unified style, all Cmake commands this time are in lowercase, and all variables are in uppercase and underlined combination.

Cmake variable

The Cmake variable can be assigned with the keyword set. The variable can be assigned in the form of switch, number, string and list, which will be used many times in Cmake later.
Option is a switch option, which is usually used as a compilation switch.

Sample code

option(OPEN_TEST "open test" ON)
set(FALSE_TEST FALSE)
set(NUMBER_TEST 3.14)
set(STRING_TEST "Cmake Test")
set(SOURCE_LIST_TEST main.cpp module1.cpp module2.cpp)
if (OPEN_TEST)
	message(STATUS "open test: ${OPEN_TEST}")
endif()

if (NOT FALSE_TEST)
	message(STATUS "false test: ${FALSE_TEST}")
endif()

message(STATUS "number test: ${NUMBER_TEST}")
message(STATUS "string test: ${STRING_TEST}")
message(STATUS "code list test: ${SOURCE_LIST_TEST}")

results of enforcement

-- open test: ON
-- false test: FALSE
-- number test: 3.14
-- string test: Cmake Test
-- code list test: main.cpp;module1.cpp;module2.cpp

The collection of variables will be marked with ';' separate

Cmake pass parameter

When executing the cmake command, cmake can pass parameters to variables, for example:

  1. For variable CMAKE_TOOLCHAIN_FILE parameters:
    -DCMAKE_TOOLCHAIN_FILE=.../config.cmake
  2. For variable CMAKE_BUILD_TYPE parameters:
    -DCMAKE_BUILD_TYPE="Debug"

Read the configuration file cmake

Some common cmake configurations do not need to be configured again in cmake projects. They can be imported through different cmake projects. The suffix of this file is Cmake, the read configuration file can be imported by passing parameters or loaded by CmakeLists keyword

Import by passing parameters through cmake command

cmake -G "$CMAKE_TYPE" ../ -DCMAKE_TOOLCHAIN_FILE=../config.cmake

Import by keyword

include(${PROJECT_SOURCE_DIR}/common_config.cmake)

Setup project: Project

The parameter set for project in the description of the current version is

project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
        [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
        [DESCRIPTION <project-description-string>]
        [HOMEPAGE_URL <url-string>]
        [LANGUAGES <language-name>...])

LANGUAGES is the specified language. If the project has a mixture of multiple LANGUAGES, this value can not be set

The simple version directly sets a project name

set(MAIN_NAME CmakeTest)
project(${MAIN_NAME})

The corresponding description can be added in the detailed version

set(MAIN_NAME CmakeTest)
project(${MAIN_NAME}
    VERSION 1.2.3.4
    DESCRIPTION "CmekTest"
    HOMEPAGE_URL "https://cmake.org/cmake/help/v3.15/command/project.html")

Print engineering variables

message("PROJECT_NAME ${PROJECT_NAME}")
message("PROJECT_VERSION ${PROJECT_VERSION}")
message("PROJECT_DESCRIPTION ${PROJECT_DESCRIPTION}")
message("PROJECT_HOMEPAGE_URL ${PROJECT_HOMEPAGE_URL}")
# If there are multiple projects in the project, the corresponding project name can be used
message("MAIN_NAME ${MAIN_NAME}")
message("${MAIN_NAME}_VERSION ${${MAIN_NAME}_VERSION}")
message("${MAIN_NAME}_DESCRIPTION ${${MAIN_NAME}_DESCRIPTION}")
message("${MAIN_NAME}_HOMEPAGE_URL ${${MAIN_NAME}_HOMEPAGE_URL}")

Print results

PROJECT_NAME CmakeTest
PROJECT_VERSION 1.2.3.4
PROJECT_DESCRIPTION CmekTest
PROJECT_HOMEPAGE_URL https://cmake.org/cmake/help/v3.15/command/project.html
MAIN_NAME CmakeTest
CmakeTest_VERSION 1.2.3.4
CmakeTest_DESCRIPTION CmekTest
CmakeTest_HOMEPAGE_URL https://cmake.org/cmake/help/v3.15/command/project.html

notes

Cmake annotates with "#"

Condition judgment: if

Like C/C + +, conditional judgment is carried out through if, else if and endif keywords.

if(<condition>)
  <commands>
elseif(<condition>) # optional block, can be repeated
  <commands>
else()              # optional block
  <commands>
endif()

Official description:

https://cmake.org/cmake/help/v3.15/command/if.html?highlight=#command:if

if(NOT <condition>)
Conditional non

if(<cond1> AND <cond2>)
Conditions and

if(<cond1> OR <cond2>)
Condition or

if(<variable|string> LESS <variable|string>)
If the value of the given string or variable is a valid value and is less than the value on the right; otherwise True. 

if(<variable|string> GREATER <variable|string>)
If the value of the given string or variable is a valid value and greater than the value on the right; otherwise True. 

if(<variable|string> EQUAL <variable|string>)
If the value of a given string or variable is a valid value and is equal to the value on the right; otherwise True. 

if(<variable|string> LESS_EQUAL <variable|string>)
If the value of the given string or variable is a valid value and is less than or equal to the value on the right; otherwise True. 
if(<variable|string> GREATER_EQUAL <variable|string>)
If the value of the given string or variable is a valid value and is greater than or equal to the value on the right; otherwise True. 

Loop: foreach, while

foreach

foreach(<loop_var> <items>)
  <commands>
endforeach()

foreach can extend the following forms

foreach(<loop_var> RANGE <stop>)
Starting from 0, stop Fill in non negative integers with numbers 0, 1, 2

foreach(<loop_var> RANGE <start> <stop> [<step>])
start stop step Fill in non negative integers with numbers of 0, 1, 2,..., if step Unspecified, default step size is 1, stop Not less than start

foreach(loop_var IN [LISTS [<lists>]] [ITEMS [<items>]])
Incoming list or item

Official details:

https://cmake.org/cmake/help/v3.15/command/foreach.html?highlight=foreach

The keyword continue is the same as the break logic

Examples

message(STATUS "foreach(getValue 2 3 5 7 11 13 17 19)")
foreach(getValue 2 3 5 7 11 13 17 19)
	if(getValue LESS 5)
		continue()
	endif()
	message(STATUS "foreach1 getValue: ${getValue}")	
endforeach()

message(STATUS "getValue RANGE 5")
foreach(getValue RANGE 5)
	if(getValue GREATER 3)
		break()
	endif()
	message(STATUS "foreach2 getValue: ${getValue}")
endforeach()

message(STATUS "foreach(getValue RANGE 2 20 4)")
foreach(getValue RANGE 2 20 4)
	message(STATUS "foreach3 getValue: ${getValue}")
endforeach()

# Use official examples
set(A 0;1)
set(B 2 3)
set(C "4 5")
set(D 6;7 8)
set(E "")
message(STATUS "foreach(X IN LISTS A B C D E)")
foreach(X IN LISTS A B C D E)
    message(STATUS "X=${X}")
endforeach()

results of enforcement

-- foreach(getValue 2 3 5 7 11 13 17 19)
-- foreach1 getValue: 5
-- foreach1 getValue: 7
-- foreach1 getValue: 11
-- foreach1 getValue: 13
-- foreach1 getValue: 17
-- foreach1 getValue: 19
-- getValue RANGE 5
-- foreach2 getValue: 0
-- foreach2 getValue: 1
-- foreach2 getValue: 2
-- foreach2 getValue: 3
-- foreach(getValue RANGE 2 20 4)
-- foreach3 getValue: 2
-- foreach3 getValue: 6
-- foreach3 getValue: 10
-- foreach3 getValue: 14
-- foreach3 getValue: 18
-- foreach(X IN LISTS A B C D E)
-- X=0
-- X=1
-- X=2
-- X=3
-- X=4 5
-- X=6
-- X=7
-- X=8

while

while(<condition>)
  <commands>
endwhile()

The condition variable needs to be self increasing or self decreasing

Examples

set(getValue 2) 
while(getValue LESS 6)
	message(STATUS "while getValue : ${getValue}")
	math(EXPR getValue "${getValue} + 1")
endwhile()

results of enforcement

-- while getValue : 2
-- while getValue : 3
-- while getValue : 4
-- while getValue : 5

Judge the current system name

It can be judged through the system macro

if(WIN32)
    message("PC Windows ${CMAKE_BUILD_TYPE}")
elseif(UNIX)
    message("PC UNIX ${CMAKE_BUILD_TYPE}")
    add_definitions(-D USE_LINUX)   
endif(WIN32)

if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
	message ("PC Linux")
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
	message ("PC Windows")
else ()
	message ("other system: ${CMAKE_SYSTEM_NAME}")
endif ()

You can also use the default variable cmake directly_ SYSTEM_ Name to judge

Windows effects

PC Windows Debug
PC Windows

Linux effect

PC UNIX Debug
PC Linux

Display compilation information

After Cmake builds the project, compiling with make will display the compilation progress of Cmake by default, but the complete compilation information is not displayed

[  3%] Building C object src/lib/TestLib/CMakeFiles/test_lib.dir/src/open_module1.c.o
[  7%] Building CXX object src/app/AlgorithmTest/CMakeFiles/algorithmTest.dir/src/BinaryTree.cpp.o
[ 10%] Building C object src/lib/TestLib/CMakeFiles/test_lib.dir/src/open_module2.c.o

There are three ways to display complete compilation information
1,CmakeLists.txt setting variables

set(CMAKE_VERBOSE_MAKEFILE ON)

2. When cmake is executed, variables are passed in through cmake parameters

-DCMAKE_VERBOSE_MAKEFILE=ON

3. Add parameters when making

make VERBOSE=1

Execution effect

[3%] Building C object src/lib/TestLib/CMakeFiles/test_lib.dir/src/open_module1.c.o
cd /home/ghost/test_Makefile/project_cache/src/lib/TestLib && /usr/bin/gcc -Dtest_lib_EXPORTS -I/home/ghost/test_Makefile/src/include -I/home/ghost/test_Makefile/src/lib/TestLib/inc  -O3 -DNDEBUG -fPIC   -D USE_LINUX -o CMakeFiles/test_lib.dir/src/open_module1.c.o   -c /home/ghost/test_Makefile/src/lib/TestLib/src/open_module1.c
[7%] Building CXX object src/app/AlgorithmTest/CMakeFiles/algorithmTest.dir/src/BinaryTree.cpp.o
[10%] Building CXX object src/app/AlgorithmTest/CMakeFiles/algorithmTest.dir/src/ClassicalAlgorithm.cpp.o
cd /home/ghost/test_Makefile/project_cache/src/app/AlgorithmTest && /usr/bin/g++   -I/home/ghost/test_Makefile/src/include -I/home/ghost/test_Makefile/src/app/AlgorithmTest/inc  -std=c++11 -std=c++11 -O3 -DNDEBUG   -D USE_LINUX -o CMakeFiles/algorithmTest.dir/src/BinaryTree.cpp.o -c /home/ghost/test_Makefile/src/app/AlgorithmTest/src/BinaryTree.cpp
cd /home/ghost/test_Makefile/project_cache/src/app/AlgorithmTest && /usr/bin/g++   -I/home/ghost/test_Makefile/src/include -I/home/ghost/test_Makefile/src/app/AlgorithmTest/inc  -std=c++11 -std=c++11 -O3 -DNDEBUG   -D USE_LINUX -o CMakeFiles/algorithmTest.dir/src/ClassicalAlgorithm.cpp.o -c /home/ghost/test_Makefile/src/app/AlgorithmTest/src/ClassicalAlgorithm.cpp

Predefined macros: add_definitions

Encountered in macro definition, for example

#ifdef USE_LINUX
std::cout << "use linux" << std::endl;
#endif

This definition can be passed in Cmake

if(WIN32)
message("PC Windows ${CMAKE_BUILD_TYPE}")
elseif(UNIX)
message("PC UNIX ${CMAKE_BUILD_TYPE}")
add_definitions(-D USE_LINUX)	
endif(WIN32)

The macros defined here are public macros. If you need to specify the macro of the target, you need to use the target constraint

target_compile_definitions(${PROJECT_APP} 
	PRIVATE -D DEFINE_TEST)

Functions: function

function(<name> [<arg1> ...])
  <commands>
endfunction()

The functions defined in the parent directory can be called by the child directory, and the functions can be placed in the parent directory cmake configuration file

Examples

function (PrintPCName arg1 arg2 arg3)
		message(STATUS "function ARGC: ${ARGC}")
		message(STATUS "function ARGV: ${ARGV}")
		message(STATUS "function ARGV0: ${ARGV0}")
		message(STATUS "function ARGV1: ${ARGV1}")
message(STATUS "function ARGV2: ${ARGV2}")
    	message(STATUS "function ARGN: ${ARGN}")
    
    	message(STATUS "System Name : ${CMAKE_SYSTEM_NAME}")
endfunction()

PrintPCName(1 ${PROJECT_APP} 2 3 4)

results of enforcement

-- function ARGC: 5
-- function ARGV: 1;project_app;2;3;4
-- function ARGV0: 1
-- function ARGV1: project_app
-- function ARGV2: 2
-- function ARGN: 3;4
-- System Name : Linux

Function parameter description

Variable nameexplain
ARGCNumber of parameters
ARGVparameter list
ARGV0Parameter 0
ARGV1Parameter 1
ARGV2Parameter 2
......
ARGNParameter list exceeding the number of parameters passed

Loop get variable
Examples

function (PrintPCName arg1 arg2 arg3)
    message(STATUS "ARGC : ${ARGC}")
    
    foreach(getValue ${ARGV})
        message(STATUS "argv: ${getValue}")
    endforeach()

    message(STATUS "System Name : ${CMAKE_SYSTEM_NAME}")

endfunction()

PrintPCName(1 ${PROJECT_APP} 2 3 4)

results of enforcement

-- ARGC : 5
-- argv: 1
-- argv: project_app
-- argv: 2
-- argv: 3
-- argv: 4
-- System Name : Linux

Keywords: cmake Project management

Added by Jak on Tue, 01 Feb 2022 09:31:06 +0200