从LevelDB CMakeFiles.txt开始学习CMake:C++项目构建系统入门

最近开始阅读LevelDB源码,希望通过源码理解一个优秀 C++ 项目的工程设计。当我打开LevelDB项目目录时,发现CMakeLists.txt几乎贯穿整个项目,但是我之前并没有怎么使用过CMake。CMakeLists.txt的内容让我有点无法理解。于是产生了几个问题:
- CMake是什么?
- 为什么C++项目需要CMake?
- CMake和Make有什么区别?
- CMakeLists.txt如何组织一个大型项目?
带着这些问题,开始学习CMake。
C++项目为什么需要构建系统?
假设我们有一个main.cpp文件:
|
|
编译:
|
|
非常简单。但随着项目变大,源码可能牵涉几十个甚至几百个文件。此时,如果再使用:
|
|
就不太方便且不可维护,最好能自动管理编译过程。
Make是什么?
最早出现的是Make。Make通过Makefile描述如何编译、文件依赖、编译顺序。例如:
|
|
执行:
|
|
就会生成可执行文件app。
Make解决了哪些文件需要重新编译的问题,假如我们只修改了math.cpp就只要重新编译math.cpp,而不是全部重新编译。
为什么不用Make?
不同平台我们使用的编译器可能不一样,比如在Linux下我们用的是gcc,Windows下用的是cl.exe,macOS下用的是clang,这就导致我们需要维护多个Makefile。
另外,项目可能有非常多的第三方依赖,手写非常麻烦。
CMake是什么?
CMake是生成构建文件的工具。
flowchart TD
A[CMakeLists.txt] --> B[CMake]
B --> C[Makefile]
C --> D[make]
D --> E[程序]
flowchart TD
A[CMakeLists.txt] --> B[CMake]
B --> C[Makefile]
C --> D[make]
D --> E[程序]
flowchart TD
A[CMakeLists.txt] --> B[CMake]
B --> C[Makefile]
C --> D[make]
D --> E[程序]
|
|
CMake不负责编译,真正编译的是gcc/clang/cl.exe。
第一个CMake项目
创建:
-
HelloCMake
- CMakeLists.txt
- main.cpp
main.cpp:
|
|
CMakeLists.txt:
|
|
构建:
|
|
生成了hello.exe。
理解CMake核心概念
Target
开始阅读LevelDB CMakeLists.txt时,最重要的概念是Target。CMake并不是告诉编译器执行哪些命令,而是描述项目有哪些构建目标,以及目标之间如何依赖。
例如:
|
|
创建了一个Target leveldb,它不是leveldb.cpp也不是leveldb文件夹,而是一个逻辑对象。这个Target可以有源文件、头文件路径、编译参数、链接依赖。最终生成leveldb.lib(Windows)或libleveldb.a(Linux)。
add_library
在LevelDB中:
|
|
表示创建一个名为leveldb的库目标。后续:
|
|
给它添加源码。
target_include_directories
target_include_directories告诉CMake头文件在哪里。
|
|
target_link_libraries
一个库通常不会孤立存在,target_link_libraries描述了模块之间如何链接。
例如:
|
|
表明LevelDB使用线程库。
PRIVATE和PUBLIC
flowchart TD
A[Application] --> B[LevelDB]
B --> C[Thread Library]
flowchart TD
A[Application] --> B[LevelDB]
B --> C[Thread Library]
flowchart TD
A[Application] --> B[LevelDB]
B --> C[Thread Library]
|
|
Application是否需要Thread Library?由关键字决定。
PRIVATE表示只属于当前Target,也就是Application不知道Thread Library。
PUBLIC表示自己需要,同时暴露给使用者。
例如:
|
|
表示使用LevelDB的程序,也需要这个头文件目录。
find_package
大型项目不会写C:\xxx\pthread.lib, 而是:
|
|
让CMake自动寻找,成功后Threads::Threads就是一个Target。
然后:
|
|
add_subdirectory
大型项目通常每个模块都有自己的CMakeLists.txt,主文件add_subdirectory表示继续处理子模块。
例如:
|
|
推荐
Learn Makefiles With the tastiest examples
CMake: The Comprehensive Guide to Managing and Building C++ Projects (From Basics to Mastery)
相关内容
支付宝
微信