linux--CMake

简介

CMake is an open-source, cross-platform family of tools designed to build, test and package software. CMake is used to control the software compilation process using simple platform and compiler independent configuration files, and generate native makefiles and workspaces that can be used in the compiler environment of your choice. The suite of CMake tools were created by Kitware in response to the need for a powerful, cross-platform build environment for open-source projects such as ITK and VTK.

CMake is part of Kitware’s collection of commercially supported open-source platforms for software development.

特点

  1. 在每个源码目录下都有一个 CMakeLists.txt.
  2. CMake 语句不区分大小写。一句一行,无行结束符号,注释用#
  3. CMake 实际也是一种编程语言。CMake 根据 CMakeLists.txt 自动生成 Makefile.。
  4. CMake 比 Autotools 更简单明了。
  5. 开放源代码。
  6. 跨平台,并可生成native编译配置文件,在Linux/Unix 平台,生成 makefile,在苹果平台,可以生成xcode,在 Windows 平台,可以生成 MSVC 的工程文件。
  7. 能够管理大型项目。
  8. 可扩展,可以为cmake编写特定功能的模块,扩充cmake 功能。
  9. 注:如果你的工程只有几个文件,直接编写Makefile 是最好的选择。

语法

1、变量使用${}方式取值,但是在 IF 语句中是直接使用变量名取值

MESSAGE(STATUS “This is bin dir” $(PROJECT_BINARY_DIR))
MESSAGE(STATUS “This is bin dir $(PROJECT_BINARY_DIR)”)
上面两句等效。

2、指令(参数 1 参数 2 …),参数之间用空格或分号隔开

SET( SRC_LIST main.cpp hello.cpp)
SET(SRC_LIST “main.cpp” “hello.cpp”)
SET(SRC_LIST “main.cpp”;“hello.cpp”)

3、内部构建和外部构建:在哪个目录下执行 cmake 命令,则在哪个目录构建

In-source:编译过程文件和源码文件在同一目录下面(在工程目录下 cmake)
Out-of-sourc:将编译目录和源码目录分割开(在非工程目录下 cmake)。

4、常用变量及指令

(1)CMake变量

序号语句注释
1PROJECT_BINARY_DIR 、PROJECT_SOURCE_DIR、CMAKE_BINARY_DIR 、CMAKE_SOURCE_DIR工程目标文件目录、工程源文件目录
2CMAKE_CURRENT_BINARY_DIR、CMAKE_CURRENT_SOURCE_DIR指当前处理的 CMakeLists.txt 所在的路径
3CMAKE_CURRENT_LIST_FILE CMAKE_CURRENT_LIST_LINE输出调用这个变量的 CMakeLists.txt
4< project name>_BINARY_DIR
< project name>_SOURCE_DIR
project name 工程目标文件
project name 源目标文件
5EXECUTABLE_OUTPUT_PATH最终目标二进制文件存放目录
6LIBRARY_OUT_PATH最终目标库文件存放目录
7CMAKE_INSTALL_PREFIX目标文件安装目录 ,默认目录为/usr/local/bin
8CMAKE_MODULE_PATH定义自己的 CMake模块所在的路径
9PROJECT_NAME返回通过 PROJECT 指令定义的值
10CMAKE_INCLUDE_CURRENT_DIR 自动添加
CMAKE_CURRENT_BINARY_DIR
和CMAKE_CURRENT_SOURCE_DIR
到当前 CMakeLists.txt 处理。
11CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFO RE将工程提供的头文件目录
始终至于系统头文件目录前面
12CMAKE_MAJOR_VERSION
CMAKE_MINOR_VERSION
CMAKE_PATCH_VERSION
CMake 主版本号,2.4.6 中的 2
CMake 次版本号,2.4.6 中的 4
CMake 的补丁等级,2.4.6 中的 6
13CMAKE_SYSTEM
CMAKE_SYSTEM_NAME
CMAKE_SYSTEM_VERSION
CMAKE_SYSTEM_PROCESSOR
系统名称,如 Linux-2.6.26
Linux
2.6.26
I386
14UNIX

WIN32
在所有的类 UNIX 平台值为 TRUE,
包括 MacOS 和 和 Cygwin
在所有的 WIN32 平台值为 TRUE,
包括 Cygwin
15CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS开关选项,用来控制 if else 的书写方式
16BUILD_SHARED_LIBS开关,默认为静态库
17CMAKE_C_FLAGS
CMAKE_CXX_FLAGS
设置 C 编译选项
设置 C++ 编译选项

(2)CMake 指令([] 表示可选参数)

