目录
凡是出现 IF 的地方一定要有对应的ENDIF。出现 ELSEIF 的地方,ENDIF 是可选的
SUBDIRS
SUBDIRS
是 CMake 中的一个指令,它用于在一个 CMake 项目中添加子目录。语法如下:
SUBDIRS(dir1 [dir2 ...])
其中 dir1
、dir2
等表示要添加的子目录。
该指令会自动查找每个子目录中的 CMakeLists.txt
文件,并在每个子目录中执行 cmake
命令,从而为子目录中的代码生成相应的构建文件。可以在子目录的 CMakeLists.txt
文件中使用 ADD_EXECUTABLE
、ADD_LIBRARY
等指令来定义目标,这些目标将会被包含在父级目录中。
当在项目的根目录中运行 cmake
命令时,CMake 会自动查找项目中所有的 CMakeLists.txt
文件,并根据这些文件的内容构建出相应的构建系统。如果在根目录的 CMakeLists.txt
文件中使用了 SUBDIRS
指令,则在构建系统中还会包含来自子目录中定义的目标。
cmake man page
man
命令是Linux/Unix中的一个命令,用于显示程序、函数、系统调用等的手册页(manual page),可以通过在终端中输入man
加上需要查询的命令或函数名来查看相应的手册页。例如,输入man ls
就可以查看ls
命令的手册页。在终端中输入man cmake
可以查看CMake的手册页,包括CMake的使用方法、命令参数、变量等。
ADD_DEFINITIONS
ADD_DEFINITIONS
是一个 CMake 命令,用于向 C/C++ 编译器添加编译选项,例如宏定义或警告标志等。
通过 ADD_DEFINITIONS
可以在 CMakeLists.txt 文件中向当前目录及其所有子目录中的源代码添加编译选项。它可以用于设置预处理器宏定义,例如开启调试模式、定义版本号等,还可以设置警告选项、优化等级等。
例如,以下命令会向编译器添加宏定义 DEBUG
和 -Wall
警告选项:
ADD_DEFINITIONS(-DDEBUG -Wall)
这将启用代码中的 #ifdef DEBUG
语句,并将编译器警告设置为最高级别。
ADD_DEPENDENCIES
ADD_DEPENDENCIES
是一个CMake函数,它用于将一个或多个自定义的构建目标添加到其他目标的依赖项列表中。当某个目标被构建时,其依赖项将在目标之前被构建。例如,可以使用ADD_DEPENDENCIES
将自定义命令或目标添加到库或可执行文件的依赖项列表中,以便在构建库或可执行文件之前执行自定义命令或构建自定义目标。 语法如下:
ADD_DEPENDENCIES(target-name depend-target1 depend-target2 ...)
其中,target-name
是将要被添加依赖项的目标名称,depend-target1, depend-target2, ...
是作为依赖项的其他目标名称。
ADD_TEST
ADD_TEST是一个CMake命令,用于为项目添加一个测试。它的语法如下:
ADD_TEST(testname Exename arg1 arg2 ...)
其中,testname是测试的名称,Exename是要运行的测试二进制文件,arg1、arg2等是传递给测试的命令行参数。
当运行“make test”或“ctest”命令时,CMake会自动运行通过ADD_TEST添加的测试,并根据测试结果输出结果。
ENABLE_TESTING()
ENABLE_TESTING()
是一个 CMake 命令,它用于启用测试。当你想在你的项目中运行一些测试时,需要在 CMakeLists.txt 中使用这个命令。它会为你的项目创建一个 test
目标,该目标可以运行由 ADD_TEST()
命令定义的测试。在生成 Makefile 或其他构建工具文件时,该命令会将 BUILD_TESTING
变量设置为 ON
。
ENABLE_TESTING()和ADD_TEST什么关系
ENABLE_TESTING()
和 ADD_TEST()
都是 CMake 中用于构建测试的命令,它们的关系是:
-
ENABLE_TESTING()
是一个命令,用于启用测试构建。在 CMakeLists.txt 文件中调用该命令后,就可以使用ADD_TEST()
命令来添加测试。 -
ADD_TEST()
命令用于向 CMake 构建系统中添加测试,它需要指定测试的名称和测试程序的路径。使用ADD_TEST()
命令添加的测试,只有在ENABLE_TESTING()
被调用后才会被构建和运行。
因此,ENABLE_TESTING()
和 ADD_TEST()
是配套使用的命令,前者用于开启测试构建,后者用于添加测试。
ENABLE_TESTING()指令是必须的,因为它启用了CTest测试,并且必须在ADD_TEST()指令之前调用。ADD_TEST()指令用于将测试添加到项目中,但是如果CTest测试框架未启用,则不会执行这些测试。因此,必须使用ENABLE_TESTING()指令启用CTest测试框架。
ADD_TEST(mytest ${PROJECT_BINARY_DIR}/bin/main)
ENABLE_TESTING()
这段代码将创建一个名为 mytest
的测试,使用生成的可执行文件 ${PROJECT_BINARY_DIR}/bin/main
来运行测试。同时,ENABLE_TESTING()
负责开启 CTest 测试并为每个测试创建一个可运行的测试程序。因此,在使用 ADD_TEST()
之前必须使用 ENABLE_TESTING()
启用 CTest 测试。
当你调用ENABLE_TESTING()
时,CMake会生成一个CTestConfig.cmake
文件,其中包含一些关于测试的配置选项,如测试程序的位置、测试超时时间等。这个文件被存储在构建目录下的Testing
子目录中。当你运行make test
时,CTest会读取这个文件,并根据其中的配置选项来执行测试。
这里ENABLE_TESTING()写在ADD_TEST()之后,但是依然可以正常运行。这是因为CMake会在生成Makefile之前先处理所有的CMakeLists.txt文件,因此ENABLE_TESTING()会在ADD_TEST()之前被处理,这就保证了ADD_TEST()的正常运行。
AUX_SOURCE_DIRECTORY
AUX_SOURCE_DIRECTORY是一个CMake命令,用于将一个目录中的所有源文件列表存储到一个变量中。命令的语法如下:
AUX_SOURCE_DIRECTORY(dir VARIABLE)
其中,dir
是要搜索源文件的目录路径,VARIABLE
是用于存储源文件列表的变量名。当命令执行成功后,CMake会将dir
目录中的所有源文件列表存储在VARIABLE
变量中。可以使用以下命令打印变量内容:
MESSAGE(${VARIABLE})
这个命令通常用于简化CMake中的源文件管理。
ADD_EXECUTABLE
ADD_EXECUTABLE是CMake中的一个命令,用于将可执行文件添加到项目中。它的语法为:
ADD_EXECUTABLE(target_name [source1] [source2 ...])
其中,target_name
为将要生成的可执行文件的名称,source1
、source2
等参数表示可执行文件的源代码文件,可以有多个。执行此命令后,CMake将生成指定名称的可执行文件,并将源文件编译为目标文件,然后将目标文件链接到可执行文件中。
CMAKE_MINIMUM_REQUIRED
CMAKE_MINIMUM_REQUIRED是一个CMake的命令,用于指定所需的CMake的最低版本。它需要在CMakeLists.txt文件中的顶部被调用,以确保在构建项目时使用正确版本的CMake。例如,如果你的项目需要CMake 3.10及以上的版本,你可以在CMakeLists.txt文件的顶部添加以下命令:
cmake_minimum_required(VERSION 3.10)
这将确保在构建项目时使用CMake 3.10或更高版本。如果使用低于3.10版本的CMake,则会收到一个错误消息,告诉你需要更新CMake。
EXEC_PROGRAM
EXEC_PROGRAM
是一个已弃用的CMake命令,它可以执行一个命令并将其输出存储到一个变量中。在较新版本的CMake中,可以使用execute_process
命令来完成同样的任务。 execute_process
命令提供了更多的选项和更灵活的用法,可以用来执行各种系统命令和外部程序,并可以定制输入、输出和环境变量等。
EXEC_PROGRAM命令的格式为:
EXEC_PROGRAM(command args... [OUTPUT_VARIABLE <var>] [RETURN_VALUE <var>])
其中,command
是要执行的命令,args
是命令的参数,可以有多个参数。OUTPUT_VARIABLE
指定命令的输出存储在哪个变量中,RETURN_VALUE
指定命令的返回值存储在哪个变量中。这两个参数都是可选的。
当使用EXEC_PROGRAM
命令时,CMake会启动一个新的进程来执行指定的命令,并等待命令执行完成后返回。命令执行的标准输出和标准错误输出可以通过OUTPUT_VARIABLE
参数和RETURN_VALUE
参数分别存储到变量中。
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)
在上面的例子中,EXEC_PROGRAM命令调用了ls
命令,并使用*.c
作为参数,以获取当前目录下所有以.c
结尾的文件,并将结果保存到名为LS_OUTPUT
的变量中。如果命令执行成功,将会打印出ls result: <输出内容>
。
FILE
FILE
是 CMake 中一个非常常用的命令,用于操作文件和目录。具体来说,FILE
命令的语法格式为:
FILE(<mode> <args...>)
其中,<mode>
参数可以指定操作模式,<args...>
参数则是具体的操作参数,格式与模式相关。以下是一些常见的模式:
COPY
: 复制文件或目录GLOB
: 获取符合指定通配符的文件列表MAKE_DIRECTORY
: 创建目录REMOVE
: 删除文件或目录RENAME
: 重命名文件或目录WRITE
: 写文件
例如,以下代码使用 FILE
命令复制了 source.txt
文件到 destination.txt
:
FILE(COPY source.txt DESTINATION destination.txt)
在 CMake 中,还有一些其他的命令也涉及文件和目录操作,比如 CONFIGURE_FILE
命令、INSTALL
命令等,但是 FILE
命令是最为基础和常用的。
FILE(WRITE filename "message to write"... )
用于向指定文件中写入内容,如果文件不存在则会创建一个新文件,如果文件已存在则会覆盖原有内容。filename
表示文件名(必选),message to write
表示要写入的内容(必选),可以有多个要写入的内容,用空格隔开。
FILE(APPEND filename "message to write"... )
用于向指定文件中追加内容,如果文件不存在则会创建一个新文件。filename
表示文件名(必选),message to write
表示要追加的内容(必选),可以有多个要追加的内容,用空格隔开。
FILE(READ filename variable)
用于将指定文件中的内容读取到一个变量中。filename
表示文件名(必选),variable
表示要存储读取内容的变量名(必选)。
FILE(GLOB variable [RELATIVE path] [globbing expressions]...)
用于将指定路径下的符合特定条件的文件名读取到一个变量中。variable
表示要存储读取的文件名的变量名(必选),path
表示指定的路径(可选,默认为当前目录),globbing expressions
表示匹配的通配符表达式(可选)。
FILE(GLOB_RECURSE variable [RELATIVE path] [globbing expressions]...)
用于将指定路径下的所有子目录中符合特定条件的文件名读取到一个变量中。variable
表示要存储读取的文件名的变量名(必选),path
表示指定的路径(可选,默认为当前目录),globbing expressions
表示匹配的通配符表达式(可选)。
FILE(REMOVE [directory]...)
用于删除指定的目录。directory
表示要删除的目录名(必选),可以有多个目录名,用空格隔开。
FILE(REMOVE_RECURSE [directory]...)
用于删除指定目录及其子目录。directory
表示要删除的目录名(必选),可以有多个目录名,用空格隔开。
FILE(MAKE_DIRECTORY [directory]...)
用于创建指定的目录。directory
表示要创建的目录名(必选),可以有多个目录名,用空格隔开。
FILE(RELATIVE_PATH variable directory file)
用于将指定文件相对于指定目录的相对路径读取到一个变量中。variable
表示要存储相对路径的变量名(必选),directory
表示指定的目录(必选),file
表示指定的文件(必选)。
FILE(TO_CMAKE_PATH path result)
将路径path
转换为CMake兼容的路径,并将结果保存在变量result
中。CMake兼容的路径使用正斜杠(/)作为路径分隔符,而不是Windows中的反斜杠(\)。
FILE(TO_NATIVE_PATH path result)
将路径path
转换为本机系统兼容的路径,并将结果保存在变量result
中。本机系统兼容的路径使用本机操作系统的路径分隔符,例如Windows中的反斜杠(\)或Linux中的正斜杠(/)。
INCLUDE
INCLUDE命令用于包含其他cmake文件。使用INCLUDE
命令可以将外部的CMake模块或其他CMakeLists.txt文件中定义的函数和宏等引入到当前的CMakeLists.txt文件中,方便在当前文件中使用。其基本语法如下:
INCLUDE(file [OPTIONAL] [RESULT_VARIABLE <variable>] [NO_POLICY_SCOPE])
其中,file指定要包含的cmake文件的路径,可以是相对路径或绝对路径。OPTIONAL选项表示该文件是可选的,如果找不到该文件,不会发生错误,cmake也不会输出警告信息。RESULT_VARIABLE选项可用于指定一个变量名,该变量将包含包含文件的结果,如果省略该选项,则文件中定义的变量将在cmake中全局可用。NO_POLICY_SCOPE选项可用于禁用该文件中指定的策略。
例如,以下示例代码包含名为mylib.cmake的cmake文件:
INCLUDE(mylib.cmake)
如果mylib.cmake文件定义了变量myvar,则该变量可以在包含它的cmake文件中直接使用,如下所示:
MESSAGE(${myvar})
此外,还可以使用RESULT_VARIABLE选项指定一个变量来存储包含文件的结果,并在需要时检查该变量,如下所示:
INCLUDE(mylib.cmake RESULT_VARIABLE result)
IF(NOT result)
MESSAGE("Failed to include mylib.cmake")
ENDIF()
FIND
FIND_FILE(<VAR> name1 path1 path2 ...)
VAR 变量代表找到的文件全路径,包含文件名
FIND_LIBRARY(<VAR> name1 path1 path2 ...)
VAR 变量表示找到的库全路径,包含库文件名
FIND_PATH(<VAR> name1 path1 path2 ...)
VAR 变量代表包含这个文件的路径。
FIND_PROGRAM(<VAR> name1 path1 path2 ...)
VAR 变量代表包含这个程序的全路径。
FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE] [[REQUIRED|COMPONENTS] [componets...]])
FIND_PACKAGE
是 CMake 中一个常用的指令,用于查找并载入指定的包。这个指令主要用于查找和配置第三方库和工具,如 OpenCV、Boost、Qt 等。 FIND_PACKAGE
可以从系统中查找已经安装的库和工具,也可以从源码中构建这些库和工具。下面是 FIND_PACKAGE
的一些常用参数:
<name>
:要查找的包的名称。这个名称通常是小写的,例如opencv
、boost
等。[major.minor]
:可选参数,指定所需包的版本号。例如find_package(OpenCV 4.5 REQUIRED)
。[QUIET]
:可选参数,如果设置,则在未找到包时不会输出错误信息。[NO_MODULE]
:可选参数,如果设置,则在使用 CMake 模块之前不会搜索CMAKE_MODULE_PATH
。这个选项通常在找不到包时使用。[[REQUIRED|COMPONENTS] [components...]]
:可选参数,如果设置,则指定需要的库和工具。使用REQUIRED
参数指定库和工具是必需的,使用COMPONENTS
参数指定需要的库和工具。
使用 FIND_PACKAGE
后,可以使用 if
语句检查是否找到了需要的库和工具,并使用 target_link_libraries()
指令将库链接到目标程序中。例如:
find_package(OpenCV 4.5 REQUIRED)
if(OpenCV_FOUND)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(my_program ${OpenCV_LIBS})
endif()
FIND_FILE(<VAR> name1 path1 path2 ...)
是一个 CMake 命令,用于在指定的路径列表中查找一个指定的文件,并将其结果保存到 CMake 变量中。如果找到该文件,则 <VAR>
将被设置为文件的绝对路径,否则将保持为空。
命令参数说明:
<VAR>
: 要设置的 CMake 变量的名称。name1 path1 path2 ...
: 要查找的文件名称和路径列表。
示例:
FIND_FILE(MY_FILE my_file.txt /usr/share/data /usr/local/data)
IF(MY_FILE)
MESSAGE("Found my_file.txt at ${MY_FILE}")
ELSE()
MESSAGE("Could not find my_file.txt")
ENDIF()
该示例将在 /usr/share/data
和 /usr/local/data
目录中查找名为 my_file.txt
的文件。如果找到该文件,则变量 MY_FILE
将设置为文件的绝对路径,否则变量将保持为空。
凡是出现 IF 的地方一定要有对应的ENDIF。出现 ELSEIF 的地方,ENDIF 是可选的
FOREACH
FOREACH是CMake语言中的一个控制流语句,用于循环遍历一个列表或者一个范围。
FOREACH的语法如下:
FOREACH(loop_var RANGE start stop [step])
# 循环体
ENDFOREACH(loop_var)
其中loop_var是循环变量,start、stop、step是循环的起始值、结束值和步长,可以是数字或者变量名。FOREACH还支持对一个列表进行循环,语法如下:
FOREACH(loop_var IN LISTS list_var)
# 循环体
ENDFOREACH(loop_var)
其中loop_var是循环变量,list_var是要循环遍历的列表变量名。FOREACH语句执行时,循环变量loop_var依次取列表中的每个元素,将每个元素依次赋值给loop_var,并执行循环体中的语句。
需要注意的是,直到遇到 ENDFOREACH 指令,整个语句块才会得到真正的执行。