CMake Common Commands

I. Introduction

cmake is much simpler than autotools. Next, let's focus on the common instructions provided by cmake. In the previous article we have discussed the usage of many commands, such as PROJECT, ADD_EXECUTABLE, INSTALL, ADD_SUBDIRECTORY, SUBDIRS, INCLUDE_DIRECTORIES, LINK_DIRECTORIES, TARGET_LINK_LIBRARIES, SET, etc.

This section introduces more cmake instructions. For the convenience of writing, various instructions will be introduced in the order of the cmake man page. The instructions that are no longer recommended will not be introduced. The INSTALL series instructions have been described in detail in the installation section. Instructions are not mentioned here.

2. Basic instructions

2.1、ADD_DEFINITIONS

Add a -D definition to the C/C++ compiler, e.g.:

ADD_DEFINITIONS(-DENABLE_DEBUG -DABC)

Parameters are separated by spaces.

If your code defines

#ifdef ENABLE_DEBUG 
// ...
#endif

This block of code will take effect.

If you want to add other compiler switches, you can set them through the CMAKE_C_FLAGS variable and CMAKE_CXX_FLAGS variable.

2.2、ADD_DEPENDENCIES

Define other targets that the target depends on, and ensure that other targets have been built before compiling this target.

ADD_DEPENDENCIES(target-name depend-target1 depend-target2 ...)

2.3. ADD_TEST and ENABLE_TESTING instructions.

The ENABLE_TESTING command is used to control whether the Makefile builds the test target, involving all directories of the project. The syntax is simple, without any parameters:

ENABLE_TESTING()

Generally, this command is placed in the main CMakeLists.txt of the project.

The syntax of the ADD_TEST command is:

ADD_TEST(testname Exename arg1 arg2 ...)

testname is a custom test name, and Exename can be a built target file or an external script, etc. Arguments passed to the executable are concatenated later. Any ADD_TEST has no effect without the ENABLE_TESTING() directive turned on in the same CMakeLists.txt.

for example:

ADD_TEST(mytest ${
    
    PROJECT_BINARY_DIR}/bin/main) 
ENABLE_TESTING()

After generating the Makefile, you can run make test to execute the tests.

2.4、AUX_SOURCE_DIRECTORY

The basic syntax is:

AUX_SOURCE_DIRECTORY(dir VARIABLE)

The function is to find all the source code files in a directory and store the list in a variable. This instruction is temporarily used to automatically build the source file list. Because currently cmake cannot automatically discover newly added source files.

for example:

AUX_SOURCE_DIRECTORY(. SRC_LIST)
ADD_EXECUTABLE(main ${
    
    SRC_LIST})

This LIST can also be processed by the FOREACH instruction mentioned later

2.5、CMAKE_MINIMUM_REQUIRED

Its syntax is:

CMAKE_MINIMUM_REQUIRED(VERSION versionNumber [FATAL_ERROR])

for example:

CMAKE_MINIMUM_REQUIRED(VERSION 2.5 FATAL_ERROR)

If the cmake version is less than 2.5, a serious error occurs and the whole process is aborted.

2.6、EXEC_PROGRAM

Commands are executed during CMakeLists.txt processing, not in the generated Makefile. The specific syntax is:

EXEC_PROGRAM(Executable [directory in which to run]
[ARGS <arguments to executable>]
[OUTPUT_VARIABLE <var>]
[RETURN_VALUE <var>])

It is used to run a program in the specified directory, add parameters through ARGS, if you want to get the output and return value, you can define two variables through OUTPUT_VARIABLE and RETURN_VALUE respectively.

This command can help you support any commands during CMakeLists.txt processing, such as modifying code files according to system conditions and so on.

To give a simple example, we want to execute the ls command in the src directory, and save the result and return value.

Can be added directly in src/CMakeLists.txt:

EXEC_PROGRAM(ls ARGS "*.c" OUTPUT_VARIABLE LS_OUTPUT RETURN_VALUE LS_RVALUE)
IF(not LS_RVALUE)
 
MESSAGE(STATUS "ls result: " ${
    
    LS_OUTPUT})
 
ENDIF(not LS_RVALUE)

During the process of cmake generating the Makefile, the ls command will be executed. If it returns 0, it means the execution is successful, then the result of ls *.c will be output. Regarding the IF statement, it will be mentioned later in the control instruction.

2.7. FILE command

File operation instructions, the basic syntax is:

FILE(WRITE filename "message to write"... )

FILE(APPEND filename "message to write"... )

FILE(READ filename variable)
 
FILE(GLOB variable [RELATIVE path] [globbing expressions]...)

FILE(GLOB_RECURSE variable [RELATIVE path] [globbing expressions]...)

FILE(REMOVE [directory]...)
 
FILE(REMOVE_RECURSE [directory]...)
 
FILE(MAKE_DIRECTORY [directory]...)
 
FILE(RELATIVE_PATH variable directory file)
 
FILE(TO_CMAKE_PATH path result)
 
FILE(TO_NATIVE_PATH path result)

The grammar here is relatively simple, so I won’t introduce it here.

2.8, INCLUDE command

Used to load the CMakeLists.txt file, also used to load the predefined cmake modules:

INCLUDE(file1 [OPTIONAL])
 
INCLUDE(module [OPTIONAL])

The effect of the OPTIONAL parameter is that the file does not exist and no error will be generated.

You can specify to load a file. If a module is defined, the module will be searched in CMAKE_MODULE_PATH and loaded.

The loaded content will be executed directly when processing to the INCLUDE statement.

2.9. Other instructions

ADD_EXECUTABLE, ADD_LIBRARY, and ADD_SUBDIRECTORY have been introduced before, so I won’t repeat them here.

