CMake的使用
CMake的使用
CMake介绍
CMake: 使用简单方便,可以跨平台,构建项目编译环境。比直接写Makefile简单(),可以通过简单的,一个命令便将我们项目想编译的可执行文件、静态库、动态库都编译出来了。
安装
Linux环境安装CMake
sudo apt install cmake
cmake -version #查看版本
或者 通过编译好的版本安装 Download CMake
移动到Linux下并解压(jie'ya'h)
tar -zxvf cmake-3.29.2-linux-x86_64.tar.gz cd cmake-3.29.2-linux-x86_64/bin
查看版本
./cmake -version
建立软链接
sudo ln -s ~/app/cmake-3.29.2-linux-x86_64/bin/cmake /usr/bin/cmake cmake -version #再测试
image-20240412142839918
vscode环境安装CMake
vscode下载相应插件-
CMake
、CMake Tools
shell终端查找cmake位置,前面我们建立的软链接,直接使用
/usr/bin/cmake
whereis cmake
点击CMake Tools的扩展设置
image-20240412134918477 选择远程主机配置,找到
Cmake:Build Environment
,添加相应环境变量即可。

使用方法
Linux上CMake使用
先cmake在make
- cd 到 build 目录下,执行
cmake .. && make
命令
vscode使用
需要在远程连接的工程根路径下建立一个主CMakeLists.txt。
主CMakeLists.txt添加相应配置,指定搜索的子目录为要参与构建的项目
工具启动时先处理主CMakeList.txt,再处理muduocode里的子CMakeList.txt,如图为子CMakeList.txt。
再直接点击vscode里cmake的按钮即可将生成的所有中间文件都放入一个build目录中,可执行文件放入bin目录中,无论是Linux上直接操作还是vscode进行配置,可以依据自己的需求进行改变。
CMake常用预定义变量
1、PROJECT_NAME
:通过 project() 指定项目名称; 2、PROJECT_SOURCE_DIR
:工程的根目录; 3、PROJECT_BINARY_DIR
:执行 cmake 命令的目录; 4、CMAKE_CURRENT_SOURCE_DIR
:当前 CMakeList.txt 文件所在的目录; 5、CMAKE_CURRENT_BINARY_DIR
:编译目录,可使用 add subdirectory
来修改; 6、EXECUTABLE_OUTPUT_PATH
:二进制可执行文件输出位置; 7、LIBRARY_OUTPUT_PATH
:库文件输出位置; 8、BUILD_SHARED_LIBS
:默认的库编译方式 ( shared 或 static ) ,默认为 static; 9、CMAKE_C_FLAGS
:设置 C 编译选项; 10、CMAKE_CXX_FLAGS
:设置 C++ 编译选项; 11、CMAKE_CXX_FLAGS_DEBUG
:设置编译类型 Debug 时的编译选项; 12、CMAKE_CXX_FLAGS_RELEASE
:设置编译类型 Release 时的编译选项; 13、CMAKE_GENERATOR
:编译器名称; 14、CMAKE_COMMAND
:CMake 可执行文件本身的全路径; 15、CMAKE_BUILD_TYPE
:工程编译生成的版本, Debug / Release;
添加可执行文件作为构建目标
同一目录,单个/多个源文件
直接写
cmake_minimum_required (VERSION 2.8) #指定运行此配置文件所需的 CMake 的最低版本 project (demo1) #参数值是 demo1,该命令表示项目的名称是 demo1 add_executable(main main.cpp) #将名为 main.cpp 的源文件编译成一个名称为 main 的可执行文件
使用
GLOB
自动查找当前目录下指定扩展名的文件,实现批量添加源文件。最好是启用CONFIGURE_DEPENDS
选项,添加新文件时会自动更新变量cmake_minimum_required(VERSION 3.10) project(yx) file(GLOB sources CONFIGURE_DEPENDS *.cpp *.h) add_executable(main ${sources})
使用
GLOB_RECURSE
可以包含所有子文件夹下的文件,为了避免将build目录里临时生成的cpp也加进来,建议把源码都放在src目录下aux_source_directory
自动会查找指定目录下的所有源文件,然后将结果存进指定变量名aux_source_directory(. sources) #就是把当前目录下需要的文件搜集到sources变量中
cmake_minimum_required (VERSION 2.8) project (demo2) aux_source_directory (./ DIR_SRCS) add_executable (demo ${DIR_SRCS})
使用
set
命令去新建变量来存放需要的源文件。因为aux_source_directory
也存在弊端,它会把指定目录下的所有源文件都加进来,实际项目中可能有些是我们不需要的文件。cmake_minimum_required (VERSION 2.8) project (demo2) set ( DIR_SRCS ./main.cpp ./add.cpp ) add_executable (demo ${DIR_SRCS})
多个目录,多个源文件
一般来说,当文件比较多时,我们会进行分类管理,根据功能把代码放在不同目录下,这样方便查找
03demo/ ├── add │ ├── add.cpp │ └── add.h ├── sub │ ├── sub.cpp │ └── sub.h └── main.cpp
方法一:include_directories指定头文件,aux_source_directory指定源文件
CMakeLists.txt 和 main.cpp 在同一目录下,内容修改成如下所示
cmake_minimum_required (VERSION 2.8)
project (demo3)
include_directories (./add ./sub)#向工程添加多个指定头文件的搜索路径,路径之间用空格分隔
aux_source_directory (./ DIR_SRCS)
aux_source_directory (./add DIR_SRCS1)
aux_source_directory (./sub DIR_SRCS2)
add_executable (demo ${DIR_SRCS} ${DIR_SRCS1} ${DIR_SRCS2})
方法二:(lib 库)分别在 add 和 sub 目录里各编写一个 CMakeLists.txt 文件
为了方便,我们可以先将 add 和 sub 目录里的文件**再由 main 函数调用根目录中的 CMakeLists.txt**
cmake_minimum_required (VERSION 2.8)
project (demo3)
include_directories (./add ./sub) #头文件
add_subdirectory (./add) #指明本项目包含子目录 add 和 sub,这样当执行 cmake 时,就会进入子目录去找 CMakeLists.txt 来生成 Makefile
add_subdirectory (./sub)
aux_source_directory (./ DIR_SRCS)
add_executable (demo ${DIR_SRCS})
target_link_libraries (demo myadd mysub) #指明可执行文件 demo 需要链接一个名为 myadd 和 mysub 的链接库
这种写法**,**
add 目录中的 CMakeLists.txt
aux_source_directory (./ DIR_LIB_SRCS)
add_library (myadd SHARED ${DIR_LIB_SRCS}) #将add目录的源文件编译成动态库
sub 目录中的 CMakeLists.txt
aux_source_directory (./ DIR_LIB_SRCS)
add_library (mysub STATIC ${DIR_LIB_SRCS})
add_library
第 1 个参数指定库的名字;第 2 个参数决定是动态还是静态,不写****;第 3 个参数指定生成库的源文件。注意:SHARED 和 STATIC 是 cmake 的关键字,必须!
常用的组织结构
把源文件放到 src 目录下 把头文件放到 include 目录下 把生成的库文件放到 lib 目录下 把生成的对象文件放到 build 目录下 把最终输出的 elf 文件放到 bin 目录下
04demo/ ├── bin ├── build ├── include │ ├── add.h │ └── sub.h ├── lib └── src ├── lib_add │ └── add.cpp ├── sub │ └── sub.cpp └── main.cpp
- 最外层新建一个 CMakeLists.txt用于掌控全局,使用
add_subdirectory
来添加要生成 elf 文件的源码目录即可
cmake_minimum_required (VERSION 2.8)
project (demo4)
add_subdirectory (./src) #指定搜索的子目录
- src 目录下,新建一个 CMakeLists.txt
add_subdirectory (./lib_add) #指定搜索的子目录
aux_source_directory (./ DIR_SRCS1)
aux_source_directory (./sub DIR_SRCS2)
include_directories (../include)
link_directories (${PROJECT_SOURCE_DIR}/lib) #添加非标准库的搜索路径
add_executable (demo ${DIR_SRCS1} ${DIR_SRCS2})
target_link_libraries (demo myadd)
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) #设置可执行文件的最终存储路径
EXECUTABLE_OUTPUT_PATH
和PROJECT_SOURCE_DIR
是 cmake 自带的预定义变量
EXECUTABLE_OUTPUT_PATH:目标二进制可执行文件的存放位置 PROJECT_SOURCE_DIR:当前工程的根目录
- lib_add 目录下,也要新建一个 CMakeLists.txt
aux_source_directory (./ DIR_LIB_SRCS)
add_library (myadd_shared SHARED ${DIR_LIB_SRCS})
add_library (myadd_static STATIC ${DIR_LIB_SRCS})
set_target_properties (myadd_shared PROPERTIES OUTPUT_NAME "myadd")
set_target_properties (myadd_static PROPERTIES OUTPUT_NAME "myadd")
set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
添加编译选项
有时编译程序时想添加一些编译选项,如 -g、-Wall、-std=c++11
等,就可以使用add_compile_options
来操作,也可以通过set命令
修改CMAKE_CXX_FLAGS
或CMAKE_C_FLAGS
,这两个是 cmake 自带的预定义变量,用于设置编译选项 这两种方式的效果是一样的,但请注意它们还是有区别的:
add_compile_options
命令添加的编译选项是针对****- 而
set命令
设置CMAKE_C_FLAGS
或CMAKE_CXX_FLAGS
变量则是分别只针对 c 和 c++ 编译器的
cmake_minimum_required (VERSION 2.8)
project (demo5)
#设置编译选项
#add_compile_options (-std=c++11 -Wall)
set (CMAKE_CXX_FLAGS "-std=c++11 -Wall ${CMAKE_CXX_FLAGS}")
aux_source_directory (./ DIR_SRCS)
add_executable (demo ${DIR_SRCS})
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
cd 到 build 目录下,执行cmake .. && make
命令,就可以在 bin 目录下得到 elf 文件
添加控制选项
希望在编译代码时****,这时可以使用 cmake 的option
命令
假设我们现在的工程会生成 2 个 bin 文件,main1 和 main2,现在整体结构如下 06demo/ ├── bin ├── build ├── CMakeLists.txt └── src ├── CMakeLists.txt ├── └──
外层的 CMakeLists.txt 内容如下
cmake_minimum_required (VERSION 2.8)
project (demo6)
option (MYDEBUG "enable debug mode" OFF)
add_subdirectory (./src)
option
命令
- 其第一个参数是这个 option 的名字,
- 第二个参数是字符串,用来描述这个 option 是来干嘛的,
- 第三个是 option 的值,
ON
或OFF
,也可以不写,不写就是默认 OFF
src 目录下的 CMakeLists.txt,如下
add_executable (main1 main1.cpp)
if (MYDEBUG)
add_executable (main2 main2.cpp)
else()
message (STATUS "Currently is not in debug mode")
endif()
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
- 这里使用了 if-else 根据 option 来决定是否编译 main2.cpp
message
为用户打印显示一条消息,可以用下述可选的关键字指定消息类型
(无) = 重要消息
STATUS = 非重要消息
WARNING = CMake 警告,会继续执行
AUTHOR_WARNING = CMake 警告 (dev),会继续执行
SEND_ERROR = CMake 错误,继续执行,但是会跳过生成的步骤
FATAL_ERROR = CMake 错误,终止所有处理过程
cd 到 build 目录下输入cmake .. && make就可以只编译出 main1,如果想编译出 main2
- 直接修改 CMakeLists.txt,把 OFF 改成 ON,这种方法有点麻烦
- cd 到 build 目录,然后输入**
cmake .. -DMYDEBUG=ON && make
**,这样就可以编译出 main1 和 main2
为什么要在 build 目录下运行 cmake?
如果不这样做,cmake 运行时就会跟文件,这样会对程序的目录结构造成污染,而在 build 目录下运行 cmake,生成的附带文件就只会待在 build 目录下,如果我们不想要这些文件就可以直接清空 build 目录,非常方便
CMAKE_BUILD_TYPE
控制构建类型
默认空字符串,相当于Debug
调试模式 其它模式:Release、MinSizeRel、RelWithDebInfo
,这3种模式都定义了NDEBUG宏,会导致****
set(CMAKE_BUILD_TYPE Release)
大多数项目为了默认为Release模式,CMakeLists中会写如下三行
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
NDEBUG宏
的使用
在CMakeLists中写上
add_definitions(-DNDEBUG) #定义了NDEBUG宏
这样对于下面的test.cpp,assert不起作用,输出xx
#include <iostream>
#include <cassert>
int main()
{
int m=3;
#ifdef NDEBUG
std::cout<<"xx"<<std::endl;
#else
std::cout<<"yy"<<std::endl;
#endif
assert(m == 2);
return 0;
}
几个目录
cmake_minimum_required(VERSION 3.29)
project(LoggerCMake)
set(SRC_LIST Logger.cc test.cc) #直接写源文件
add_executable(Logger ${SRC_LIST})
target_link_libraries(Logger log4cpp pthread)