概述
CMake是个一个跨平台自动化建构系统,用来管理软件建置的程序,并不依赖于某特定编译器,并可支持多层目录、多个应用程序与多个函数库。
CMake 通过使用简单的配置文件CMakeLists.txt,自动生成不同平台的构建文件(如Makefile、Ninja构建文件、Visual Studio工程文件等),简化了项目的编译和构建过程。CMake 本身不是构建工具,而是生成构建系统的工具,它生成的构建系统可以使用不同的编译器和工具链。
语法
基本语法格式:指令(参数1 参数2)
参数之间使用空格或者分号隔开
- 指令不区分大小写,参数和变量区分大小写
- 变量使用
${}
取值
常用指令
- 指定CMake的最小版本要求:
cmake_minimum_required
- 语法:
cmake_minimum_required(VERSION versionNumber [FATAL_ERROR])
- 示例:
cmake_minimum_required(VERSION 2.8.3)
- 语法:
- 定义工程名称,并可指定工程支持的语言:
project
- 语法:
project(projectname [CXX][C][Java]...)
- 示例:
project(HELLOWORLD)
- 语法:
- 显式定义变量:
set
- 语法:
set(VAR [value][CACHE TYPE DOCSTRING [FORCE]])
- 示例:
set(SRC 1.cpp hi.cpp)
- 语法:
- 向工程添加多个特定的头文件搜索路径(相当于指定g++编译器的-I参数):
include_directories
- 语法:
include_directories([AFTER][BEFORE][SYSTEM] directory1 directory2 ...)
- 示例:
include_directories(/usr/include/myincludefolder ./include)
- 语法:
- 向工程添加多个特定的库文件搜索路径(相当于指定g++编译器的-L参数):
link_directories
- 语法:
link_directories(directory1 directory2 ...)
- 示例:
link_directories(/usr/lib/mylibfolder ./lib)
- 语法:
- 生成库文件:
add_library
- 语法:
add_library(libname [STATIC|SHARED|MODULE][EXCLUDE_FROM_ALL] source1 source2 ... sourceN)
- 示例:
add_library(hello SHARED ${SRC}) //通过变量SRC生成libhello.so共享库
- 语法:
- 添加编译参数:
add_compile_options
- 语法:
add_compile_options(<option> ...)
- 示例:
link_directories(-Wall -std=c++11 -o2)
- 语法:
- 生成可执行文件:
add_executable
- 语法:
add_executable(exename source1 source2 ... sourceN)
- 示例:
add_executable(main main.cpp) //编译main.cpp生成可执行文件main
- 语法:
- 为target添加需要链接的共享库(相当于指定g++编译器的-l参数):
target_link_libraries
- 语法:
target_link_libraries(target library1<debug|optimized> library2 ...)
- 示例:
target_link_libraries(main hello) //将hello动态库文件链接到可执行文件main
- 语法:
- 向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置:
add_subdirectory
- 语法:
add_subdirectory(source_dir [binary_dir][EXCLUDE_FROM_ALL])
- 示例:
add_subdirectory(src) //添加src子目录,src中需有一个CMakeLists.txt
- 语法:
- 发现一个目录下的所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表:
aux_source_directory
- 语法:
aux_source_directory(dir VARIABLE)
- 示例:
aux_source_directory(. SRC) //定义SRC变量,其值为当前目录下所有的源代码文件
add_executable(main ${SRC}) //编译SRC变量所代表的源代码文件,生成main可执行文件
- 语法:
常用变量
CMAKE_C_FLAGS
:gcc编译选项CMAKE_CXX_FLAGS
:g++编译选项set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
//在CMAKE_CXX_FLAGS
编译选项后追加-std=c++11
CMAKE_BUILD_TYPE
:编译类型(Debug、Release)set(CMAKE_BUILD_TYPE Debug) //设定编译类型为debug,调试时选择debug
set(CMAKE_BUILD_TYPE Release) //设定编译类型为release,发布时选择release
CMAKE_C_COMPILER
:指定C编译器CMAKE_CXX_COMPILER
:指定C++编译器EXECUTABLE_OUTPUT_PATH
:可执行文件输出的存放路径LIBRARY_OUTPUT_PATH
:库文件输出的存放路径- ①
CMAKE_BINARY_DIR
②PROJECT_BINARY_DIR
③<projectname>_BINARY_DIR
- 这三个变量指代的内容是相同的
- 如果是in source build,指的就是工程顶层目录
- 如果是out-of-source编译,指的就是工程编译发生的目录
- ①
CMAKE_SOURCE_DIR
②PROJECT_SOURCE_DIR
③<projectname>_SOURCE_DIR
- 这三个变量指代的内容是相同的,无论采取何种编译方式,都代表工程顶层目录
- 即在in source build时,跟
CMAKE_BINARY_DIR
等变量相同
编译工程
CMake目录结构:项目主目录存在一个CMakeLists.txt文件
两种方式设置编译规则:
- 包含源文件的子文件夹包含CMakeLists.txt文件,主目录的CMakelists.txt通过
add_subdirectory
添加子目录即可 - 包含源文件的子文件夹未包含CMakeLists.txt文件,子目录编译规则体现在主目录的CMakeLists.txt中
编译流程
在Linux上使用CMake构建C/C++工程的流程如下:
- 手动编写CMakeLists.txt文件
- 执行命令
cmake PATH
生成Makefile(PATH是顶层CMakeLists.txt所在的目录) - 执行命令
make
进行编译
两种构建方式
内部构建(in-source build):不推荐❌
内部构建会在同级目录下产生很多最终并不需要的中间文件,和源文件放在一起显得杂乱无章
# 在当前目录下,编译本目录的CMakeLists.txt,生成Makefile和其他文件
cmake .
# 执行make命令,生成target
make
外部构建(out-of-source build):推荐✅
将编译输出文件与源文件放到不同目录下
# 在当前目录下,创建build文件夹
mkdir build
# 进入build文件夹
cd build
# 编译上级目录的CMakeLists.txt,生成Makefile和其他文件
cmake ..
# 执行make命令,生成target
make
6.4.1 编译流程
在 linux 平台下使用 CMake 构建C/C++工程的流程如下:
手动编写 CmakeLists.txt。
。执行命令 cmake PATH生成 Makefile(PATH 是顶层CMakeLists.txt 所在的目录)。
·执行命令make 进行编译