cmake使用示例与整理总结cmake中一些预定义变量PROJECT\_SOURCE\_DIR 工程的根目录PROJECT\_BINARY\_DIR 运行cmake命令的目录,通常是${PROJECT\_SOURCE\_DIR}/buildCMAKE\_INCLUDE\_PATH 环境变量,非cmake变量CMAKE\_LIBRARY\_PATH 环境变量CMAKE\_CURRENT\_SOURCE\_DIR 当前处理的CMakeLists.txt所在的路径CMAKE\_CURRENT\_BINARY\_DIR target编译目录使用ADD\_SURDIRECTORY(src bin)可以更改此变量的值SET(EXECUTABLE\_OUTPUT\_PATH <新路径>)并不会对此变量有影响,只是改变了最终目标文件的存储路径CMAKE\_CURRENT\_LIST\_FILE 输出调用这个变量的CMakeLists.txt的完整路径CMAKE\_CURRENT\_LIST\_LINE 输出这个变量所在的行CMAKE\_MODULE\_PATH 定义自己的cmake模块所在的路径SET(CMAKE\_MODULE\_PATH ${PROJECT\_SOURCE\_DIR}/cmake),然后可以用INCLUDE命令来调用自己的模块EXECUTABLE\_OUTPUT\_PATH 重新定义目标二进制可执行文件的存放位置LIBRARY\_OUTPUT\_PATH 重新定义目标链接库文件的存放位置PROJECT\_NAME 返回通过PROJECT指令定义的项目名称CMAKE\_ALLOW\_LOOSE\_LOOP\_CONSTRUCTS 用来控制IF ELSE语句的书写方式系统信息CMAKE\_MAJOR\_VERSION cmake主版本号,如2.8.6中的2CMAKE\_MINOR\_VERSION cmake次版本号,如2.8.6中的8CMAKE\_PATCH\_VERSION cmake补丁等级,如2.8.6中的6CMAKE\_SYSTEM 系统名称,例如Linux-2.6.22CAMKE\_SYSTEM\_NAME 不包含版本的系统名,如LinuxCMAKE\_SYSTEM\_VERSION 系统版本,如2.6.22CMAKE\_SYSTEM\_PROCESSOR 处理器名称,如i686UNIX 在所有的类UNIX平台为TRUE,包括OS X和cygwinWIN32 在所有的win32平台为TRUE,包括cygwin开关选项BUILD\_SHARED\_LIBS 控制默认的库编译方式。如果未进行设置,使用ADD\_LIBRARY时又没有指定库类型,默认编译生成的库都是静态库 （可在t3中稍加修改进行验证）CMAKE\_C\_FLAGS 设置C编译选项CMAKE\_CXX\_FLAGS 设置C++编译选项cmake常用命令基本语法规则：cmake变量使用${}方式取值,但是在IF控制语句中是直接使用变量名环境变量使用$ENV{}方式取值,使用SET(ENV{VAR} VALUE)赋值指令(参数1 参数2...)参数使用括弧括起,参数之间使用空格或分号分开。以ADD_EXECUTABLE指令为例： ADD_EXECUTABLE(hello main.c func.c)或者 ADD_EXECUTABLE(hello main.c;func.c)指令是大小写无关的,参数和变量是大小写相关的。推荐你全部使用大写指令。部分常用命令列表：PROJECTPROJECT(projectname [CXX] [C] [Java])指定工程名称,并可指定工程支持的语言。支持语言列表可忽略,默认支持所有语言SETSET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])定义变量(可以定义多个VALUE,如SET(SRC\_LIST main.c util.c reactor.c))MESSAGEMESSAGE([SEND\_ERROR | STATUS | FATAL\_ERROR] "message to display" ...)向终端输出用户定义的信息或变量的值SEND\_ERROR, 产生错误,生成过程被跳过STATUS, 输出前缀为--的信息FATAL\_ERROR, 立即终止所有cmake过程ADD\_EXECUTABLEADD\_EXECUTABLE(bin\_file\_name ${SRC\_LIST})生成可执行文件ADD\_LIBRARYADD\_LIBRARY(libname [SHARED | STATIC | MODULE] [EXCLUDE\_FROM\_ALL] SRC\_LIST)生成动态库或静态库SHARED 动态库STATIC 静态库MODULE 在使用dyld的系统有效,若不支持dyld,等同于SHAREDEXCLUDE\_FROM\_ALL 表示该库不会被默认构建SET\_TARGET\_PROPERTIES设置输出的名称,设置动态库的版本和API版本CMAKE\_MINIMUM\_REQUIREDCMAKE\_MINIMUM\_REQUIRED(VERSION version\_number [FATAL\_ERROR])声明CMake的版本要求ADD\_SUBDIRECTORYADD\_SUBDIRECTORY(src\_dir [binary\_dir] [EXCLUDE\_FROM\_ALL])向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制的存放位置EXCLUDE\_FROM\_ALL含义：将这个目录从编译过程中排除SUBDIRSdeprecated,不再推荐使用(hello sample)相当于分别写ADD\_SUBDIRECTORY(hello),ADD\_SUBDIRECTORY(sample)INCLUDE\_DIRECTORIESINCLUDE\_DIRECTORIES([AFTER | BEFORE] [SYSTEM] dir1 dir2 ... )向工程添加多个特定的头文件搜索路径,路径之间用空格分隔,如果路径包含空格,可以使用双引号将它括起来,默认的行为为追加到当前头文件搜索路径的后面。有如下两种方式可以控制搜索路径添加的位置：CMAKE\_INCLUDE\_DIRECTORIES\_BEFORE,通过SET这个cmake变量为on,可以将添加的头文件搜索路径放在已有路径的前面通过AFTER或BEFORE参数,也可以控制是追加还是置前LINK\_DIRECTORIESLINK\_DIRECTORIES(dir1 dir2 ...)添加非标准的共享库搜索路径TARGET\_LINK\_LIBRARIESTARGET\_LINK\_LIBRARIES(target lib1 lib2 ...)为target添加需要链接的共享库ADD\_DEFINITIONS想C/C++编译器添加-D定义ADD\_DEFINITIONS(-DENABLE\_DEBUG -DABC),参数之间用空格分隔ADD\_DEPENDENCIESADD\_DEPENDENCIES(target-name depend-target1 depend-target2 ...)定义target依赖的其他target,确保target在构建之前,其依赖的target已经构建完毕AUX\_SOURCE\_DIRECTORYAUX\_SOURCE\_DIRECTORY(dir VAR)发现一个目录下所有的源代码文件并将列表存储在一个变量中把当前目录下的所有源码文件名赋给变量DIR\_HELLO\_SRCSEXEC\_PROGRAMEXEC\_PROGRAM(Executable [dir where to run] ARGS <args> [RETURN\_VALUE <value>])用于在指定目录运行某个程序（默认为当前CMakeLists.txt所在目录）,通过ARGS添加参数,通过OUTPUT\_VARIABLE和RETURN\_VALUE获取输出和返回值,如下示例# 在src中运行ls命令,在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)INCLUDEINCLUDE(file [OPTIONAL]) 用来载入CMakeLists.txt文件INCLUDE(module [OPTIONAL])用来载入预定义的cmake模块OPTIONAL参数的左右是文件不存在也不会产生错误可以载入一个文件,也可以载入预定义模块（模块会在CMAKE\_MODULE\_PATH指定的路径进行搜索）载入的内容将在处理到INCLUDE语句时直接执行FIND\_FIND\_FILE(<VAR> name path1 path2 ...)VAR变量代表找到的文件全路径,包含文件名FIND\_LIBRARY(<VAR> name path1 path2 ...)VAR变量代表找到的库全路径,包含库文件名FIND_LIBRARY(libX X11 /usr/lib) IF (NOT libx) MESSAGE(FATAL_ERROR "libX not found") ENDIF(NOT libX)FIND\_PATH(<VAR> name path1 path2 ...)VAR变量代表包含这个文件的路径FIND\_PROGRAM(<VAR> name path1 path2 ...)VAR变量代表包含这个程序的全路径FIND\_PACKAGE(<name> [major.minor] [QUIET] [NO\_MODULE] [[REQUIRED | COMPONENTS] [componets ...]])用来调用预定义在CMAKE\_MODULE\_PATH下的Find<name>.cmake模块,你也可以自己定义Find<name>模块,通过SET(CMAKE\_MODULE\_PATH dir)将其放入工程的某个目录供工程使用IF语法：IF (expression) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... ELSE (expression) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... ENDIF (expression) # 一定要有ENDIF与IF对应IF (expression), expression不为：空,0,N,NO,OFF,FALSE,NOTFOUND或\_NOTFOUND,为真IF (not exp), 与上面相反IF (var1 AND var2)IF (var1 OR var2)IF (COMMAND cmd) 如果cmd确实是命令并可调用,为真IF (EXISTS dir) IF (EXISTS file) 如果目录或文件存在,为真IF (file1 IS\_NEWER\_THAN file2),当file1比file2新,或file1/file2中有一个不存在时为真,文件名需使用全路径IF (IS\_DIRECTORY dir) 当dir是目录时,为真IF (DEFINED var) 如果变量被定义,为真IF (var MATCHES regex) 此处var可以用var名,也可以用${var}IF (string MATCHES regex)当给定的变量或者字符串能够匹配正则表达式regex时为真。比如： 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)按照字母表顺序进行比较IF (variable STRLESS string)IF (string STRLESS string)IF (variable STRGREATER string)IF (string STRGREATER string)IF (variable STREQUAL string)IF (string STREQUAL string)一个小例子,用来判断平台差异： IF (WIN32) MESSAGE(STATUS “This is windows.”) ELSE (WIN32) MESSAGE(STATUS “This is not windows”) ENDIF (WIN32) 上述代码用来控制在不同的平台进行不同的控制,但是,阅读起来却并不是那么舒服,ELSE(WIN32)之类的语句很容易引起歧义。 可以SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) 这时候就可以写成: IF (WIN32) ELSE () ENDIF () 配合ELSEIF使用,可能的写法是这样: IF (WIN32) #do something related to WIN32 ELSEIF (UNIX) #do something related to UNIX ELSEIF(APPLE) #do something related to APPLE ENDIF (WIN32)WHILE语法：WHILE(condition) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... ENDWHILE(condition)其真假判断条件可以参考IF指令FOREACHFOREACH指令的使用方法有三种形式：列表语法：FOREACH(loop_var arg1 arg2 ...) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... ENDFOREACH(loop_var)示例：AUX_SOURCE_DIRECTORY(. SRC_LIST) FOREACH(F ${SRC_LIST}) MESSAGE(${F}) ENDFOREACH(F)范围FOREACH(loop\_var RANGE total) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ...ENDFOREACH(loop\_var)从0到total以１为步进 FOREACH(VAR RANGE 10) MESSAGE(${VAR}) ENDFOREACH(VAR) 输出： 0 1 2 3 4 5 6 7 8 9 10范围和步进语法：FOREACH(loop_var RANGE start stop [step]) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... ENDFOREACH(loop_var)从start开始到stop结束,以step为步进,注意：直到遇到ENDFOREACH指令,整个语句块才会得到真正的执行。FOREACH(A RANGE 5 15 3) MESSAGE(${A}) ENDFOREACH(A) 输出： 5 8 11 14cmake中如何生成动态库和静态库参考ADD\_LIBRARY和SET\_TARGET\_PROPERTIES用法t3示例cmake中如何使用动态库和静态库（查找库的路径）参考INCLUDE\_DIRECTORIES, LINK\_DIRECTORIES, TARGET\_LINK\_LIBRARIES用法t4示例使用动态库或静态库t5示例如何使用cmake预定义的cmake模块(以FindCURL.cmake为例演示)t6示例如何使用自定义的cmake模块(编写了自定义的FindHELLO.cmake)注意读t5和t6的CMakeLists.txt和FindHELLO.cmake中的注释部分cmake中如何指定生成文件的输出路径如上ADD\_SUBDIRECTORY的时候指定目标二进制文件输出路径（推荐使用下面这种）使用SET命令重新定义EXECUTABLE\_OUTPUT\_PATH和LIBRARY\_OUTPUT\_PATH变量来指定最终的二进制文件的位置SET(EXECUTABLE\_OUTPUT\_PATH ${PROJECT\_BINARY\_DIR}/bin) SET(LIBRARY\_OUTPUT\_PATH ${PROJECT\_BINARY\_DIR}/lib)上面的两条命令通常紧跟ADD\_EXECUTABLE和ADD\_LIBRARY,与其写在同一个CMakeLists.txt即可cmake中如何增加编译选项使用变量CMAKE\_C\_FLAGS添加C编译选项使用变量CMAKE\_CXX\_FLAGS添加C++编译选项使用ADD\_DEFINITION添加cmake中如何增加头文件路径参考INCLUDE\_DIRECTORIES命令用法cmake中如何在屏幕上打印信息参考MESSAGE用法cmake中如何给变量赋值参考SET和AUX\_SOURCE\_DIRECTORY用法建议：在Project根目录先建立build,然后在build文件夹内运行cmake ..，这样就不会污染源代码, 如果不想要这些自动生成的文件了，只要简单的删除build文件夹就可以cmake生成Xcode、vs项目生成Xcode项目：cmake -G "Xcode" .，.代表当前目录，即CMakeLists.txt所在的目录，建议最好新建Xcode文件夹，并在Xcode文件夹内执行cmake -G "Xcode" ../。如果报错找不到编译器，可以使用：.sudo xcode-select --switch /Applications/Xcode.app/，若要配置arm64，则需要如下配置：cmake -G "Xcode" -DCMAKE_OSX_ARCHITECTURES='arm64' ../CMakeLists.txt如果需要在vs中开发，则在cmd中执行如下指令，按自己对应路径进行修改cmake.exe -G "Visual Studio 17 2022" -A x64 -DCMAKE_PREFIX_PATH=C:/Qt/Qt5.12.5/5.12.5/msvc2017_64/lib/cmake -S C:/devWin/refactoring -B C:/devWin/refactoring/CMake中配置获取当前路径，并生成头文件在编译过程中直接包含，内含一个宏，在本项目中设置为CMakeLists.txt中所在路径见下：Cmake传参：适用于简单场景在Cmake中，很容易知道项目的地址，例如${PROJECT_SOURCE_DIR}可以在cmakelists中，将该值赋值给变量，例如MAIN_PATH：set(MAIN_PATH ${PROJECT_SOURCE_DIR})然后新建xxx.h.in文件，仅需一行即可利用宏捕获MAIN_PATH:#define PROJECT_PATH "@MAIN_PATH@"在cmakelists中将xxx.h.in编译成xxx.h：configure_file(src/param_deliver.h.in ../src/param_deliver.h)编译完成后即可生成对应的xxx.h：#define PROJECT_PATH "/home/type/mcamera/mcamera"然后调用该宏即可获得项目地址。