CMake是个一个开源的跨平台自动化建构系统,用来管理软件建置的程序,并不相依于某特定编译器。可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的Makefile或者project文件,CMake 并不直接建构出最终的软件,而是产生标准的建构档(如Unix的Makefile或projects),然后再依一般的建构方式使用。

1. 基本模板

Cmake的基础便是CMakeLists.txt文件,一般:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# cmake版本要求
cmake_minimum_required (VERSION 2.8)
# 当前工程名称
project(main)

message("")
# 资源目录
message(STATUS "SOURCE DIR: " ${PROJECT_SOURCE_DIR})

# 设置源文件变量, 并添加文件(多个)
# set(src_list xxx.cpp xxx.cpp xx.cpp)
set(src_list main.cpp 1.cpp)
# 目标可执行文件
# 可执行文件的输出目录
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
set(target_file ${PROJECT_NAME})

# 打印提示信息
message(STATUS "SOURCE: " ${src_list})
message(STATUS "TARGET: " ${EXECUTABLE_OUTPUT_PATH}/${target_file})
message("")

# 设置C++编译参数(CMAKE_CXX_FLAGS是全局变量)
set(CMAKE_CXX_FLAGS "-Wall -std=c++11")

#指定头文件目录位置
# INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include)
#添加共享库搜索路径
# LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/lib)

# 设置头文件位置,相当于g++ -I,可以用相对或绝对路径,也可以用自定义的变量值
# include_directories(${})

# 使用给定的源文件,为工程引入一个可执行文件test。
add_executable(${target_file} ${src_list})

编译的时候,当源文件很多的时候,可以使用 aux_source_directory 命令,该命令会查找指定目录下的所有源文件,然后将结果存进指定变量名。其语法如下:

1
2
3
4
aux_source_directory(<dir> <variable>)

aux_source_directory(${PROJECT_SOURCE_DIR} DIR_SRCS)
add_executable(${target_file} ${src_list})

这样,CMake 会将当前目录所有源文件的文件名赋值给变量 DIR_SRCS ,再指示变量 DIR_SRCS 中的源文件需要编译成一个名称为 CMakeDemo的可执行文件。

2. 生成库文件

1
add_library(${name} ${source})

库文件是事先编译好的方法的合集。比如:我们提前写好一些数据公式的实现,将其打包成库文件,以后使用只需要库文件就可以,不需要重新编写。

库文件分两种:静态库和动态库(也叫共享库)

  • Windows系统静态库扩展名为:.lib,动态库扩展名为.dll;
  • Linux系统下静态库的扩展名为.a,动态库的扩展名为.so;
  1. Cmake生成静态库

静态库(也称作归档文件),程序在链接的过程中,链接器从库文件中取得所需代码,复制到生成的可执行文件中。因此,静态库是在程序员的链接阶段被复制到程序当中,和程序的执行没有任何关系。

这类库在编译的时候会直接整合到目标程序中,所以利用静态函数库编译成的文件会比较大,这类函数库最大的优点就是编译成功的可执行文件可以独立运行,而不再需要向外部要求读取函数库的内容;

1
2
3
4
5
6
7
8
9
10
# cmake版本要求
cmake_minimum_required (VERSION 2.8)
# 当前工程名称
project(sub)

aux_source_directory(${PROJECT_SOURCE_DIR} DIR_SRCS)
message(STATUS "SOURCE: " ${DIR_SRCS})

# 这里就是关键,生成静态库(默认)
add_library(${PROJECT_NAME} ${DIR_SRCS})
  1. Cmake生成动态库

与静态函数库被整个捕捉到程序中不同,动态函数库在编译的时候,在程序里只有一个“指向”的位置而已,也就是说当可执行文件需要使用到函数库的机制时,程序才会去读取函数库来使用;也就是说可执行文件无法单独运行。

1
2
3
4
5
6
7
8
9
10
# cmake版本要求
cmake_minimum_required (VERSION 2.8)
# 当前工程名称
project(sub)

aux_source_directory(${PROJECT_SOURCE_DIR} DIR_SRCS)
message(STATUS "SOURCE: " ${DIR_SRCS})

# 这里就是关键,生成动态库!SHARED
add_library(${PROJECT_NAME} SHARED ${DIR_SRCS})

3. 链接库

  • link_directories

该指令的作用主要是指定要链接的库文件的路径,该指令有时候不一定需要。因为find_package和find_library指令可以得到库文件的绝对路径。不过你自己写的动态库文件放在自己新建的目录下时,可以用该指令指定该目录的路径以便工程能够找到。

  • target_link_libraries

该指令的作用为将目标文件与库文件进行链接。该指令的语法如下:

1
2
target_link_libraries(<target> [item1] [item2] [...]
[[debug|optimized|general] <item>] ...)
  • 示例

假设我们需要寻找当前目录中lib/libmath.so,则CMakeLIsts.txt:

1
2
3
4
5
# 添加库目录
link_directories(${PROJECT_SOURCE_DIR}/lib)

# 添加链接库libmath.so or libmath.a
target_link_libraries(${PROJECT_NAME} math)

4. 外部项目

当当前编译的项目需要外部文件支持时,可以将外部文件编译为静态链接库,然后链接到目标,

1
2
3
4
5
# 添加外部文件夹,并执行该文件夹下方的CMakeLists.txt
add_subdirectory(sub1)

# 添加静态库,sub->实际中:libsub.a
target_link_libraries(${target_file} sub)

同时,外部文件夹sub1中,同样需要CMakeLIsts.txt文件:例如:

1
2
3
4
5
6
7
# cmake版本要求
cmake_minimum_required (VERSION 2.8)
# 当前工程名称
project(sub)

aux_source_directory(${PROJECT_SOURCE_DIR} DIR_SRCS)
add_library(${PROJECT_NAME} ${DIR_SRCS})

cmake clean

cmake没有提供类似Makefile中clean的命令,因此可以在源文件同级目录下写一个Makefile,内容如下:CSDN-coldplayplay

1
2
3
4
5
6
7
8
9
10
11
12
BUILD_DIR = ./build
DEST_DIR = ./bin
DEST_EXE_NAME = main

all: build
cd $(BUILD_DIR); make -j4
run:
cd $(DEST_DIR); ./$(DEST_EXE_NAME)
clean:
rm $(BUILD_DIR) -rf
build:
mkdir $(BUILD_DIR);cd $(BUILD_DIR); cmake ..

cmake基础部分大概如此,更加进阶的基于基础在实战中进步!