Cmake

简易工程学习

cmake 是一个跨平台的自动构建工具 ,用来生成Makefile,不用动手编写Makefile。

对于一个初始的C语言程序来说使用cmke进行构建。

1
2
3
4
5
#include <stdio.h>
int main(void)
{
printf("hello world");
}

创建CMakeLists.txt文件,CMakeLists.txt文件会被cmake工具解析 ,写入内容

1
2
project(HELLO)	#设置工程名称
add_executable(hello ./main.c) #第一个参数生成可执行文件用,空格分开传入的参数,第二个参数表示对应的源文件

执行cmake命令

1
cmake ./

之后就会生成makefile文件,可以使用make进行编译。

使用out-of-source方式进行构建,来将工程生成的文件何源文件分离开。

然后在工程目录下创建一个 build 目录

1
2
3
cd build/
cmake ../
make

这样 cmake 生成的中间文件以及 make 编译生成的可执行文件就全部在 build 目录下了,如果要清理工程,直接删除 build 目录即可,这样就方便多了。

当对应的源文件是多个文件时候,例如main.c hello.c

1
add_executable(hello main.c hello.c)

编译动态库/静态库

动态库:以.so作为后缀
静态库:通常以.a.la作为后缀。

1
2
3
add_library(libhello SHARED hello.c) #生成动态库文件
add_library(libhello STATIC hello.c) #生成静态库文件
target_link_libraries(hello libhello) #命令为目标指定依赖库

这时生成的库名字是liblibhello.a,可以通过set_target_properties 来修改工程的名字。

1
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

通过 set_target_properties 命令对 libhello 目标的OUTPUT_NAME 属性进行了设置,将其设置为 hello

大工程分层存储文件夹

使用add_subdirectory来添加子目录并构建子目录。

当前目录为

1
2
3
4
5
6
7
8
9
├── build #build 目录
├── CMakeLists.txt
├── libhello
│ ├── CMakeLists.txt
│ ├── hello.c
│ └── hello.h
└── src
├── CMakeLists.txt
└── main.c

顶层 CMakeLists.txt

1
2
3
project(HELLO)
add_subdirectory(libhello)
add_subdirectory(src)

src 目录下的 CMakeLists.txt

1
2
3
4
include_directories(${PROJECT_SOURCE_DIR}/libhello)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_executable(hello main.c)
target_link_libraries(hello libhello)

libhello 目录下的 CMakeLists.txt

1
2
3
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
add_library(libhello hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

最终得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
├── build
│ ├── bin
│ │ └── hello
│ └── lib
│ └── libhello.a
├── CMakeLists.txt
├── libhello
│ ├── CMakeLists.txt
│ ├── hello.c
│ └── hello.h
└─ src
├── CMakeLists.txt
└── main.c

基础指令

全部命令查看官方文档https://cmake.org/cmake/help/v3.5/manual/cmake-commands.7.html

参数间隔用空格

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
add_executable(<name> source1 source2...) 
# 命令用于添加一个可执行程序目标,并设置目标所需的源文件,可以用绝对路径和相对路径
add_library(<name> [STATIC | SHARED | MODULE] source1 source2 ...])
# 命令用于添加一个库文件,并设置所需要的源文件
add_subdirectory(source_dir [binary_dir])
# 命令用于source_dir 指定一个目录, 告诉cmake 去该目录下寻找 CMakeLists.txt文件并执行它
# 参数binary_dir为指定路径,该路径作为子源码(调用 add_subdirectory 命令的源码称为当前源码或父源码,被执行的
# 源码称为子源码)的输出文件(cmake 命令所产生的中间文件) 目录,
aux_source_directory(<dir> <variable>)
# 查找目录中的所有源文件,dir为指定目录,将得到的信息放入到variable中。
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
# 命令用于设置头文件的搜索路径,如果使用 SYSTEM 选项,会把指定目录当成系统的搜索目录。
# 添加到列表后面
include_directories(AFTER include)
# 添加到列表前面
include_directories(BEFORE include)
link_directories(directory1 directory2 ...)
# 命令用于设置库文件的搜索路径
link_libraries([item1 [item2 [...]]] [[debug|optimized|general] <item>] ...)
# 会将指定目录添加到库文件搜索列表(可以认为每一个 CMakeLists.txt 源码都有自己的库文件搜索列表)中
# 简写
link_libraries(hello)
# 全称
link_libraries(libhello.so)
message([<mode>] "message to display" ...)
# 命令用于打印、输出信息
mode 说明
none(无) 重要信息、普通信息
STATUS 附带信息
WARNING CMake警告,继续处理
AUTHOR_WARNINIG CMake警告(开发),继续处理
SEND_ERROR CMake错误,继续处理,但跳过生成
FALTAL_ERROR CMake错误,停止处理和生成
DEPRECATION 如 果 变 量 CMAKE_ERROR_DEPRECATED 或CMAKE_WARN_DEPRECATED 分别启用, 则 CMake 弃用错
误或警告,否则没有消息。
1
2
3
4
5
6
7
8
9
# 设置工程名称为 HELLO
project(HELLO)#执行这个之后会引入两个变量: HELLO_SOURCE_DIR 和 HELLO_BINARY_DIR
#HELLO_SOURCE_DIR 变量指的是 HELLO 工程源码目录、 HELLO_BINARY_DIR 变量指的是 HELLO 工程源码的输出文件目录
set(<variable> <value>... [PARENT_SCOPE])
#set 命令用于设置变量
target_include_directories(<target> [SYSTEM] [BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
#target_include_directories 命令为指定目标设置头文件搜索路径
target_link_libraries(<target> <PRIVATE|PUBLIC|INTERFACE> <item>... [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
#target_link_libraries为指定目标设置链接库文件

eg:

写一个指针的斐波那契数列(非递归指针方式实现)

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include "function.h"
int main(void)
{
int a = 1, b = 1 ;
int *ptr1, *ptr2;

ptr1 = &a;
ptr2 = &b;
feibo_arr( ptr1, ptr2);

return 0;
}

function.c

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int feibo_arr(int *a, int *b)
{
int temp ;
for( int i = 0; i < 10; i++)
{
temp = *a + *b;
*a = *b;
*b = temp;
printf("%d\n", *b);
}
}

function.h

1
2
3
4
#ifndef _TEST_H
#define _TEST_H
int feibo_arr(int *a, int *b);
#endif
1
tree #使用tree输出树状结构

1
2
3
4
5
#src下的CMakeLists.txt内容
add_executable(feibo main.c) #给feibo可执行文件加上源文件
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) #将可执行文件放到bin文件夹中
include_directories(${PROJECT_SOURCE_DIR}/libfeibo) #指定头文件目录
target_link_libraries(feibo libfeibo) #给feibo工程使用libfeibo的库
1
2
3
4
#lib下的CMakeLists.txt内容
add_library(libfeibo function.c)
set_target_properties(libfeibo PROPERTIES OUTPUT_NAME "feibo") #给lib库重新命名
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) #设置目录
1
2
3
4
5
#工程目录下的CMakeLists.txt内容
cmake_minimum_required(VERSION 3.5)
project(feibo) #给工厂命名feibo
add_subdirectory(src) #执行src下的CMakeLists.txt
add_subdirectory(libfeibo) #执行lib下的CMakeLists.txt