序号语句注释
1PROJECT(project name[CXX][C][Java]) 定义工程名称( 工程名与生成的
目标文件名称是没有任何关系的) 。
此条指令隐含了两个变量
< project name>_BINARY_DIR
< project name>_SOURCE_DIR
2SET(var [value] [cache type docstring[force]])自定义变量指令
set( SRC_LIST main.cpp hello.cpp)
set(SRC_LIST “main.cpp” “test.cpp”)
3MASSEGE([SEND_ERROR|STATUS|FATAL_ERROR] “massage to display” …)SEND_ERROR: 产生错误,生成过程被跳过 STATUS: 输出前缀为--- 的信息
FATAL_ERROR: 立即终止所有 CMake 过程
4ADD_EXECUTABLE(target source_file…) 增加可执行目标文件,
target 由 source_file生成
5ADD_SUBDIRECTORY(source_dir [binary_dir]
[EXCLUDE FROM ALL])
增加子目录
6SUBDIRS(dir1 dir2 …) 一次添加多个目录, 即使外部编译,
子目录体系仍然会被保存
7INSTALL(TARGETS targets [
[ARCHIVE|LIBRARY|RUNTIME]
[DESTINATION< dir>]
[PERMISSIONS permissions…]
[CONFIGGURATIONS [Debug|Release|…]]
[COMPONENT ]
[OPTIONAL]][…])
安装目标文件
ARCHIVE 静态库文件
LIBRARY 动态库文件
RUNTIME 可执行文件
DESTINATION 定义安装路径,
如果是绝对路径则覆盖了
CMAKE_INSTALL_PREFIX, 否则是指
相对 CMAKE_INSTALL_PREFIX 的相对路径
8INSTALL(FILES files [
[DESTINATION < dir>]
[PERMISSIONS permissions…]
[CONFIGGURATIONS [Debug|Release|…]]
[COMPONENT ]
[OPTIONAL]
][…])
安装普通文件
可以指定权限,如果不指定,
则默认是 644
9INSTALL(DIRECTORY dirs [
[DESTINATION < dir>]
[FILE_PERMISSIONS permissions…]
[DIRECTORY_PERMISSIONS permissions…]
[USE_SOURCE_PERMISSIONS permissions…]
[CONFIGGURATIONS [Debug|Release|…]]
[COMPONENT ]
[[PATTERN | REGEX ]
[EXCLUDE] [PERMISSIONS permissions…]]
[…])
安装目录
可以指定权限,如果不指定,
则默 认是 644
10ADD_LIBRARY(libname [SHARED|STATIC|MODULE]
[EXCLUDE_FROM_ALL] source1source2 … sourceN)
MODULE: 在使用 dydl 的系统有效,
如果支持 dydl, 则默认为 SHARED
11SET_TARGET_PROPERTIES(target1 target2 …
PROPERTIES prop1 value prop2 value2 …)
设置目标输出的名字 及属性
由于 TARGET 名字不能有重复,
所以需在生成库文件再改为需要的名 字,
这时就要用到这个指令了。
相关变量:
OUTPUT_NAME, 输出名字( 库,可执行文件名字,可以不用加后缀)
OUTPUT_VALUE
CLEAN_DIRECT_OUTPUT
VERSION
SOVERSION
12GET_TARGET_PROPERTIES(VAR target property) 获取目标的属性
13$ENV{NAME} 调用系统环境变量
14SET(ENV{ 变量名} 值) 设置环境变量值
15ADD_DEFINITIONS
例:ADD_DEFINITIONS(-DENABLE_DEBUG)
向编译器添加-D定义
16ADD_DEPENDENCIES(target_name
depend_target1 depend_target)
定义 target 依赖的其他 target
17ADD_TEST(testname program arg1 arg2) 在打开了 ENABEL_TESTING 后有效
18ENABEL_TESTING 不带任何参数,
控制 Makefile 是否构建 test 目标,
一般用在工程主CMakeList.txt
19AUX_SOURCE_DIRECTORY(dir VARIABLE)
例 AUX_SOURCE_DIRECTORY(. SRC_LIST),
将当前目录下源文件名赋给变量 SRC_LIST
自动构建源文件列表
20CMAKE_MINIMUM_REQUIRED(VERSION
version_num [FATAL_ERROR])
检查 CMake 版本,若不满足,
产生错误提示或退出
21EXEC_PROGRAM(program
[ARGS args]
[OUTPUT_VARIABLE var]
[RETURN_VALUE value])
ARGS 用于添加参数
OUTPUT_VARIABLE 用于获取命令输出
RETURN_VALUE 用于获取返回值
22FILE 指令
FILE(WRITE filename “message” …)
FILE(APPEND filename “message” …)
FILE(READ filename variable)
FILE(GLOB variable [RELATIVE path]
[globing expressions]…)
FILE(GLOB_RECURSE variable [RELATIVE path]
[globing 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)
写文件
添加内容到文件
读文件





移除目录
递归移除目录
创建目录
23INCLUDE(file [OPTIONAL])
INCLUDE(module [OPTIONAL])
用来载入 CMakeLists.txt 文件
或者CMake
24FIND 指令
FIND_FILE(< VAR>name1 path1 path2 …)
FIND_LIBRARY(< VAR>name1 path1 path2 …)
FIND_PATH(< VAR>name1 path1 path2 …)
FIND_PROGRAM(< VAR>name1 path1 path2 …)
FIND_PACKAGE(< name> [major.minor] [QUITE]
[NO_MODULE]
[[REQUIRED|COMPONENTS] [components…]])
VAR 变量
name1 代表找到的文件全路径,
包含文件名VAR 变量
name2 代表找到的文件全路径,
包含库文件名
VAR 变量代表包含这个文件的路径
VAR 变量代表包含这个程序的全路径

5、判断语句

IF指令,基本语法为:
IF(expression)
#THEN section
COMMAND1(ARGS …)
COMMAND2(ARGS …)

ELSE(expression)
#ELSE section
COMMAND1(ARGS …)
COMMAND2(ARGS …)

ENDIF(expression)
另外一个指令是ELSEIF,总体把握一个原则,凡是出现IF的地方一定要有对应的ENDIF。出现ELSEIF的地方,ENDIF是可选的。
表达式的使用方法如下:
IF(var),如果变量不是:空,0,N,NO,OFF,FALSE,NOTFOUND或
< var>_NOTFOUND时,表达式为真。
IF(NOT var),与上述条件相反。
IF(var1 AND var2),当两个变量都为真时为真。
IF(var1 OR var2),当两个变量其中一个为真时为真。
IF(COMMAND cmd),当给定的cmd确实时命令并可以调用时为真。
IF(EXISTS dir)或者IF(EXISTS file),当目录名或者文件名存在时为真。
IF(file1 IS_VEWER_THAN file2),当file1比file2新,或者file1/file2其中有一个不存在时为真,文件名请使用完整路径。
IF(IS_DIRECTORY dirname),当dirname是目录时,为真。
IF(variable MATCHES regex)
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 number)
IF(string STRLESS number)
IF(variable STRGREATER number)
IF(string STRGREATER number)
IF(variable STREQUAL number)
IF(string STREQUAL number)
按照字母序的排列进行比较
IF(DEFINED variable),如果变量被定义,为真
一个小例子,用来判断平台差异:
IF(WIN32)
MESSAGE(STATUS “This is windows”)
#做一些Windows相关的操作
ELSE(WIN32)
MESSAGE(STATUS “This is windows”)
#做一些非Windows相关的操作
ENDIF(WIN32)
上述代码用来控制在不同的平台进行不同的控制,但是,阅读起来却并不是那么舒服
ENDIF(WIN32)之类的语句很容易引起歧义。
这就用到了我们在“常用变量”一节提到的CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS开关。
可以SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)
这时候就可以写成:
IF(WIN32)
WLSE()
ENDIF()

