Cmake
除了源文件之外,还需要向CMake提供项目配置描述。必须把CMake指令放入一个名为CMakeLists.txt
的文件中,CMake才能够解析。
CMake
是一个构建系统生成器,描述构建系统应当如何操作才能编译代码,GNU/Linux上,CMake
默认生成Unix Makefile来构建项目:
Makefile
:make
将运行指令来构建项目。CMakefile
:包含临时文件的目录,CMake用于检测操作系统、编译器等。此外,根据所选的生成器,它还包含特定的文件。cmake_install.cmake
:处理安装规则的CMake脚本,在项目安装时使用。CMakeCache.txt
:如文件名所示,CMake缓存。CMake在重新运行配置时使用这个文件。
Cmakelists.txt
编译工程:
mkdir build && cd build
cmake -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang .. && make
- 第一行,设置CMake所需的最低版本。
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
- 第二行,声明项目的名称(
project-01
)和支持的编程语言(CXX代表C++):
project(project-01 LANGUAGES CXX)
C++
版本的定义
set(CMAKE_CXX_STANDARD 11)
- 检测外部库和程序:
find_package
是用于发现和设置包的CMake
模块(CMake
命令,用于标识系统标准位置中的包)的命令,当调用find_package(<name>)
时,模块中的命令将会运行。
find_package(PythonInterp 2.7)
- 指示CMake创建一个新目标:可执行文件
hello-world
。这个可执行文件是通过编译和链接源文件hello-world.cpp
生成的。CMake将为编译器使用默认设置,并自动选择生成工具:
add_executable(hello-world hello-world.cpp)
- 添加头文件搜索路径
- 为所有目标添加头文件搜索路径:将指定目录添加到编译器的头文件搜索路径之下,指定的目录被解释成当前源码路径的相对路径。
- 为指定目标(
target
)添加头文件搜索路径:指定目标是指通过add_executable()
,add_library()
命令生成的目标
// 为所有目标添加头文件搜索路径
include_directories(sub_dir) # 注意当前CMakeLists.txt和sub_dir相对路径关系
include_directories(${PROJECT_SOURCE_DIR}/sub_dir) # 通过源码根目录来定位sub_dir
// 为指定目标(`target`)添加头文件搜索路径
target_include_directories(projectA ./include1) # 注意相对路径关系
add_executable(projectA main.cpp)
include_directories
会为当前CMakeLists.tx
t的所有目标,以及之后添加的所有子目录的目标添加头文件搜索路径。target_include_directories
只会为指定目标包含头文件搜索路径。如果想为不同目标设置不同的搜索路径,那么用target_include_directories
更合适。
- 添加源文件
aux_source_directory(< dir > < variable >)
// 搜集所有在指定路径下的源文件的文件名,并将输出结果列表储存在指定的变量中。
- 添加一个子目录并构建该子目录
add_subdirectory (sub_dir)
构建和链接静态库和动态库
- 创建目标库,库的名称和源码文件名相同,具体代码如下:
add_library(message
STATIC
Message.hpp
Message.cpp
)
- STATIC:用于创建静态库,即编译文件的打包存档,以便在链接其他目标时使用,例如:可执行文件。
- SHARED:用于创建动态库,即可以动态链接,并在运行时加载的库。可以在
CMakeLists.txt
中使用add_library(message SHARED Message.hpp Message.cpp)
从静态库切换到动态共享对象(DSO)。 - OBJECT:可将给定
add_library
的列表中的源码编译到目标文件,不将它们归档到静态库中,也不能将它们链接到共享对象中。如果需要一次性创建静态库和动态库,那么使用对象库尤其有用。 - MODULE:又为DSO组。与
SHARED
库不同,它们不链接到项目中的任何目标,不过可以进行动态加载。该参数可以用于构建运行时插件。
- 创建
hello-world
可执行文件的目标部分不需要修改: - 将目标库链接到可执行目标:
target_link_libraries(hello-world message)
条件编译
- 引入逻辑变量
USE_LIBRARY
,值为OFF
。
set(USE_LIBRARY OFF)
//打印逻辑变量值
message(STATUS "Compile sources into a library? ${USE_LIBRARY}")
- 引入一个基于
USE_LIBRARY
值的if-else
语句
//引入变量_sources,包括Message.hpp和Message.cpp
list(APPEND _sources Message.hpp Message.cpp)
if(USE_LIBRARY)
add_library(message ${_sources})
add_executable(hello-world hello-world.cpp)
target_link_libraries(hello-world message)
else()
add_executable(hello-world hello-world.cpp ${_sources})
endif()
Python库
有两种方式可以将解释语言(如Python)与编译语言(如C或C++)组合在一起使用。
- 扩展Python,通过编译成共享库的C或C++模块在这些类型上提供新类型和新功能。
- 将Python解释器嵌入到C或C++程序中。
#include <Python.h>
int main(int argc, char *argv[]) {
Py_SetProgramName(argv[0]); /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print 'Today is',ctime(time())\n");
Py_Finalize();
return 0;
}
//找到Python解释器
find_package(PythonInterp REQUIRED)
//通过(FindPythonLibs.cmake模块)找到Python头文件和库
find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT REQUIRED)
//可执行文件包含Python.h头文件,这个目标的include目录必须包含Python的include目录
target_include_directories(c++-embedded-python
PRIVATE
PYTHON_INCLUDE_DIRS}
)
//将可执行文件链接到Python库
target_link_libraries(c++-embedded-python
PRIVATE
${PYTHON_LIBRARIES}
)
Makefile
-
变量定义
一般是字符串,规则类似宏。var=var1
,使用:$(var)
-
Makefile编写规则
目标文件:依赖文件
命令1
命令2
...
命令n