CMake教程总结

本文深入介绍了CMake的基本语法和常用指令,包括PROJECT、SET、MESSAGE、ADD_SUBDIRECTORY等,详细阐述了如何管理项目源文件、设置输出路径、处理库和可执行文件,以及安装步骤。此外,还讲解了CMake变量、系统信息和条件判断等内容,为C++项目的跨平台构建提供了清晰的指导。
摘要由CSDN通过智能技术生成

CMake教程

语法

1.PROJECT

PROJECT(projectname [CXX] [C] [Java])

  • 默认情况表示支持所有语言。
  • 预定义了PROJECT_BINARY_DIR,PROJECT_SOURCE_DIR

2.SET 指令

SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])

3.MESSAGE 指令

MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display"...)

  • SEND_ERROR,产生错误,生成过程被跳过。
  • STATUS,输出前缀为—的信息。
  • FATAL_ERROR,立即终止所有 cmake 过程

4. 变量

  • 1.变量使用${}方式取值,但是在 IF 控制语句中是直接使用变量名
  • 2.指令(参数 1 参数 2…)
  • 3.参数使用括弧括起,参数之间使用空格或分号分开。
  • 4.指令是大小写无关的,参数和变量是大小写相关的。推荐你全部使用大写指令

5.语法的疑惑

  • 1.SET(SRC_LIST main.c)也可以写成 SET(SRC_LIST “main.c”)
  • 2.假设一个源文件的文件名是 fu nc.c(文件名中间包含了空格)。这时候就必须使用双引号

6.清理工程

make clean

  • 既可对现有构建的工程清理
  • 但是cmake 不支持make disclean

7.内部构建与外部构建

  • 通过建立新的build文件进行cmake ..来实现构建称为外部构建,不会对源码有任何影响
  • 内部构建已经就是直接cmake .

8.ADD_SUBDIRECTORY 指令

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

  • 这个指令用于向当前工程添加存放源文件的子目录
  • 可以指定中间二进制和目标二进制存放的位置
  • EXCLUDE_FROM_ALL 参数的含义是将这个目录从编译过程中排除

9.SUBDIRS 指令

  • 这个指令已经不推荐使用

  • 子目录体系仍然会被保存

10.换个地方保存目标二进制

  • SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

  • SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

  • 可执行二进制的输出路径为 build/bin 和库的输出路径为 build/lib

11.make install

  • make install用于安装make好的文件

  • configure配置文件时,用./configure -prefix=/usr或者./configure - -prefix=/usr来确定安装的位置。

  • 而CMake中,我们采用CMAKE_INSTALL_PREFIX来指定文件的安装位置

  • INSTALL(TARGETS targets...
           [[ARCHIVE|LIBRARY|RUNTIME]
           [DESTINATION <dir>]
           [PERMISSIONS permissions...]
             [CONFIGURATIONS
             [Debug|Release|...]]
           [COMPONENT <component>]
           [OPTIONAL]
           ] [...])
    
  • TARGETS – 目标文件: 可执行二进制、动态库、静态库

  • ARCHIVE 特指静态库,LIBRARY 特指动态库,RUNTIME特指可执行目标二进制

  • DESTINATION 定义了安装的路径

  • INSTALL(TARGETS myrun mylib mystaticlib
    	  RUNTIME DESTINATION bin
    		  LIBRARY DESTINATION lib
          ARCHIVE DESTINATION libstatic
     )
    
  • 可执行二进制 myrun 安装到${CMAKE_INSTALL_PREFIX}/bin 目录

  • 动态库 libmylib 安装到${CMAKE_INSTALL_PREFIX}/lib 目录

  • 静态库 libmystaticlib 安装到${CMAKE_INSTALL_PREFIX}/libstatic 目录

  • 你不需要关心 TARGETS 具体生成的路径,只需要写上 TARGETS 名称就可以了

12.普通文件的安装

   INSTALL(FILES files... DESTINATION <dir>
          [PERMISSIONS permissions...]
          [CONFIGURATIONS [Debug|Release|...]]
          [COMPONENT <component>]
          [RENAME <name>] [OPTIONAL])
  • 可用于安装一般文件,并可以指定访问权限,文件名是此指令所在路径下的相对路径
  • OWNER_WRITE, OWNER_READ, GROUP_READ,和 WORLD_READ,即 644 权限

13.非目标文件的安装

INSTALL(PROGRAMS files... DESTINATION <dir>
            [PERMISSIONS permissions...]
            [CONFIGURATIONS [Debug|Release|...]]
            [COMPONENT <component>]
            [RENAME <name>] [OPTIONAL])
  • 跟上面的 FILES 指令使用方法一样,唯一的不同是安装后权限为:
    OWNER_EXECUTE, GROUP_EXECUTE, 和 WORLD_EXECUTE,即 755 权限

