Cmake
原文以及代码来自:https://github.com/wzpan/cmake-demo
https://zhuanlan.zhihu.com/p/534439206
CMake使用介绍
cmake命令会执行目录下的CMakeLists.txt配置文件里面的配置项,一个基本的CMakeLists.txt的配置
文件内容如下:
cmake_minimum_required (VERSION 3.0) #要求cmake最低的版本号
project (demo) # 定义当前工程名字
set(CMAKE_BUILD_TYPE "Debug")#设置debug模式,如果没有这一行将不能调试设断点
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -g)
add_executable(main main.c)
#进入子目录下执行 CMakeLists.txt文件 这里的lib和tests里面都有可编译的代码文件
add_subdirectory(lib)
add_subdirectory(tests)
示例一
生成一个main.cpp源文件,输出"hello world",然后在同级目录创建一个CMakeLists.txt文件,内容
如下:
cmake_minimum_required (VERSION 2.8) #要求cmake最低的版本号
project (demo) # 定义当前工程名字
set(CMAKE_BUILD_TYPE "Debug")#设置debug模式,如果没有这一行将不能调试设断点
add_executable(main main.cpp)
示例二
如果需要编译的有多个源文件,可以都添加到add_executable(main main.cpp test.cpp)列表当中,
但是如果源文件太多,一个个添加到add_executable的源文件列表中,就太麻烦了,此时可以用
aux_source_directory(dir var)来定义源文件列表,使用如下:
cmake_minimum_required (VERSION 2.8)
project (demo)
aux_source_directory(. SRC_LIST) # 定义变量,存储当前目录下的所有源文件
add_executable(main ${SRC_LIST})
aux_source_directory()也存在弊端,它会把指定目录下的所有源文件都加进来,可能会加入一些我们
不需要的文件,此时我们可以使用set命令去新建变量来存放需要的源文件,如下
cmake_minimum_required (VERSION 2.8)
project (demo)
set( SRC_LIST
./main.cpp
./test.cpp)
add_executable(main ${SRC_LIST})
示例三 - 一个正式的工程构建
一个正式的源码工程应该有这几个目录:
-bin 存放最终的可执行文件
-build 存放编译中间文件
-include 头文件
--sum.h
--minor.h
-src 源代码文件
--sum.cpp
--minor.cpp
--main.cpp
-CMakeLists.txt
CMakeLists.txt如下:
cmake_minimum_required (VERSION 2.8)
project (math)
# 设置cmake的全局变量
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#添加头文件路径,相当于makefile里面的-I
include_directories(${PROJECT_SOURCE_DIR}/include)
aux_source_directory (src SRC_LIST)
add_executable (main main.cpp ${SRC_LIST})
然后在build目录里面执行cmake .. 命令,这样所有的编译中间文件都会在build目录下,最终的可执行
文件会在bin目录里面
静态库和动态库的编译控制
把上面的sum和minor源文件直接生成静态库或者动态库,让外部程序进行链接使用,代码结构如下:
-bin 存放最终的可执行文件
-build 存放编译中间文件
-lib 存放编译生成的库文件
-include 头文件
--sum.h
--minor.h
-src 源代码文件
--sum.cpp
--minor.cpp
--CMakeLists.txt
-test 测试代码
--main.cpp
--CMakeLists.txt
-CMakeLists.txt
最外层的CMakeLists.txt是总控制编译,内容如下:
cmake_minimum_required (VERSION 2.8)
project (math)
add_subdirectory (test)
add_subdirectory (src)
src里面的源代码要生成静态库或动态库,CMakeLists.txt内容如下:
set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
# 生成库,动态库是SHARED,静态库是STATIC
add_library (sum SHARED sum.cpp)
add_library (minor SHARED minor.cpp)
# 修改库的名字
#set_target_properties (sum PROPERTIES OUTPUT_NAME "libsum")
#set_target_properties (minor PROPERTIES OUTPUT_NAME "libminor")
test里面的CMakeLists.txt内容如下:
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
include_directories (../include) # 头文件搜索路径
link_directories (${PROJECT_SOURCE_DIR}/lib) # 库文件搜索路径
add_executable (main main.cpp) # 指定生成的可执行文件
target_link_libraries (main sum minor) # 执行可执行文件需要依赖的库
在build目录下执行cmake ..命令,然后执行make
CMake常用的预定义变量
PROJECT_NAME : 通过 project() 指定项目名称
PROJECT_SOURCE_DIR : 工程的根目录
PROJECT_BINARY_DIR : 执行 cmake 命令的目录
CMAKE_CURRENT_SOURCE_DIR : 当前 CMakeList.txt 文件所在的目录
CMAKE_CURRENT_BINARY_DIR : 编译目录,可使用 add subdirectory 来修改
EXECUTABLE_OUTPUT_PATH : 二进制可执行文件输出位置
LIBRARY_OUTPUT_PATH : 库文件输出位置
BUILD_SHARED_LIBS : 默认的库编译方式 ( shared 或 static ) ,默认为 static
CMAKE_C_FLAGS : 设置 C 编译选项
CMAKE_CXX_FLAGS : 设置 C++ 编译选项
CMAKE_CXX_FLAGS_DEBUG : 设置编译类型 Debug 时的编译选项
CMAKE_CXX_FLAGS_RELEASE : 设置编译类型 Release 时的编译选项
CMAKE_GENERATOR : 编译器名称
CMAKE_COMMAND : CMake 可执行文件本身的全路径
CMAKE_BUILD_TYPE : 工程编译生成的版本, Debug / Release
Cmake使用步骤
写 CMake 配置文件 CMakeLists.txt 。
执行命令
cmake PATH
或者ccmake PATH
生成 Makefile(ccmake
和cmake
的区别在于前者提供了一个交互式的界面)。其中,PATH
是 CMakeLists.txt 所在的目录。使用
make
命令进行编译。
入门案例:单个源文件
编写 CMakeLists.txt
只有单个源文件,首先编写 CMakeLists.txt 文件,并保存在与 main.cc 源文件同个目录下:
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo1)
# 指定生成目标
add_executable(Demo main.cc)
CMakeLists.txt 的语法比较简单,由命令、注释和空格组成,其中命令是不区分大小写的。符号 #
后面的内容被认为是注释。命令由命令名称、小括号和参数组成,参数之间使用空格进行间隔。对于上面的 CMakeLists.txt 文件,依次出现了几个命令:
cmake_minimum_required
:指定运行此配置文件所需的 CMake 的最低版本;project
:参数值是Demo1
,该命令表示项目的名称是Demo1
。add_executable
:将名为 main.cc 的源文件编译成一个名称为 Demo 的可执行文件。
编译项目
之后,在当前目录执行 cmake .
,得到 Makefile 后再使用 make
命令编译得到 Demo1 可执行文件。
多个源文件
./Demo2
|
+--- main.cc
|
+--- MathFunctions.cc
|
+--- MathFunctions.h
这个时候,CMakeLists.txt 可以改成如下的形式:
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 指定生成目标
add_executable(Demo main.cc MathFunctions.cc)
唯一的改动只是在 add_executable
命令中增加了一个 MathFunctions.cc
源文件。这样写当然没什么问题,但是如果源文件很多,把所有源文件的名字都加进去将是一件烦人的工作。更省事的方法是使用 aux_source_directory
命令,该命令会查找指定目录下的所有源文件,然后将结果存进指定变量名。其语法如下:
aux_source_directory(<dir> <variable>)
因此,可以修改 CMakeLists.txt 如下:
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})
这样,CMake 会将当前目录所有源文件的文件名赋值给变量 DIR_SRCS
,再指示变量 DIR_SRCS
中的源文件需要编译成一个名称为 Demo 的可执行文件。
多个目录,多个源文件
./Demo3
|
+--- main.cc
|
+--- math/
|
+--- MathFunctions.cc
|
+--- MathFunctions.h
对于这种情况,需要分别在项目根目录 Demo3 和 math 目录里各编写一个 CMakeLists.txt 文件。为了方便,我们可以先将 math 目录里的文件编译成静态库再由 main 函数调用。根目录中的 CMakeLists.txt :
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo3)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 添加 math 子目录
add_subdirectory(math)
# 指定生成目标
add_executable(Demo main.cc)
# 添加链接库
target_link_libraries(Demo MathFunctions)
该文件添加了下面的内容: 第3行,使用命令 add_subdirectory
指明本项目包含一个子目录 math,这样 math 目录下的 CMakeLists.txt 文件和源代码也会被处理 。第6行,使用命令 target_link_libraries
指明可执行文件 main 需要连接一个名为 MathFunctions 的链接库 。子目录中的 CMakeLists.txt:
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)
# 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})
在该文件中使用命令 add_library
将 src 目录中的源文件编译为静态链接库。