0voice-1.4.1-cmake
CMake介绍
- 上一节讲了
Makefile, 它和CMake的关系? CMake就像一个高级的“项目配置工具”,你告诉它你的项目有哪些源文件、需要什么库、如何编译等。然后,CMake会根据你的操作系统和你想使用的构建系统(比如make或Visual \ Studio),自动为你生成对应的“施工图纸”(Makefile或.sln/.vcxproj)。最后,你再使用这些“图纸”来实际“施工”(即运行make命令或在Visual Studio中构建项目)。
单个文件目录实现
CMake在查找项目构建定义时,会默认且只查找名为CMakeLists.txt的文件 (注意文件尾部有个s) 。- 每个
CMake项目的根目录都必须包含一个名为CMakeLists.txt的文件。这是CMake开始解析项目构建规则的入口点 。
1 # 单个目录实现
2 # CMake 最低版本号要求
3 cmake_minimum_required (VERSION 2.8)
4 # 工程,他不是执行文件名
5 PROJECT(0voice)
6 # 手动加入文件 ${变量名},比如${SRC_LIST}
7 SET(SRC_LIST main.c)
8 SET(SRC_LIST2 main2.c)
9 # MESSAGE和echo类似
10 MESSAGE(STATUS "THIS IS BINARY DIR " ${PROJECT_BINARY_DIR})
11 MESSAGE(STATUS "THIS IS SOURCE DIR " ${PROJECT_SOURCE_DIR})
12
13 # 生产执行文件名0voice 0voice2
14 ADD_EXECUTABLE(0voice ${SRC_LIST})
15 ADD_EXECUTABLE(0voice2 ${SRC_LIST2})
cmake关键字的大小写没有影响。SET(SRC_LIST main.c)类似于Makefile中的SRC_LIST = main.c,就是变量名赋值。PROJECT_BINARY_DIR( 顶层运行cmake命令时的绝对路径 ) 、PROJECT_SOURCE_DIR( 顶层CMakeLists.txt的绝对路径 ) 。- 先创建一个
build文件夹,在这文件夹下cmake ..( 原因是CMakeLists在上一级目录),这样子cmake产生的过程文件就在build下。 ( 最好每次手动创建一个 )。 - 执行
cmake ..,最大的感受就是创建一个复杂的Makefile文件,包含了所有编译和链接规则、依赖关系、路径和变量。所有的细节都是CMake根据简洁的CMakeLists.txt文件( 只写了add_executable(0voice main.c)和add_executable(0voice2 main2.c)这样的命令)自动推导并生成的。
拿上一个 Makefile 举例
.PHONY: main clean
simple: main.o foo.o
@echo "simple: main.o foo.o"
gcc -o simple main.o foo.o
main.o: main.c
@echo "gcc -o main.o -c main.c"
gcc -o main.o -c main.c
foo.o: foo.c
@echo "gcc -o foo.o -c foo.c"
gcc -o foo.o -c foo.c
clean:
rm simple main.o foo.o
等价于 cmake 中的 add_executable(simple main.c foo.c),执行后会自动帮你生成。
- 源代码更加复杂的依赖关系,则需要其他语法解决。
- 简单的、单目录项目,在源文件下放一个
CMakeLists.txt即可。
my_simple_project/
├── CMakeLists.txt
├── main.c
└── foo.c
单个文件目录实现 2
- 目录结构
.
├── build/
├── CMakeLists.txt
├── doc/
│ ├── darren.txt
│ └── README.MD
└── src/
├── CMakeLists.txt
└── main.c
- 顶层
CMakeLists.txt
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
PROJECT(0VOICE)
MESSAGE(STATUS "0voice top PROJECT_BINARY_DIR " "${PROJECT_BINARY_DIR}")
MESSAGE(STATUS "0voice top PROJECT_SOURCE_DIR " "${PROJECT_SOURCE_DIR}")
# CMAKE_CURRENT_SOURCE_DIR它的CMakeLists.txt所在的当前源目
MESSAGE(STATUS "0voice top CMAKE_CURRENT_SOURCE_DIR " "${CMAKE_CURRENT_SOURCE_DIR}")
# 添加子目录
ADD_SUBDIRECTORY(src)
#INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/0voice)
# 安装doc到 share/doc/cmake/0voice目录
# 默认/usr/local/
# 指定自定义目录, 比如 cmake -DCMAKE_INSTALL_PREFIX=/tmp/usr ..
INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake/0voice)
src中的CMakeLists.txt
# 单个目录实现
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 工程
# PROJECT(0VOICE)
# 手动加入文件
SET(SRC_LIST main.c)
MESSAGE(STATUS "0voice sub PROJECT_BINARY_DIR" ${PROJECT_BINARY_DIR})
MESSAGE(STATUS "0voice sub PROJECT_SOURCE_DIR" ${PROJECT_SOURCE_DIR})
# CMAKE_CURRENT_SOURCE_DIR它的CMakeLists.txt所在的当前源目
MESSAGE(STATUS "0voice sub CMAKE_CURRENT_SOURCE_DIR " ${CMAKE_CURRENT_SOURCE_DIR})
ADD_EXECUTABLE(youzi ${SRC_LIST})
# 演示
ADD_EXECUTABLE(youzi2 ${SRC_LIST})
# 将执行文件安装到bin目录
# 默认/usr/local/
#指定自定义目录,比如 cmake -DCMAKE_INSTALL_PREFIX=/tmp/usr ..
INSTALL(TARGETS youzi RUNTIME DESTINATION bin)
INSTALL(TARGETS youzi2 RUNTIME DESTINATION bin)
ADD_SUBDIRECTORY(src):CMake会进入src目录,读取并执行src/CMakeLists.txt中的命令。这使得项目可以模块化,将不同部分的构建逻辑放在各自的子目录中。CMAKE_CURRENT_SOURCE_DIR:CMake命名执行的当前目录。INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake/0voice):- 针对文件本身。
DIRECTORY关键字表示你要安装一个目录。DESTINATION关键字指定了安装的目标路径。
INSTALL(TARGETS youzi2 RUNTIME DESTINATION bin):TARGETS关键字表示你要安装一个或多个CMake目标。youzi2是你要安装的目标名称。这个目标必须在之前的CMakeLists.txt中通过add_executable(youzi2 ...)或add_library(youzi2 ...)定义过。RUNTIME: 关键字特指可执行文件。虽然youzi2本来就是可执行文件,但这里也要说明,因为target也能指定其他类型的文件。
多个目录实现 - 子目录编译成库文件
- 文件结构
.
├── CMakeLists.txt # 根目录的 CMakeLists.txt
├── doc # 文档目录
│ ├── darren.txt
│ └── README.MD
└── src # 源代码主目录
├── CMakeLists.txt # src 目录的 CMakeLists.txt
├── dir1 # 子模块1目录
│ ├── CMakeLists.txt # dir1 目录的 CMakeLists.txt
│ ├── dir1.c
│ └── dir1.h
├── dir2 # 子模块2目录
│ ├── CMakeLists.txt # dir2 目录的 CMakeLists.txt
│ ├── dir2.c
│ └── dir2.h
└── main.c # 主程序的源文件
-
INCLUDE_DIRECTORIES当项目变得复杂的时候,并且一个源文件需要包含位于其自身目录之外的自定义头文件时,需要用到
INCLUDE_DIRECTORIES。语法:
INCLUDE_DIRECTORIES("xxx") -
ADD_LIBRARYADD_LIBRARY( hello_shared SHARED libHelloSLAM.cpp ) 生成动态库 ADD_LIBRARY( hello_shared STATIC libHelloSLAM.cpp ) 生成静态库- 对于库文件的理解:一个库(无论是静态库
.a/.lib还是动态库.so/.dll)的本质是编译好的二进制代码,这些代码包含了函数的定义和变量的定义。.cpp完成对函数和变量的定义,生成目标文件.o, 链接器会把.o打包成库 。 - 静态库的标准命名约定是
lib前缀,.a后缀。动态库的标准命名约定是lib前缀,.so后缀 (lib+ 库名 +.a\.so, 前后缀自动生成)。 - 静态库:链接器将库中的机器码复制到应用程序的可执行文件中,运行时就独立。
- 动态库:链接器在应用程序可执行文件中只写入对动态库中函数的引用(符号信息),而不是实际机器码,运行时,操作系统加载器找到并加载动态库文件到内存,然后将应用程序中的引用解析为内存中动态库里实际机器码的地址
hello_shared是库的名字 ,SHARED和STATIC区分动\静态
- 对于库文件的理解:一个库(无论是静态库
-
TARGET_LINK_LIBRARIES- 链接库到执行文件上
TARGET_LINK_LIBRARIES(darren dir1 dir2) -
build- 在
build目录下生成一个与源文件目录结构平行的目录结构,用于存放所有生成的构建文件 。 - 在顶层目录
build使用make, 是能够调用其下子文件夹下的Makefile的 。
- 在
make指令尝试构建Makefile中定义的默认目标,install指令在CMakeLists.txt中定义的是一个独立的构建目标。CMake会在生成的Makefile中创建一个名为install的目标。也就是说make启动不了CMakeLists.txt里面的安装指令。

浙公网安备 33010602011771号