如果配合ELSEIF使用,可能的写法是这样:
IF(WIN32)
#do something related to WIN32
ELSEIF(UNIX)
#do something related to UNIX
ELSEIF(APPLE)
#do something related to APPLE
ELSEIF(WIN32)

6、循环语句

(1)WHILE
WHILE指令的语法是:
WHILE(condition)
COMMAND1(ARGS …)
COMMAND2(ARGS …)

ENDWHILE(condition)
其真假判断条件可以参考IF指令。
(2)FOREACH
FOREACH指令的使用方法有三种形式:
<1>列表
FOREACH(loop_var_ arg1 arg2 …)
COMMAND1(ARGS …)
COMMAND2(ARGS …)

ENDFOREACH(loop_var)
像我们前面使用的AUX_SOURCE_DIRECTORY的例子
AUX_SOURCE_DIRECTORY( SRC_LIST)
FOREACH(F SRCLIST)MESSAGE({SRC_LIST}) MESSAGE({F})
ENDFOREACH(F)
<2>范围
FOREACH(loop_var RANGE total)
ENDFOREACH(loop_var)
从0到total以1为步进

举例如下:
FOREACH(VAR RANGE 10)
MESSAGE($ {VAR})
ENDFOREACH(VAR)
最终得到的输出是:
0
1
2
3
4
5
6
7
8
9
10
<3>范围和步进
FOREACH(loop_var RANGE start stop [step])
ENDFOREACH(loop_var)
从start开始到stop结束,以step为步进。
举例如下:
FOREACH(A RANGE 5 15 3)
MESSAGE(${A})
ENDFOREACH(A)
最终得到的结果是:
5
8
11
14
这个指令需要注意的是,知道遇到ENDFOREACH指令,整个语句块才会得到真正的执行。

7、模块的使用与编写

其实使用纯粹依靠cmake本身提供的基本指令来管理工程是一件非常复杂的事情,所以,cmake设计成了可扩展的架构,可以通过编写一些通用的模块来扩展cmake。
接下来首先介绍cmake提供的FindCURL模块的使用。然后,基于我们前面的libhello共享库,编写一个FindHello.cmake模块。

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读