CMake的使用

CMake

CMake是开源、跨平台的构建工具,可以让我们通过编写简单的配置文件去生成本地的Makefile,这个配置文件是独立于运行平台和编译器的,这样就不用亲自去编写Makefile了,而且配置文件可以直接拿到其它平台上使用,无需修改,非常方便。

Linux下CMake简明教程_linux中cmake_爱就是恒久忍耐的博客-CSDN博客

CMake 的安装

Ubuntu下的安装

1
2
3
4
5
6
$ sudo apt-get install cmake

$ cmake --version
cmake version 3.16.3
.....
# 这样就安装好了

CMake语法

最简单的版本

环境:只有一个main.c的hello world文件,没有任何依赖。

main.c的同级目录下建立一个文件,文件名叫CMakeFileLists.txt,这个文件名不能变更,只能是这个形式。

文件内容如下:

1
2
3
4
5
6
7
8
# cmake的最低版本要求是2.8
cmake_minimum_required(VERSION 2.8)

# 工程名
project(download)

# 使用main.c这个源文件 生成elf文件 生成的文件名字叫main
add_executable(main, main.c)

我们在当前目录(main.cCMakeFileLists.txt的目录下)运行cmake .,含义就是在当前目录下执行cmake。执行成功后会生成Makefils以及一些cmake运行时自动生成的文件。

这个时候我们使用命令make就可以看到正确编译了。

一个目录下的多个源文件

1
2
3
4
5
6
7
8
9
cmake_minimum_required (VERSION 2.8)

project (demo)

# 当前目录下的源文件存列表存放到变量SRC_LIST里
aux_source_directory(. SRC_LIST)

# 在add_executable里调用SRC_LIST(注意调用变量时的写法)
add_executable(main ${SRC_LIST})

aux_source_directory()也存在弊端,它会把指定目录下的所有源文件都加进来,可能会加入一些我们不需要的文件,此时我们可以使用set命令去新建变量来存放需要的源文件

1
2
3
4
5
6
7
8
9
10
11
cmake_minimum_required (VERSION 2.8)

project (demo)

# set 命令设置变量存放源文件
set( SRC_LIST
./main.c
./testFunc1.c
./testFunc.c)

add_executable(main ${SRC_LIST})

不同目录下的多个源文件

文件结构

1
2
3
4
5
6
7
8
./bin
./build
./include
xx.h
xxx.h
./src
xxx.c
xx.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cmake_minimum_required (VERSION 2.8)

project (demo)

# 修改输出位置
# EXECUTABLE_OUT_PATH和PROJECT_SOURCE_DIR是CMake自带的预定义变量
# EXECUTABLE_OUTPUT_PATH :目标二进制可执行文件的存放位置
# PROJECT_SOURCE_DIR:工程的根目录
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

# 当前src目录下的源文件存列表存放到变量SRC_LIST里
aux_source_directory (src SRC_LIST)

# 将include文件夹设定为头文件搜索路径
# 该命令是用来向工程添加多个指定头文件的搜索路径,路径之间用空格分隔。
include_directories (include)

# 生成elf文件
add_executable (main ${SRC_LIST})

静态库和动态库的编译

编译出动态库和静态库,然后等着让其它程序去使用。

文件结构

1
2
3
4
5
6
7
8
9
./bin
./build
./lib
./include
xx.h
xxx.h
./src
xxx.c
xx.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cmake_minimum_required (VERSION 3.5)

project (demo)

set (SRC_LIST ${PROJECT_SOURCE_DIR}/src/xxx.c)

# 生成动态库或静态库
# 第1个参数指定库的名字;
# 第2个参数决定是动态还是静态,如果没有就默认静态;
# 第3个参数指定生成库的源文件
add_library (testFunc_shared SHARED ${SRC_LIST})
add_library (testFunc_static STATIC ${SRC_LIST})

# 设置最终生成的库的名称,还有其它功能,如设置库的版本号等等
set_target_properties (testFunc_shared PROPERTIES OUTPUT_NAME "testFunc")
set_target_properties (testFunc_static PROPERTIES OUTPUT_NAME "testFunc")

set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

对库进行链接

1
2
3
find_library(TESTFUNC_LIB testFunc HINTS ${PROJECT_SOURCE_DIR}/testFunc/lib)

target_link_libraries (main ${TESTFUNC_LIB})
  • find_library: 在指定目录下查找指定库,并把库的绝对路径存放到变量里,其第一个参数是变量名称,第二个参数是库名称,第三个参数是HINTS,第4个参数是路径,其它用法可以参考cmake文档
  • target_link_libraries: 把目标文件与库文件进行链接

ps:在lib目录下有testFunc的静态库和动态库,find_library(TESTFUNC_LIB testFunc …默认是查找动态库,如果想直接指定使用动态库还是静态库,可以写成find_library(TESTFUNC_LIB libtestFunc.so …或者find_library(TESTFUNC_LIB libtestFunc.a …

ps: 查看elf文件使用了哪些库,可以使用readelf -d ./xx来查看

之前本节教程使用的是库查找方法是link_directories,但是很多读者反映运行时有问题,本人去官方文档上查了下,发现不建议使用了,推荐使用find_library或者find_package

添加编译选项

有时编译程序时想添加一些编译选项,如-Wall,-std=c++11等,就可以使用add_compile_options来进行操作。

add_compile_options(-std=c++11 -Wall)

更加完善的目录结构及编译选项

文件结构

构建的时候我们需要先cd build,然后再cmake ..构建,最后make -j8编译即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
.
├── build
├── CMakeLists.txt
├── libzip
│ ├── ioapi.c
│ ├── ioapi.h
│ ├── unzip.c
│ └── unzip.h
├── main
│ └── curl_zip.c
├── tools
└── log
└── log.h
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
cmake_minimum_required(VERSION 3.0)
project(curl_zip)

set(Target down)

# 设置语言标准
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

# 为当前路径以及子目录的源文件加入由-D预编译定义
# add_definitions(-DFOO -DDEBUG ...)

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

# 设置指定的C++编译器版本是必须的,如果不设置,或者为OFF,则指定版本不可用时,会使用上一版本。
# set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 设置编译器选项
add_compile_options(-O3 -Wall)


message("Target=" ${Target})
message("---------- Start building ----------")


# 设置包含路径
include_directories( ${PROJECT_SOURCE_DIR}/libzip
${PROJECT_SOURCE_DIR}/tools/log
)


# 把xxx目录下所有源文件写入变量SRC_LIST
aux_source_directory(${PROJECT_SOURCE_DIR}/libzip SRC_LIST)
aux_source_directory(${PROJECT_SOURCE_DIR}/src/curl SRC_LIST)
aux_source_directory(${PROJECT_SOURCE_DIR}/main SRC_LIST)

# 以SRC_LIST为源文件生成目标文件xxx
add_executable(${Target} ${SRC_LIST})


# 创建库文件
# add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 source2 ... sourceN)


# 目标文件链接的库
# target_link_libraries() 总是指明 PRIVATE、PUBLIC 、INTERFACE
target_link_libraries( ${Target}
pthread
curl
z
)

message("---------- Stop building ----------")

CMake的使用
https://www.oikiou.top/2023/3c5e47f1/
作者
Oikiou
发布于
2023年3月29日
许可协议