makefile依赖于不同编译平台,CMake可以跨平台。通过编写CMakeLists.txt文件,执行cmake命令,就可以自动生成对应平台的makefile文件,再执行命令make就能进行编译
语法
变量使用${}取值,if语句中直接使用变量名
指令格式为:指令(参数1 参数2),指令大小写无关,参数和变量大小写相关
基本指令
- cmake_minimum_required(版本):指定cmake所需最低版本
- project(工程名字 支持语言):指定工程名字
- set(变量 变量值)
- 设置一个变量
# 该add_executable(mytest main.c func.c)可变为 set(src_list mytest main.c func.c) add_executable(mytest ${src_list})
- 指定c++标准
set(CMAKE_CXX_STANDARD 11)//使用c++11标准
- 指定可执行程序的输出路径
set(EXECUTABLE_OUTPUT_PATH 项目的路径/bin)
- message(信息类型 自定义信息):向用户终端输出自定义信息,用于调试,信息类型包含三种:
- SEND_ERROR:产生错误,生成过程被跳过
- STATUS:输出前缀为--的信息
- FATL_ERROR:立即终止cmake过程
- add_executable(生成可执行文件名 源文件名称):生成可执行程序
例子
有如下文件,都在同一目录src中:head.h,main.c,func.c
在目录下添加一个新文件CMakeLists.txt,文件内容如下:
cmake_minimum_required(VERSION 3.0)
project(test)
add_executable(mytest main.c func.c)
执行cmake该录下生成了一个makefile文件,此时再执行make,就得到所需的可执行程序了mytest
外部构建与内部构建
上面的例子是外部构建,外部构建产生很多临时文件,清理麻烦
内部构建:新建文件夹build,在build目录下执行cmake ..
所有的临时文件都放在这个目录下
工程的基本结构
src:存放源代码
lib:存放库文件
include:存放头文件
build:cmake产生的临时文件
bin:编译生成的二进制文件
doc:存放工程文档
.sh脚本:来调用生成的二进制文件
CMakeLists文件:根目录要通过ADD_SUBDIRECTORY指定src与bin
COPYRIGHT
README
搜索文件
如果一个项目里边的源文件很多,将项目目录的各个文件罗列出来太麻烦。可以使用aux_source_directory命令或者file命令,将文件名都保存在一个变量中
# 将目录下搜索到的源文件列表存储到SRC_LIST变量中
# PROJECT_SOURCE_DIR是一个宏,是cmakelists.txt文件所在的目录
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC_LIST)
add_executable(app ${SRC_LIST})
头文件可能不在源文件当前目录,需将头文件路径指定出来,使编译器能够找到这些头文件include_directories(头文件目录)
静态库和动态库
windows中静态库后缀是.lib,动态库后缀是.dll
linux中静态库后缀是.a,动态库后缀是 .so
创建静态库和动态库
ADD_LIBRARY(生成库名 库类型 源代码文件)
库类型有SHARED动态库 STATIC静态库
ADD_LIBRARY(hello_static STATIC hello.cpp)
ADD_LIBRARY(hello SHARED hello.cpp)
设置动态库/静态库输出路径set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
加载静态库和动态库
要加载库,需要有库文件和头文件
加载静态库link_libraries(多个库文件名)
加载动态库或者静态库target_link_libraries(需要链接库的文件 链接权限PRIVATE|PUBLIC|INTERFACE 库名)
对于系统提供的库,只要提供名字就可以找到库文件,其它库(非标准库),就需要指定库文件的路径link_directories(库文件路径)
另外还可以改变系统的环境变量来指定搜索路径CMAKE_INCLUDE_PATH(头文件目录),CMAKE_LIBRARY_PATH
自定义宏
add_definitions(-D宏名称)
可以在代码中添加一些宏定义,通过这些宏来控制这些代码是否生效
int main()
{
int a = 10;
#ifdef DEBUG
printf("debug\n");
#endif
}
在程序中对DEBUG宏进行了判断,如果该宏被定义了,就会进行日志输出,如果没有定义就相当于被注释掉了。为了让测试更灵活,可以不在代码中定义这个宏,而是在测试的时候去把它定义出来,就可以在CMake中定义宏
嵌套CMake
有时候如果只使用一个CMakeLists.txt,那么这个文件相对会比较复杂,可以给每个源代码目录都添加一个CMakeLists.txt 文件。所以在父目录的CMakeLists.txt文件中就需要指明子目录的位置add_subdirectory(源代码子目录)
安装库与头文件
使用CMake构建一个项目时,通常会生成库文件(如静态库或动态库)以及一些公共的头文件。这些库文件和头文件通常位于构建目录下,如果希望其他项目或用户能够方便地使用这些库和头文件,需要安装库与头文件。
通过在CMakeLists.txt文件中install命令,可以将库文件和头文件复制到指定的安装目录。
# 构建库
add_library(mylib SHARED mylib.cpp)
# 指定安装目录
install(TARGETS mylib DESTINATION /usr/local/lib)
install(FILES mylib.h DESTINATION /usr/local/include)
首先使用add_library命令构建一个名为mylib的共享库,它的源文件为mylib.cpp。然后,使用install命令指定要安装的目标(mylib)和目标位置(/usr/local/lib)。这将把mylib库文件复制到系统的/usr/local/lib目录中。同时,使用install命令将mylib.h头文件复制到系统的/usr/local/include目录中,以便其他项目或用户可以通过包含该头文件来访问库的接口。
安装库和头文件后,其他项目或用户就可以在其CMakeLists.txt文件中使用target_link_libraries命令来链接这个已安装的库,并通过#include语句来引用安装的头文件。
参考链接
CMake 保姆级教程及对应视频CMake 保姆级教程【C/C++】
从零开始详细介绍CMake
软件构建: CMake 快速入门