14.目录的安装

    INSTALL(DIRECTORY dirs... DESTINATION <dir>
            [FILE_PERMISSIONS permissions...]
            [DIRECTORY_PERMISSIONS permissions...]
            [USE_SOURCE_PERMISSIONS]
            [CONFIGURATIONS [Debug|Release|...]]
            [COMPONENT <component>]
            [[PATTERN <pattern> | REGEX <regex>]
            [EXCLUDE] [PERMISSIONS permissions...]] [...])

DIRECTORY后面连接的是所在 Source 目录的相对路径,但务必注意abc 和 abc/有很大的区别。

  • 如果目录名不以/结尾,那么这个目录将被安装为目标路径下的 abc

  • 如果目录名以/结尾,代表将这个目录中的内容安装到目标路径,但不包括这个目录本身。

  • PATTERN 用于使用正则表达式进行过滤,PERMISSIONS 用于指定 PATTERN 过滤后的文件权限。

  • 例子

    INSTALL(DIRECTORY icons scripts/ DESTINATION share/myproj
            PATTERN "CVS" EXCLUDE
            PATTERN "scripts/*"
            PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
            GROUP_EXECUTE GROUP_READ)
    

    这条指令的执行结果是:
    将 icons 目录安装到 /share/myproj,将 scripts/中的内容安装到/share/myproj
    不包含目录名为 CVS 的目录,对于 scripts/*文件指定权限为 OWNER_EXECUTE
    OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ

15.ADD_LIBRARY指令

ADD_LIBRARY(libname [SHARED|STATIC|MODULE]
[EXCLUDE_FROM_ALL]
source1 source2 … sourceN)

  • SHARED,动态库

  • STATIC,静态库

  • MODULE,在使用 dyld 的系统有效,如果不支持 dyld,则被当作 SHARED 对待

  • EXCLUDE_FROM_ALL 参数的意思是这个库不会被默认构建,除非有其他的组件依赖或者手工构建。

  • 这个指令只能生成名字相同的一个静态或动态库,而不能同时生成

16.SET_TARGET_PROPERTIES 和GET_TARGET_PROPERTY指令

  SET_TARGET_PROPERTIES(target1 target2 ...
                        PROPERTIES prop1 value1
                        prop2 value2 ...)
  • 这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和 API 版本

  • 与他对应的指令是:

    GET_TARGET_PROPERTY(VAR target property)
    
  • 具体用法如下例,我们向 lib/CMakeListst.txt 中添加:

    GET_TARGET_PROPERTY(OUTPUT_VALUE hello_static OUTPUT_NAME)
    

    MESSAGE(STATUS “This is the hello_static OUTPUT_NAME:”${OUTPUT_VALUE})

如果没有这个属性定义,则返回 NOTFOUND

  • 动态库版本号

    SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
    
  • VERSION 指代动态库版本,SOVERSION 指代 API 版本。

17.安装共享库

    INSTALL(TARGETS hello hello_static
            LIBRARY DESTINATION lib
            ARCHIVE DESTINATION lib)
            
    INSTALL(FILES hello.h DESTINATION include/hello)
  • 静态库要使用 ARCHIVE 关键字

18.使用外部共享库和头文件

INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)
  • 这条指令可以用来向工程添加多个特定的头文件搜索路径
  • CMAKE_INCLUDE_DIRECTORIES_BEFORE,通过 SET 这个 cmake 变量为 on,可以将添加的头文件搜索路径放在已有路径的前面
  • 通过 AFTER 或者 BEFORE 参数,也可以控制是追加还是置前

LINK_DIRECTORIES 和 TARGET_LINK_LIBRARIES指令

 LINK_DIRECTORIES (directory1 directory2 ...)
  • 这个指令非常简单,添加非标准的共享库搜索路径

    TARGET_LINK_LIBRARIES(target library1
                          <debug | optimized> library2
                          ...)
    
  • 这个指令可以用来为 target 添加需要链接的共享库

    TARGET_LINK_LIBRARIES (main hello) 或者 TARGET_LINK_LIBRARIES(main libhello.so)

  • 如何链接到静态库

    TARGET_LINK_LIBRARIES(main libhello.a)
    

19.CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH

  • 务必注意,这两个是环境变量而不是 cmake 变量
  • 使用方法是要在 bash 中用 export 或者在 csh 中使用 set 命令设置或者CMAKE_INCLUDE_PATH=/home/include cmake …等方式。
  • 通过 INCLUDE_DIRECTORIES 指令加入非标准的头文件搜索路径
  • 通过 LINK_DIRECTORIES 指令加入非标准的库文件搜索路径
  • 通过 TARGET_LINK_LIBRARIES 为库或可执行二进制加入库链接

20.Cmake变量

  • cmake变量的取值:${}表示取值,但是在IF()中直接用变量名

  • 显示定义:set HELLO_SRC main.c)

  • 这样就定义了HELLO_SRC这个变量

  • 隐式定义: 例如PROJECT()就会定义 _BINARY_DIR 和_SOURCE_DIR

  • 常用变量

    CMAKE_BINARY_DIR
    
    PROJECT_BINARY_DIR
      
    <projectname>_BINARY_DIR
    
    • 这三个变量指代的内容是一致的
    • 如果是 in source 编译,指得就是工程顶层目录
    • 如果是 out-of-source 编译,指的是工程编译发生的目录
    • PROJECT_BINARY_DIR 跟其他指令稍有区别,现在,你可以理解为他们是一致的
  • CMAKE_SOURCE_DIR

    PROJECT_SOURCE_DIR
    
    <projectname>_SOURCE_DIR
    
    • 这三个变量指代的内容是一致的,不论采用何种编译方式,都是工程顶层目录
    • 也就是在 in source 编译时,他跟 CMAKE_BINARY_DIR 等变量一致。
    • PROJECT_SOURCE_DIR 跟其他指令稍有区别,现在,你可以理解为他们是一致的
  • CMAKE_CURRENT_SOURCE_DIR

    • 指的是当前处理的 CMakeLists.txt 所在的路径,比如上面我们提到的 src 子目录
  • CMAKE_CURRRENT_BINARY_DIR

    • 如果是 in-source 编译,它跟 CMAKE_CURRENT_SOURCE_DIR 一致
    • 如果是 out-ofsource 编译,他指的是 target 编译目录。
    • 使用我们上面提到的 ADD_SUBDIRECTORY(src bin)可以更改这个变量的值
    • 使用 SET(EXECUTABLE_OUTPUT_PATH <新路径>)并不会对这个变量造成影响,它仅仅修改了最终目标文件存放的路径
  • CMAKE_CURRENT_LIST_FILE
    - 输出调用这个变量的 CMakeLists.txt 的完整路径
    
  • CMAKE_CURRENT_LIST_LINE

    • 输出这个变量所在的行
  • CMAKE_MODULE_PATH

    • 这个变量用来定义自己的 cmake 模块所在的路径

    • 你需要通过 SET 指令,将自己的 cmake 模块路径设
      置一下,比如

  • SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)

  • EXECUTABLE_OUTPUT_PATH 和 LIBRARY_OUTPUT_PATH
    - 分别用来重新定义最终结果的存放目录,前面我们已经提到了这两个变量
    
  • PROJECT_NAME
    - 返回通过 PROJECT 指令定义的项目名称。
    

20.cmake调用系统变量

使用 $ENV{NAME}指令就可以调用系统的环境变量了。比如

    MESSAGE(STATUS “HOME dir: $ENV{HOME}”)

设置系统变量的值

   SET(ENV{变量名} 值)

1.CMAKE_INCLUDE_CURRENT_DIR

自动添加 CMAKE_CURRENT_BINARY_DIR 和CMAKE_CURRENT_SOURCE_DIR 到当前处理的 CMakeLists.txt。

2.CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE

将工程提供的头文件目录始终至于系统头文件目录的前面,当你定义的头文件确实跟系统发生冲突时可以提供一些帮助。

3.CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH

我们在上一节已经提及。

21.系统信息

1.CMAKE_MAJOR_VERSION,CMAKE 主版本号,比如 2.4.6 中的 2
2.CMAKE_MINOR_VERSION,CMAKE 次版本号,比如 2.4.6 中的 4
3.CMAKE_PATCH_VERSION,CMAKE 补丁等级,比如 2.4.6 中的 6
4.CMAKE_SYSTEM,系统名称,比如 Linux-2.6.22
5.CMAKE_SYSTEM_NAME,不包含版本的系统名,比如 Linux
6.CMAKE_SYSTEM_VERSION,系统版本,比如 2.6.22
7.CMAKE_SYSTEM_PROCESSOR,处理器名称,比如 i686.
8.UNIX,在所有的类 UNIX 平台为 TRUE,包括 OS X 和 cygwin
9.WIN32,在所有的 win32 平台为 TRUE,包括 cygwin

22.主要的开关选项

1.CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS,用来控制 IF ELSE 语句的书写方式,在下一节语法部分会讲到。
2.BUILD_SHARED_LIBS
这个开关用来控制默认的库编译方式,如果不进行设置,使用 ADD_LIBRARY 并没有指定库类型的情况下,默认编译生成的库都是静态库。如果 SET(BUILD_SHARED_LIBS ON)后,默认生成的为动态库。
3.CMAKE_C_FLAGS
设置 C 编译选项,也可以通过指令 ADD_DEFINITIONS()添加。
4.CMAKE_CXX_FLAGS
设置 C++编译选项,也可以通过指令 ADD_DEFINITIONS()添加。

23.cmake常用指令

1)ADD_DEFINITIONS

  • 向 C/C++编译器添加-D 定义
  • ADD_DEFINITIONS(-DENABLE_DEBUG -DABC),参数之间用空格分割
  • 如果你的代码中定义了#ifdef ENABLE_DEBUG #endif,这个代码块就会生效
  • 如果要添加其他的编译器开关,可以通过 CMAKE_C_FLAGS 变量CMAKE_CXX_FLAGS 变量设置

2)ADD_DEPENDENCIES

  • 定义 target 依赖的其他 target,确保在编译本 target 之前,其他的 target 已经被构建。

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

3)ADD_EXECUTABLE、ADD_LIBRARY、ADD_SUBDIRECTORY

前面已经介绍过了,这里不再罗唆。

4)ADD_TEST 与 ENABLE_TESTING 指令。

ENABLE_TESTING指令用来控制 Makefile 是否构建 test 目标,涉及工程所有目录。语法很简单,没有任何参数,ENABLE_TESTING(),一般情况这个指令放在工程的主CMakeLists.txt 中

  ADD_TEST(testname Exename arg1 arg2 ...)

testname是自定义的 test 名称,Exename可以是构建的目标文件也可以是外部脚本等等。后面连接传递给可执行文件的参数。如果没有在同一个 CMakeLists.txt 中打开ENABLE_TESTING()指令,任何 ADD_TEST 都是无效的。

5)AUX_SOURCE_DIRECTORY

   AUX_SOURCE_DIRECTORY(dir VARIABLE)

作用是发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表。因为目前 cmake 还不能自动发现新添加的源文件。

6)CMAKE_MINIMUM_REQUIRED

   CMAKE_MINIMUM_REQUIRED(VERSION versionNumber [FATAL_ERROR])

7)EXEC_PROGRAM

在 CMakeLists.txt 处理过程中执行命令,并不会在生成的 Makefile 中执行

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

用于在指定的目录运行某个程序,通过 ARGS 添加参数,如果要获取输出和返回值,可通过OUTPUT_VARIABLE 和 RETURN_VALUE 分别定义两个变量.

8)FILE 指令

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)

这里的语法都比较简单,不在展开介绍了

9)INCLUDE 指令

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

OPTIONAL 参数的作用是文件不存在也不会产生错误。

10)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...]])

用来调用预定义在 CMAKE_MODULE_PATH 下的 Find.cmake 模块,你也可以自己定义 Find模块,通过 SET(CMAKE_MODULE_PATH dir)将其放入工程的某个目录中供工程使用,我们在后面的章节会详细介绍 FIND_PACKAGE 的使用方法和 Find 模块的编写。

11)IF 指令

IF(expression)
	COMMAND1(ARGS ...)
	COMMAND2(ARGS ...)
	...
ELSE(expression)
	COMMAND1(ARGS ...)
	COMMAND2(ARGS ...)
	...
ENDIF(expression)

另外一个指令是 ELSEIF,总体把握一个原则,凡是出现 IF 的地方一定要有对应的
ENDIF.出现 ELSEIF 的地方,ENDIF 是可选的。

SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)
IF(WIN32)

ELSE()

ENDIF()

12)WHILE

WHILE 指令的语法是:

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

其真假判断条件可以参考 IF 指令。
13)FOREACH

(1)FOREACH(loop_var arg1 arg2 ...) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... ENDFOREACH(loop_var)
像我们前面使用的 AUX_SOURCE_DIRECTORY 的例子

(2)FOREACH(loop_var RANGE total) ENDFOREACH(loop_var)
(3)FOREACH(loop_var RANGE start stop [step]) ENDFOREACH(loop_var)

24.FIND<package>.cmake

1).对于系统预定义的 Find.cmake 模块,使用方法一般如上例所示:
每一个模块都会定义以下几个变量
<name>_FOUND
<name>_INCLUDE_DIR or _INCLUDES
<name>_LIBRARY or _LIBRARIES

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值