The INSTALL series of instructions have been described in detail in the previous article, so I won’t go into details here, you can refer to the previous article.

3. FIND_ series instructions

The FIND_ series instructions mainly include the following instructions:

FIND_FILE(<VAR> name1 path1 path2 ...)

The VAR variable represents the full path of the found file, including the file name.

FIND_LIBRARY(<VAR> name1 path1 path2 ...)

The VAR variable represents the full path of the found library, including the library file name.

FIND_PATH(<VAR> name1 path1 path2 ...)

The VAR variable represents the path containing this file.

FIND_PROGRAM(<VAR> name1 path1 path2 ...)

The VAR variable represents the full path containing the program.

FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE] [[REQUIRED|COMPONENTS] [componets...]])

It is used to call the Find< name >.cmake module predefined under CMAKE_MODULE_PATH. You can also define the Find module yourself, and put it into a certain directory of the project through SET(CMAKE_MODULE_PATH dir) for project use.

FIND_LIBRARY example:

FIND_LIBRARY(libX X11 /usr/lib)
IF(NOT libX)
MESSAGE(FATAL_ERROR “libX not found”)
ENDIF(NOT libX)

4. Control instructions

4.1, IF instruction

The basic syntax is:

IF(expression)
#  THEN section. COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ELSE(expression)
#  ELSE section. COMMAND1(ARGS ...) COMMAND2(ARGS ...)
...
ENDIF(expression)

The other instruction is ELSEIF. Generally speaking, there is a principle that wherever IF appears, there must be a corresponding ENDIF. Where ELSEIF appears, ENDIF is optional.

Expressions are used as follows:

  • IF(var), the expression is true if the variable is not: NULL, 0, N, NO, OFF, FALSE, NOTFOUND or <var>_NOTFOUND.
  • IF(NOT var ), the opposite of the above condition.
  • IF(var1 AND var2), is true when both variables are true.
  • IF(var1 OR var2), true when one of the two variables is true.
  • IF(COMMAND cmd), true if the given cmd is indeed a command and can be invoked.
  • IF(EXISTS dir) or IF(EXISTS file), true if the directory name or file name exists.
  • IF(file1 IS_NEWER_THAN file2), when file1 is newer than file2, or one of file1/file2 does not exist, please use the full path for the file name.
  • IF(IS_DIRECTORY dirname), true when dirname is a directory. ,
  • IF(variable MATCHES regex)。
  • IF(string MATCHES regex)。

True if the given variable or string matches the regular expression regex. for example:

IF("hello" MATCHES "ell")
MESSAGE("true")
 
ENDIF("hello" MATCHES "ell")

IF(variable LESS number)
 
IF(string LESS number)
 
IF(variable GREATER number)
 
IF(string GREATER number)
 
IF(variable EQUAL number)
 
IF(string EQUAL number)

Numeric comparison expressions:

IF(variable STRLESS string)
 
IF(string STRLESS string)
 
IF(variable STRGREATER string)
 
IF(string STRGREATER string)
 
IF(variable STREQUAL string)
 
IF(string STREQUAL string)

Compare alphabetically:

IF(DEFINED variable), true if the variable is defined.

A small example to judge platform differences:

IF(WIN32)
MESSAGE(STATUS “This is windows.”)
#作一些Windows 相关的操作
ELSE(WIN32)
MESSAGE(STATUS “This is not windows”)
#作一些非Windows 相关的操作
ENDIF(WIN32)

The above code is used to control different controls on different platforms, but it is not so comfortable to read. Statements such as ELSE (WIN32) can easily cause ambiguity.

This uses the CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS switch we mentioned in the "Common Variables" section.

可以SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)

Then it can be written as:

IF(WIN32)
ELSE()
ENDIF()

If it is used with ELSEIF, the possible writing method is as follows:

IF(WIN32)
#do something related to WIN32
ELSEIF(UNIX)
#do something related to UNIX
ELSEIF(APPLE)
#do something related to APPLE
ENDIF(WIN32)

4.2、WHILE

The syntax of the WHILE directive is:

WHILE(condition)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDWHILE(condition)

Its true and false judgment conditions can refer to the IF instruction.

4.3、FOREACH

There are three forms of usage of the FOREACH instruction:

(1) List:

FOREACH(loop_var arg1 arg2 ...)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDFOREACH(loop_var)

Like the AUX_SOURCE_DIRECTORY example we used earlier:

AUX_SOURCE_DIRECTORY(. SRC_LIST) FOREACH(F ${
    
    SRC_LIST})
MESSAGE(${
    
    F})
ENDFOREACH(F)

(2. area:

FOREACH(loop_var RANGE total)
ENDFOREACH(loop_var)

From 0 to total in steps of 1.

Examples are as follows:

FOREACH(VAR RANGE 10)
MESSAGE(${
    
    VAR})
ENDFOREACH(VAR)

The resulting output is:

0
1
2
3
4
5
6
7
8
9
10

(3) Range and step:

FOREACH(loop_var RANGE start stop [step])
ENDFOREACH(loop_var)

From start to stop, take step as the step.

Examples are as follows:

FOREACH(A RANGE 5 15 3)
MESSAGE(${
    
    A})
ENDFOREACH(A)

The final result is:

5
8
11 
14

What needs to be noted about this instruction is that the entire statement block will be actually executed until the ENDFOREACH instruction is encountered.

Summarize

  1. It basically covers commonly used cmake instructions, including basic instructions, search instructions, installation instructions, and control statements. It should be noted that variables used in control statement conditions cannot be quoted with ${}, but directly apply variable names.
  2. After mastering the above various control commands, it should be possible to manage complex programs through cmake.

insert image description here

Guess you like

Origin blog.csdn.net/Long_xu/article/details/129179618