iGMAS Innovation Application Center
@School of Geodesy and Geomatics, Wuhan University
Menu
Home
Products
Visualization
Group
Software
Feedback
Sign In
Group
学术动态
团队风采
研究方向与代表成果
GNSS轨道钟差
实时精密定位
低轨增强GNSS
多源融合导航
GREATers
Tools and PPT
Group
学术动态
团队风采
研究方向与代表成果
GNSS轨道钟差
实时精密定位
低轨增强GNSS
多源融合导航
GREATers
Tools and PPT
GREATers
Return
CMake 软件下载、安装和指北
Create on
2020-07-27T17:25:57Z
written by Huang Jiande
# 背景 **CMake是个一个开源的跨平台自动化建构系统,用来管理软件建置的程序,并不相依于某特定编译器。** 并可支持多层目录、多个应用程序与多个库。 它用配置文件控制建构过程(build process)的方式和Unix的make相似,只是CMake的配置文件取名为CMakeLists.txt。 **CMake并不直接建构出最终的软件,而是产生标准的建构档(如Unix的Makefile或Windows Visual C++的projects/workspaces),然后再依一般的建构方式使用。** 这使得熟悉某个集成开发环境(IDE)的开发者可以用标准的方式建构他的软件,这种可以使用各平台的原生建构系统的能力是CMake和SCons等其他类似系统的区别之处。 **它首先允许开发者编写一种平台无关的CMakeList.txt 文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix的 Makefile 或 Windows 的 Visual Studio 工程。从而做到“Write once, run everywhere”。显然,CMake 是一个比上述几种 make 更高级的编译配置工具。** **“CMake”这个名字是"Cross platform MAke"的缩写。虽然名字中含有"make",但是CMake和Unix上常见的“make”系统是分开的,而且更为高端。 它可与原生建置环境结合使用,例如:make、苹果的Xcode与微软的Visual Studio。**  # 下载与安装 ## window 可以在Cmake的官方网站下载[CMake下载](https://cmake.org/)。无需额外操作,一直默认选项安装即可。 ## Linux/Unix 一般linux和Unix都是自带Cmake命令的,如果对cmake有版本要求,可自行在常用库安装更新。 # CMake使用 ## CMakeLists.txt cmake的所有语句都写在一个CMakeLists.txt的文件中,CMakeLists.txt文件确定后,直接使用cmake命令进行运行,但是这个命令要指向CMakeLists.txt所在的目录,cmake之后就会产生我们想要的makefile文件。 其基本操作流程为: ```sh ccmake directory cmake directory make ``` 其中directory为CMakeList.txt所在目录; - 第一条语句用于配置编译选项,如VTK_DIR目录 ,一般这一步不需要配置,直接执行第二条语句即可,但当出现错误时,这里就需要认为配置了,这一步才真正派上用场; - 第二条命令用于根据CMakeLists.txt生成Makefile文件; - 第三条命令用于执行Makefile文件,编译程序,生成可执行文件; ## CMakeLists常用语法 ### option-选项开关 使用场景 : 编译脚本传递参数 -> CMake脚本接收option -> 源代码宏 > **编译脚本传递参数** ```sh #!/bin/sh cmake -DTEST_DEBUG=ON . cmake --build . ``` > **cmake 脚本定义TEST_DEBUG 默认关闭OFF** ```cmake option(TEST_DEBUG "option for debug" OFF) if (TEST_DEBUG) add_definitions(-DTEST_DEBUG) endif() ``` > **效果** ```c++ #include "test.h" #ifdef TEST_DEBUG ... #endif ``` ### if else-逻辑判断 ```camke if() ... else() .. endif() ``` ### include_directories-头文件路径 ```cmake include_directories(${PATH}) # 可以用相对货绝对路径,也可以用自定义的变量值 include_directories(./include ${MY_INCLUDE}) ``` ### link_directories-链接路径 将PATH添加到索引路径,这样才可以找到对应路径的头文件。 ```cmake link_directories(${PATH}) ``` 将PATH添加到索引路径,这样才可以找到对应路径的库文件。 ### set-变量定义 ```cmake set( libA libAAAA ) ``` 将libAAA赋值给变量libA,之后可以用libA代替libAAAA ```cmake ${libA} ``` 其他例子: ```cmake # 设置可执行文件的输出路径(EXCUTABLE_OUTPUT_PATH是全局变量) set(EXECUTABLE_OUTPUT_PATH [output_path]) # 设置库文件的输出路径(LIBRARY_OUTPUT_PATH是全局变量) set(LIBRARY_OUTPUT_PATH [output_path]) # 设置C++编译参数(CMAKE_CXX_FLAGS是全局变量) set(CMAKE_CXX_FLAGS "-Wall std=c++11") # 设置源文件集合(SOURCE_FILES是本地变量即自定义变量) set(SOURCE_FILES main.cpp test.cpp ...) ``` ### find_path-GUI添加路径 ```cmake find_path(PATH HINTS "${PATH}" "$ENV{PATH} ") ``` 通过GUI给${PATH}变量赋值。 ### message-信息输出 ```cmake message(STATUS "================== Not Windows o(▼皿▼メ;)o ======================") ``` 作用不大,可以用来输出些信息,调试可能会用到。 ### 编译选项 #### 方法一 ```cmake add_compile_options(-w) ``` #### 方法二 ```cmake CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) ``` #### 方法三 ```cmake set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread") ``` ### 操作系统判断 ```cmake if(CMAKE_SYSTEM_NAME MATCHES "Linux") elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") elseif(CMAKE_SYSTEM_NAME MATCHES "Windows") endif() ``` ### 编译类型判断 ```cmake if(CMAKE_BUILD_TYPE MATCHES "Release") set(CMAKE_BUILD_POSTFIX "${CMAKE_RELEASE_POSTFIX}") elseif(CMAKE_BUILD_TYPE MATCHES "Debug") set(CMAKE_BUILD_POSTFIX "${CMAKE_DEBUG_POSTFIX}") elseif(CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo") set(CMAKE_BUILD_POSTFIX "${CMAKE_RELWITHDEBINFO_POSTFIX}") elseif(CMAKE_BUILD_TYPE MATCHES "MinSizeRel") set(CMAKE_BUILD_POSTFIX "${CMAKE_MINSIZEREL_POSTFIX}") else() set(CMAKE_BUILD_POSTFIX "") endif() ``` ### add_subdirectory-添加子CMakeList ```cmake add_subdirectory(${sub_A} ${ROOT}/build/${sub_A}) ``` 添加子CMakeList后,子CmakeList会和父Cmakelist共享所有全局变量。 ### set_property-设置给定域属性 ```cmake set_property(<GLOBAL | DIRECTORY [dir] | TARGET [target ...] | SOURCE [src1 ...] | TEST [test1 ...] | CACHE [entry1 ...]> [APPEND] PROPERTY <name> [value ...]) ``` 第一个参数决定了属性可以影响的作用域,必须为以下值: - GLOBAL 全局作作用域,不接受名字 - DIRECTORY 默认为当前路径,但是同样也可以用[dir]指定路径 - TARGET 目标作用,可以是0个或多个已有的目标 - SOURCE 源作用域, 可以是0个过多个源文件 - TEST 测试作用域, 可以是0个或多个已有的测试 - CACHE 必须指定0个或多个cache中已有的条目 `PROPERTY`参数是必须的 例如: ```cmake SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON) SET_PROPERTY(TARGET ${sub_A} PROPERTY FOLDER "sub") SET_PROPERTY(TARGET ${sub_B} PROPERTY FOLDER "sub") SET_PROPERTY(TARGET ${sub_C} PROPERTY FOLDER "sub") SET_PROPERTY(TARGET ${app_A} PROPERTY FOLDER "app") SET_PROPERTY(TARGET ${app_B} PROPERTY FOLDER "app") SET_PROPERTY(TARGET ${app_C} PROPERTY FOLDER "app") ``` ### CMake版本设置 ```cmake cmake_minimum_required(VERSION 3.0.0) ``` 要求3.0版本及以上 ### project-工程名 ```cmake PROJECT(helloworld) ///工程名为helloworld project(helloworld) ///工程名为helloworld ``` {% note warning %} CMake语法关键字不区分大小写。 {% endnote %} ### add_executable-添加要生成的可执行文件 使用SRC_LIST源文件列表里的文件生成一个可执行文件hello ```cmake add_executable(hello $(SRC_LIST}) ``` ### add_library-添加库 ```cmake add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 source2 ... sourceN) ``` 添加一个名为`<name>`的库文件 指定`STATIC, SHARED, MODULE`参数来指定要创建的库的类型, `STATIC`对应的静态库(.a),`SHARED`对应共享动态库(.so) `[EXCLUDE_FROM_ALL]`, 如果指定了这一属性,对应的一些属性会在目标被创建时被设置(**指明此目录和子目录中所有的目标,是否应当从默认构建中排除, 子目录的IDE工程文件/Makefile将从顶级IDE工程文件/Makefile中排除**) `source1 source2 ... sourceN`用来指定源文件 #### 例如:添加静态库 ```cmake add_library(hello STATIC ${SRC_LIST}) //// 使用SRC_LIST源文件列表里的文件生成一个静态链接libhello.a ``` #### 例如:添加动态库 ```cmake add_library(hello SHARD ${SRC_LIST}) //// 使用SRC_LIST源文件列表里的文件生成一个动态链接库libhello.so ``` #### 导入已有库 ```cmake add_library(<name> [STATIC | SHARED | MODULE | UNKNOWN] IMPORTED) ``` 导入了一个已存在的`<name>`库文件,导入库一般配合`set_target_properties`使用,这个命令用来指定导入库的路径,比如: ```cmake add_library(test SHARED IMPORTED) set_target_properties( test #指定目标库名称 PROPERTIES IMPORTED_LOCATION #指明要设置的参数 libs/src/${ANDROID_ABI}/libtest.so #设定导入库的路径) ``` ### target_link_libraries-链接库 将若干库链接到目标库文件 ```cmake target_link_libraries(<name> lib1 lib2 lib3) ``` arget_link_libraries里的库文件的顺序符合gcc/g++链接顺序的规则,即被依赖的库放在依赖它的库的后面,如果顺序有错,链接时会报错。 NOTE: 链接的顺序应当符合gcc链接顺序规则,被链接的库放在依赖它的库的后面,即如果上面的命令中,lib1依赖于lib2, lib2又依赖于lib3,则在上面命令中必须严格按照`lib1 lib2 lib3`的顺序排列,否则会报错 也可以自定义链接选项, 比如针对lib1使用`-WL`选项,`target_link_libraries(<name> lib1 -WL, lib2 lib3)` ### file-文件操作 文件操作命令 ```cmake # 将message写入filename文件中,会覆盖文件原有内容 file(WRITE filename "message") # 将message写入filename文件中,会追加在文件末尾 file(APPEND filename "message") ``` ```cmake # 从filename文件中读取内容并存储到var变量中,如果指定了numBytes和offset, # 则从offset处开始最多读numBytes个字节,另外如果指定了HEX参数,则内容会以十六进制形式存储在var变量中 file(READ filename var [LIMIT numBytes] [OFFSET offset] [HEX]) ``` ```cmake # 重命名文件 file(RENAME <oldname> <newname>) ``` ```cmake # 删除文件, 等于rm命令 file(REMOVE [file1 ...]) ``` ```cmake # 递归的执行删除文件命令, 等于rm -r file(REMOVE_RECURSE [file1 ...]) ``` ```cmake # 根据指定的url下载文件 # timeout超时时间; 下载的状态会保存到status中; 下载日志会被保存到log; sum指定所下载文件预期的MD5值,如果指定会自动进行比对,如果不一致,则返回一个错误; SHOW_PROGRESS,进度信息会以状态信息的形式被打印出来 file(DOWNLOAD url file [TIMEOUT timeout] [STATUS status] [LOG log] [EXPECTED_MD5 sum] [SHOW_PROGRESS]) ``` ```cmake # 创建目录 file(MAKE_DIRECTORY [dir1 dir2 ...]) ``` ```cmake # 会把path转换为以unix的/开头的cmake风格路径,保存在result中 file(TO_CMAKE_PATH path result) ``` ```cmake # 它会把cmake风格的路径转换为本地路径风格:windows下用"\",而unix下用"/" file(TO_NATIVE_PATH path result) ``` ```cmake # 将会为所有匹配查询表达式的文件生成一个文件list,并将该list存储进变量variable里, 如果一个表达式指定了RELATIVE, 返回的结果将会是相对于给定路径的相对路径, 查询表达式例子: *.cxx, *.vt? NOTE: 按照官方文档的说法,不建议使用file的GLOB指令来收集工程的源文件 file(GLOB variable [RELATIVE path] [globbing expressions]...) ``` ### set_directory_properties-设置路径属性 ```cmake set_directory_properties(PROPERTIES prop1 value1 prop2 value2) ``` `prop1 prop`代表属性,取值为: - INCLUDE_DIRECTORIES - LINK_DIRECTORIES - INCLUDE_REGULAR_EXPRESSION - ADDITIONAL_MAKE_CLEAN_FILES # 简单的例子 ```cmake cmake_minimum_required(VERSION 3.8) PROJECT (Tsinghua) INCLUDE_DIRECTORIES (${PROJECT_SOURCE_DIR}/eigen3) SET (SRC_LIST base.cpp ) ADD_LIBRARY (base_static STATIC ${SRC_LIST}) add_executable(hello main.cpp base.cpp base.h) ``` # 关键词索引 ## 一. CMake中常用预定义变量 ### 1. CMake的预定义变量 - PROJECT_SOURCE_DIR:工程根目录; - PROJECT_BINARY_DIR:运行cmake命令的目录。笔者建议定义为${PROJECT_SOURCE_DIR}/build下。具体原因见后文外部编译部分; - CMAKE_INCLUDE_PATH:环境变量,非cmake变量; - CMAKE_LIBRARY_PATH:环境变量; - CMAKE_CURRENT_SOURCE_DIR:当前处理的CMakeLists.txt文件所在路径; - CMAKE_CURRENT_BINARY_DIR:target编译目录; - 使用ADD_SURDIRECTORY指令可以更改该变量的值; - SET(EXECUTABLE_OUTPUT_PATH < dir >) 指令不会对该变量有影响,但改变了最终目标文件的存储路径; - CMAKE_CURRENT_LIST_FILE:输出调用该变量的CMakeLists.txt的完整路径; - CMAKE_CURRENT_LIST_LINE:输出该变量所在的行; - CMAKE_MODULE_PATH:定义自己的cmake模块所在路径; - EXECUTABLE_OUTPUT_PATH:重新定义目标二进制可执行文件的存放位置; - LIBRARY_OUTPUT_PATH:重新定义目标链接库文件的存放位置; - PROJECT_NAME:返回由PROJECT指令定义的项目名称; - CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS:用来控制IF…ELSE…语句的书写方式; ### 2. 系统信息预定义变量 - CMAKE_MAJOR_VERSION cmake主版本号,如2.8.6中的2 - CMAKE_MINOR_VERSION cmake次版本号,如2.8.6中的8 - CMAKE_PATCH_VERSION cmake补丁等级,如2.8.6中的6 - CMAKE_SYSTEM 系统名称,例如Linux-2.6.22 - CMAKE_SYSTEM_NAME 不包含版本的系统名,如Linux - CMAKE_SYSTEM_VERSION 系统版本,如2.6.22 - CMAKE_SYSTEM_PROCESSOR 处理器名称,如i686 - UNIX 在所有的类UNIX平台为TRUE,包括OS X和cygwin - WIN32 在所有的win32平台为TRUE,包括cygwin ### 3. 开关选项 - BUILD_SHARED_LIBS 控制默认的库编译方式。 - 注:如果未进行设置,使用ADD_LIBRARY时又没有指定库类型,默认编译生成的库都是静态库。 - CMAKE_C_FLAGS 设置C编译选项 - CMAKE_CXX_FLAGS 设置C++编译选项 # 参考文献 更详细的说明请参考 -[github说明](https://gearyyoung.gitbooks.io/cmake-api/content/cmake/CMake%E7%94%9F%E6%88%90%E5%99%A8.html) -[官方文档](https://cmake.org/documentation/)