CMake入门
CMake
简介
CMake
是一个跨平台的构建系统生成工具,用于管理编译过程,其主要功能如下:
- 通过读取配置文件(
CMakeLists.txt
) - 生成特定于平台的构建文件(如
Makefile
或 Visual Studio 工程文件); - 帮助用户管理项目的依赖关系、编译流程等;
也就是说CMake
是一套交叉编译的工具链,通过CMake
我们可以更好地管理项目结构;
CMake
相比于传统的构建工具(如直接编写 Makefile
),具有以下几个核心特性:
-
跨平台:CMake 支持多个平台(如
Windows
、Linux
、macOS
)和编译器(GCC
、Clang
、MSVC
等),通过生成平台特定的构建系统文件,能够帮助开发者更轻松地在不同平台上编译项目。 -
依赖管理:
CMake
能够自动检测并配置项目的依赖库,确保在编译过程中正确地链接外部库。例如,它可以通过find_package
指令查找和配置第三方库。 -
增量编译:
CMake
支持增量编译机制。当源代码部分更新时,它只会重新编译受影响的部分,减少不必要的编译时间。 -
模块化与可扩展性:
CMake
允许用户编写模块和脚本,用于管理更复杂的项目结构。它提供了丰富的指令集来配置编译流程,并且可以通过编写自定义的模块扩展其功能。 -
可集成性:
CMake
可以生成多种构建工具的配置文件,支持不同的 IDE 和构建系统;
C++工程目录设计最佳实践
一个典型的 C++ 项目目录结构应该具有清晰的分层,常见的目录和文件如下:
/project-root
├── CMakeLists.txt # 项目的主 CMake 配置文件
├── src/ # 源文件目录
│ ├── main.cpp # 主程序入口
│ ├── module1.cpp # 模块1的源文件
│ ├── module2.cpp # 模块2的源文件
├── include/ # 公共头文件目录
│ ├── module1.h # 模块1的头文件
│ ├── module2.h # 模块2的头文件
├── lib/ # 外部库(静态或动态库)存放目录
├── bin/ # 存放二进制文件
├── tests/ # 测试代码
│ ├── CMakeLists.txt # 测试目录的 CMake 文件
│ ├── test_module1.cpp # 测试模块1的单元测试
├── examples/ # 示例代码
├── docs/ # 文档(用户指南、API 文档等)
├── build/ # 构建生成目录(通常不放入源码控制系统中)
├── scripts/ # 构建、部署、运行等自动化脚本
├── README.md # 项目说明文件
└── LICENSE # 项目许可证
除此之外,仍有一些细节需要注意:
-
src/
和include/
目录分离-
src/
中应该存放项目的.cpp
、.c
文件,即项目的具体实现代码。 -
include/
则存放公共的.h
、.hpp
文件,这些头文件定义了接口,并且其他项目或模块可以包含这些头文件。 -
使用这种分离策略有助于清晰地定义哪些文件是实现细节,哪些文件是对外暴露的接口;
-
注意在头文件中不要
using namespace std;
;
-
-
模块化管理
-
对于中大型项目,将代码划分为多个逻辑模块或库会使项目更具可维护性和可扩展性;
-
每个模块通常有自己的源文件和头文件;
-
每个模块应该尽量自包含,模块的头文件和实现文件可以放在各自的子目录下,例如:
/project-root ├── src/ │ ├── module1/ │ │ ├── module1.cpp │ │ └── CMakeLists.txt │ ├── module2/ │ │ ├── module2.cpp │ │ └── CMakeLists.txt ├── include/ │ ├── module1/ │ │ └── module1.h │ ├── module2/ │ │ └── module2.h
-
-
依赖管理
lib/
目录:推荐通过自动化脚本或包管理工具自动下载和构建依赖,而非手动放入外部库的二进制文件;third_party/
目录:将外部依赖源代码放在third_party/
目录中,并使用CMake
或其他工具集成;
-
测试目录结构
tests/
目录应该用于存放所有的测试代码;- 推荐使用与项目主目录相同的模块化结构,保证测试代码清晰、独立,方便集成到 CI/CD 流程中
-
文档目录
docs/
目录用于存放项目的文档资料,文档可以包含项目概述、API 文档、使用指南、开发者指南等。- 推荐使用
Doxygen
并将其保存在此目录中;
-
构建输出目录
build/
** 目录用于存放项目的构建输出文件(如中间文件、可执行文件等)。- 为了避免污染源码目录,建议将构建生成的文件放入单独的
build/
目录中,并将此目录加入.gitignore
中,防止其被加入版本控制;
-
使用脚本自动化流程
scripts/
目录可以用于存放一些常用的自动化脚本,如构建、清理、测试、打包、发布等脚本。- 通常包括
build.sh, test.sh, deploy.sh
CMake
基本编译原理
CMake
的编译过程可以分为几个主要步骤:
-
配置阶段:
- 读取
CMakeLists.txt
文件:CMake
通过解析项目中的CMakeLists.txt
文件来获取项目信息(源文件、依赖库、编译选项等);
- 生成构建系统:
- ``CMake
解析
CMakeLists.txt` 后,基于当前平台和用户指定的生成器生成特定的构建系统文件这些生成的文件控制项目的编译流程;
- ``CMake
- 读取
-
生成阶段:
CMake
根据配置阶段的结果,生成构建文件(如IDE
工程文件),详细描述了如何从源代码生成目标文件;CMake
不直接编译代码,而是通过生成的构建系统文件调用具体的编译工具链来进行编译。
-
编译阶段:
- 用户运行生成的构建系统(例如执行
make
命令),调用编译器编译源代码,生成目标文件(如.o
文件)。 - 链接目标文件,生成最终的可执行文件或库文件(如
.exe
或.so/.dll
文件)。
- 用户运行生成的构建系统(例如执行
简要来说,如果我的项目遵循上述的最佳实践的话,可以通过一个文件编写两条命令实现:
- 编写
CMakeLists.txt
; cmake .
cmake --build .
CMakeLists.txt
编写原则
-
模块化:
- 将项目配置划分为多个
CMake
文件; - 使用变量来避免重复代码,并通过函数/宏封装复杂的操作。
- 将项目配置划分为多个
-
指定最低版本要求
- 每个项目的
CMakeLists.txt
中明确指定所需的最低 CMake 版本;
- 每个项目的
-
项目声明
- 定义项目名称和相关语言
-
管理编译选项:
- 设置编译器选项:通过
target_compile_options()
为目标指定编译器选项,而不是使用全局变量CMAKE_CXX_FLAGS
,这样可以避免全局配置导致的不必要副作用。 - 使用
CMAKE_BUILD_TYPE
:通过CMAKE_BUILD_TYPE
设置构建模式(如Debug
或Release
)。在实际项目中,建议允许用户在命令行中指定,而非硬编码在CMakeLists.txt
中;
- 设置编译器选项:通过
-
处理依赖项:
- 如果项目依赖于外部库,使用
find_package()
查找库,并根据需要设置是否强制要求该库; - 对于一些外部库,可以使用
FetchContent
下载和构建它们,避免手动配置;
- 如果项目依赖于外部库,使用
-
管理源文件
- 将源文件列表集中管理,并根据项目结构清晰划分。例如,可以将源文件分组,并使用
file()
或变量存储文件路径;
- 将源文件列表集中管理,并根据项目结构清晰划分。例如,可以将源文件分组,并使用
-
启用自动化测试:
- 建议为项目配置测试框架,并使用 CMake 的
enable_testing()
和add_test()
来集成测试
- 建议为项目配置测试框架,并使用 CMake 的
-
多平台支持:
-
检查系统特性:使用
if()
检查不同的平台或编译器选项,并在CMakeLists.txt
中做出适应性调整。 -
设置跨平台编译选项:使用
target_compile_options()
和target_link_libraries()
管理特定平台的编译选项;
-
-
支持安装和打包:
- 为了方便部署项目,可以在
CMakeLists.txt
中配置安装和打包规则。使用install()
命令设置如何将生成的可执行文件、库和其他资源安装到系统路径;
- 为了方便部署项目,可以在
CMakeLists.txt
配置具体含义
指定CMake
的最低版本
cmake_minimum_required(VERSION 3.15)
项目命名
project(MyDraft)
指定C++标准
set(CMAKE_CXX_STANDARD 20)
设置编译器路径
set(CMAKE_C_COMPILER "/usr/bin/gcc")
set(CMAKE_CXX_COMPILER "/usr/bin/g++")
确保它们只在项目第一次运行时配置, 避免重复配置,或者即使清除CMake
缓存;
设置源文件目录
file(GLOB SRC_LIST "${PROJECT_SOURCE_DIR}/src/tb/*.cpp")
添加头文件路径
include_directories(include)
生成目标可执行文件
add_executable(tb ${SRC_LIST})
外部库的引用
fmt库
从 CMake 3.11 开始,可以使用 FetchContent 自动 在 configure 时下载 {fmt} 作为依赖项:
include(FetchContent)
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt
GIT_TAG e69e5f977d458f2650bb346dadf2ad30c5320281) # 10.2.1
FetchContent_MakeAvailable(fmt)
target_link_libraries(<your-target> fmt::fmt)
注意<your-target>
应填写可执行文件的名称
- 在编译的最后一步,链接器会把编译后的目标文件(即
.o
文件或.obj
文件)与所依赖的外部库(如静态库.a
文件或动态库.so
/.dll
文件)链接在一起,生成最终的可执行文件。因此,target
通常是这个最终生成的可执行文件的名称; - 如果项目中包含多个不同的可执行文件,每个可执行文件可能会依赖不同的库。在这种情况下,你可以为每个目标定义一个不同的
target
,以便生成多个不同的可执行文件;
在头文件内加入
注意
相对路径问题
通常,工作目录是在命令行中运行可执行文件的地方;
如果设置bin/
为输出目录,那么需要一个上级目录..
才能回到项目根目录;
对于头文件的相对路径,通常会设置include_directories(include)
,直接引用对应模块即可;
示例
以下是一个CMakeLists.txt
# 指定`CMake`的最低版本
cmake_minimum_required(VERSION 3.15)
# 项目命名
project(MyDraft)
# 指定 C++ 标准
set(CMAKE_CXX_STANDARD 20)
# 设置编译器路径
# set(CMAKE_C_COMPILER "/usr/bin/gcc")
# set(CMAKE_CXX_COMPILER "/usr/bin/g++")
# 设置可执行文件的输出目录
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/bin")
# 添加头文件路径
include_directories(include)
# 设置源文件目录
file(GLOB SRC_LIST "${PROJECT_SOURCE_DIR}/src/hello/*.cpp")
# 生成目标可执行文件
add_executable(hello ${SRC_LIST})
# 引入外部库
include(FetchContent)
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt
GIT_TAG e69e5f977d458f2650bb346dadf2ad30c5320281) # 10.2.1
FetchContent_MakeAvailable(fmt)
target_link_libraries(hello fmt::fmt)
我的目录树如下:
.MyCMake
├── bin
│ └── hello
├── build
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ │ ├── 3.30.3
│ │ │ ├── CMakeCCompiler.cmake
│ │ │ ├── CMakeCXXCompiler.cmake
│ │ │ ├── CMakeDetermineCompilerABI_C.bin
│ │ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ │ ├── CMakeSystem.cmake
│ │ │ ├── CompilerIdC
│ │ │ │ ├── a.out
│ │ │ │ ├── CMakeCCompilerId.c
│ │ │ │ └── tmp
│ │ │ └── CompilerIdCXX
│ │ │ ├── a.out
│ │ │ ├── CMakeCXXCompilerId.cpp
│ │ │ └── tmp
│ │ ├── cmake.check_cache
│ │ ├── CMakeConfigureLog.yaml
│ │ ├── CMakeDirectoryInformation.cmake
│ │ ├── CMakeScratch
│ │ ├── hello.dir
│ │ │ ├── build.make
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── compiler_depend.make
│ │ │ ├── compiler_depend.ts
│ │ │ ├── DependInfo.cmake
│ │ │ ├── depend.make
│ │ │ ├── flags.make
│ │ │ ├── link.txt
│ │ │ ├── progress.make
│ │ │ └── src
│ │ │ └── hello
│ │ │ ├── hello.cpp.o
│ │ │ └── hello.cpp.o.d
│ │ ├── Makefile2
│ │ ├── Makefile.cmake
│ │ ├── pkgRedirects
│ │ ├── progress.marks
│ │ └── TargetDirectories.txt
│ ├── cmake_install.cmake
│ ├── _deps
│ │ ├── fmt-build
│ │ │ ├── CMakeFiles
│ │ │ │ ├── CMakeDirectoryInformation.cmake
│ │ │ │ ├── Export
│ │ │ │ │ └── b834597d9b1628ff12ae4314c3a2e4b8
│ │ │ │ │ ├── fmt-targets.cmake
│ │ │ │ │ └── fmt-targets-noconfig.cmake
│ │ │ │ ├── fmt.dir
│ │ │ │ │ ├── build.make
│ │ │ │ │ ├── cmake_clean.cmake
│ │ │ │ │ ├── cmake_clean_target.cmake
│ │ │ │ │ ├── compiler_depend.make
│ │ │ │ │ ├── compiler_depend.ts
│ │ │ │ │ ├── DependInfo.cmake
│ │ │ │ │ ├── depend.make
│ │ │ │ │ ├── flags.make
│ │ │ │ │ ├── link.txt
│ │ │ │ │ ├── progress.make
│ │ │ │ │ └── src
│ │ │ │ │ ├── format.cc.o
│ │ │ │ │ ├── format.cc.o.d
│ │ │ │ │ ├── os.cc.o
│ │ │ │ │ └── os.cc.o.d
│ │ │ │ └── progress.marks
│ │ │ ├── cmake_install.cmake
│ │ │ ├── fmt-config.cmake
│ │ │ ├── fmt-config-version.cmake
│ │ │ ├── fmt.pc
│ │ │ ├── fmt-targets.cmake
│ │ │ ├── libfmt.a
│ │ │ └── Makefile
│ │ ├── fmt-src
│ │ │ ├── ChangeLog.md
│ │ │ ├── CMakeLists.txt
│ │ │ ├── CONTRIBUTING.md
│ │ │ ├── doc
│ │ │ │ ├── api.rst
│ │ │ │ ├── basic-bootstrap
│ │ │ │ │ ├── layout.html
│ │ │ │ │ ├── README
│ │ │ │ │ └── theme.conf
│ │ │ │ ├── bootstrap
│ │ │ │ │ ├── alerts.less
│ │ │ │ │ ├── badges.less
│ │ │ │ │ ├── bootstrap.less
│ │ │ │ │ ├── breadcrumbs.less
│ │ │ │ │ ├── button-groups.less
│ │ │ │ │ ├── buttons.less
│ │ │ │ │ ├── carousel.less
│ │ │ │ │ ├── close.less
│ │ │ │ │ ├── code.less
│ │ │ │ │ ├── component-animations.less
│ │ │ │ │ ├── dropdowns.less
│ │ │ │ │ ├── forms.less
│ │ │ │ │ ├── glyphicons.less
│ │ │ │ │ ├── grid.less
│ │ │ │ │ ├── input-groups.less
│ │ │ │ │ ├── jumbotron.less
│ │ │ │ │ ├── labels.less
│ │ │ │ │ ├── list-group.less
│ │ │ │ │ ├── media.less
│ │ │ │ │ ├── mixins
│ │ │ │ │ │ ├── alerts.less
│ │ │ │ │ │ ├── background-variant.less
│ │ │ │ │ │ ├── border-radius.less
│ │ │ │ │ │ ├── buttons.less
│ │ │ │ │ │ ├── center-block.less
│ │ │ │ │ │ ├── clearfix.less
│ │ │ │ │ │ ├── forms.less
│ │ │ │ │ │ ├── gradients.less
│ │ │ │ │ │ ├── grid-framework.less
│ │ │ │ │ │ ├── grid.less
│ │ │ │ │ │ ├── hide-text.less
│ │ │ │ │ │ ├── image.less
│ │ │ │ │ │ ├── labels.less
│ │ │ │ │ │ ├── list-group.less
│ │ │ │ │ │ ├── nav-divider.less
│ │ │ │ │ │ ├── nav-vertical-align.less
│ │ │ │ │ │ ├── opacity.less
│ │ │ │ │ │ ├── pagination.less
│ │ │ │ │ │ ├── panels.less
│ │ │ │ │ │ ├── progress-bar.less
│ │ │ │ │ │ ├── reset-filter.less
│ │ │ │ │ │ ├── resize.less
│ │ │ │ │ │ ├── responsive-visibility.less
│ │ │ │ │ │ ├── size.less
│ │ │ │ │ │ ├── tab-focus.less
│ │ │ │ │ │ ├── table-row.less
│ │ │ │ │ │ ├── text-emphasis.less
│ │ │ │ │ │ ├── text-overflow.less
│ │ │ │ │ │ └── vendor-prefixes.less
│ │ │ │ │ ├── mixins.less
│ │ │ │ │ ├── modals.less
│ │ │ │ │ ├── navbar.less
│ │ │ │ │ ├── navs.less
│ │ │ │ │ ├── normalize.less
│ │ │ │ │ ├── pager.less
│ │ │ │ │ ├── pagination.less
│ │ │ │ │ ├── panels.less
│ │ │ │ │ ├── popovers.less
│ │ │ │ │ ├── print.less
│ │ │ │ │ ├── progress-bars.less
│ │ │ │ │ ├── responsive-embed.less
│ │ │ │ │ ├── responsive-utilities.less
│ │ │ │ │ ├── scaffolding.less
│ │ │ │ │ ├── tables.less
│ │ │ │ │ ├── theme.less
│ │ │ │ │ ├── thumbnails.less
│ │ │ │ │ ├── tooltip.less
│ │ │ │ │ ├── type.less
│ │ │ │ │ ├── utilities.less
│ │ │ │ │ ├── variables.less
│ │ │ │ │ └── wells.less
│ │ │ │ ├── build.py
│ │ │ │ ├── CMakeLists.txt
│ │ │ │ ├── conf.py
│ │ │ │ ├── contents.rst
│ │ │ │ ├── fmt.less
│ │ │ │ ├── index.rst
│ │ │ │ ├── python-license.txt
│ │ │ │ ├── _static
│ │ │ │ │ ├── bootstrap.min.js
│ │ │ │ │ ├── breathe.css
│ │ │ │ │ └── fonts
│ │ │ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ │ │ ├── glyphicons-halflings-regular.svg
│ │ │ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ │ │ └── glyphicons-halflings-regular.woff
│ │ │ │ ├── syntax.rst
│ │ │ │ ├── _templates
│ │ │ │ │ ├── layout.html
│ │ │ │ │ └── search.html
│ │ │ │ └── usage.rst
│ │ │ ├── include
│ │ │ │ └── fmt
│ │ │ │ ├── args.h
│ │ │ │ ├── chrono.h
│ │ │ │ ├── color.h
│ │ │ │ ├── compile.h
│ │ │ │ ├── core.h
│ │ │ │ ├── format.h
│ │ │ │ ├── format-inl.h
│ │ │ │ ├── os.h
│ │ │ │ ├── ostream.h
│ │ │ │ ├── printf.h
│ │ │ │ ├── ranges.h
│ │ │ │ ├── std.h
│ │ │ │ └── xchar.h
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── src
│ │ │ │ ├── fmt.cc
│ │ │ │ ├── format.cc
│ │ │ │ └── os.cc
│ │ │ ├── support
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ ├── Android.mk
│ │ │ │ ├── bazel
│ │ │ │ │ ├── BUILD.bazel
│ │ │ │ │ ├── README.md
│ │ │ │ │ └── WORKSPACE.bazel
│ │ │ │ ├── build-docs.py
│ │ │ │ ├── build.gradle
│ │ │ │ ├── cmake
│ │ │ │ │ ├── FindSetEnv.cmake
│ │ │ │ │ ├── fmt-config.cmake.in
│ │ │ │ │ ├── fmt.pc.in
│ │ │ │ │ └── JoinPaths.cmake
│ │ │ │ ├── compute-powers.py
│ │ │ │ ├── C++.sublime-syntax
│ │ │ │ ├── docopt.py
│ │ │ │ ├── manage.py
│ │ │ │ ├── printable.py
│ │ │ │ ├── README
│ │ │ │ ├── rtd
│ │ │ │ │ ├── conf.py
│ │ │ │ │ ├── index.rst
│ │ │ │ │ └── theme
│ │ │ │ │ ├── layout.html
│ │ │ │ │ └── theme.conf
│ │ │ │ └── Vagrantfile
│ │ │ └── test
│ │ │ ├── add-subdirectory-test
│ │ │ │ ├── CMakeLists.txt
│ │ │ │ └── main.cc
│ │ │ ├── args-test.cc
│ │ │ ├── assert-test.cc
│ │ │ ├── chrono-test.cc
│ │ │ ├── CMakeLists.txt
│ │ │ ├── color-test.cc
│ │ │ ├── compile-error-test
│ │ │ │ └── CMakeLists.txt
│ │ │ ├── compile-fp-test.cc
│ │ │ ├── compile-test.cc
│ │ │ ├── core-test.cc
│ │ │ ├── cuda-test
│ │ │ │ ├── CMakeLists.txt
│ │ │ │ ├── cpp14.cc
│ │ │ │ └── cuda-cpp14.cu
│ │ │ ├── detect-stdfs.cc
│ │ │ ├── enforce-checks-test.cc
│ │ │ ├── find-package-test
│ │ │ │ ├── CMakeLists.txt
│ │ │ │ └── main.cc
│ │ │ ├── format-impl-test.cc
│ │ │ ├── format-test.cc
│ │ │ ├── fuzzing
│ │ │ │ ├── build.sh
│ │ │ │ ├── chrono-duration.cc
│ │ │ │ ├── chrono-timepoint.cc
│ │ │ │ ├── CMakeLists.txt
│ │ │ │ ├── float.cc
│ │ │ │ ├── fuzzer-common.h
│ │ │ │ ├── main.cc
│ │ │ │ ├── named-arg.cc
│ │ │ │ ├── one-arg.cc
│ │ │ │ ├── README.md
│ │ │ │ └── two-args.cc
│ │ │ ├── gtest
│ │ │ │ ├── CMakeLists.txt
│ │ │ │ ├── gmock
│ │ │ │ │ └── gmock.h
│ │ │ │ ├── gmock-gtest-all.cc
│ │ │ │ └── gtest
│ │ │ │ ├── gtest.h
│ │ │ │ └── gtest-spi.h
│ │ │ ├── gtest-extra.cc
│ │ │ ├── gtest-extra.h
│ │ │ ├── gtest-extra-test.cc
│ │ │ ├── header-only-test.cc
│ │ │ ├── mock-allocator.h
│ │ │ ├── module-test.cc
│ │ │ ├── noexception-test.cc
│ │ │ ├── os-test.cc
│ │ │ ├── ostream-test.cc
│ │ │ ├── posix-mock.h
│ │ │ ├── posix-mock-test.cc
│ │ │ ├── printf-test.cc
│ │ │ ├── ranges-odr-test.cc
│ │ │ ├── ranges-test.cc
│ │ │ ├── scan.h
│ │ │ ├── scan-test.cc
│ │ │ ├── static-export-test
│ │ │ │ ├── CMakeLists.txt
│ │ │ │ ├── library.cc
│ │ │ │ └── main.cc
│ │ │ ├── std-test.cc
│ │ │ ├── test-assert.h
│ │ │ ├── test-main.cc
│ │ │ ├── unicode-test.cc
│ │ │ ├── util.cc
│ │ │ ├── util.h
│ │ │ └── xchar-test.cc
│ │ └── fmt-subbuild
│ │ ├── CMakeCache.txt
│ │ ├── CMakeFiles
│ │ │ ├── 3.30.3
│ │ │ │ └── CMakeSystem.cmake
│ │ │ ├── cmake.check_cache
│ │ │ ├── CMakeConfigureLog.yaml
│ │ │ ├── CMakeDirectoryInformation.cmake
│ │ │ ├── CMakeRuleHashes.txt
│ │ │ ├── fmt-populate-complete
│ │ │ ├── fmt-populate.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── compiler_depend.make
│ │ │ │ ├── compiler_depend.ts
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── Labels.json
│ │ │ │ ├── Labels.txt
│ │ │ │ └── progress.make
│ │ │ ├── Makefile2
│ │ │ ├── Makefile.cmake
│ │ │ ├── pkgRedirects
│ │ │ ├── progress.marks
│ │ │ └── TargetDirectories.txt
│ │ ├── cmake_install.cmake
│ │ ├── CMakeLists.txt
│ │ ├── fmt-populate-prefix
│ │ │ ├── src
│ │ │ │ └── fmt-populate-stamp
│ │ │ │ ├── fmt-populate-build
│ │ │ │ ├── fmt-populate-configure
│ │ │ │ ├── fmt-populate-done
│ │ │ │ ├── fmt-populate-download
│ │ │ │ ├── fmt-populate-gitclone-lastrun.txt
│ │ │ │ ├── fmt-populate-gitinfo.txt
│ │ │ │ ├── fmt-populate-install
│ │ │ │ ├── fmt-populate-mkdir
│ │ │ │ ├── fmt-populate-patch
│ │ │ │ ├── fmt-populate-patch-info.txt
│ │ │ │ ├── fmt-populate-test
│ │ │ │ └── fmt-populate-update-info.txt
│ │ │ └── tmp
│ │ │ ├── fmt-populate-cfgcmd.txt
│ │ │ ├── fmt-populate-gitclone.cmake
│ │ │ ├── fmt-populate-gitupdate.cmake
│ │ │ └── fmt-populate-mkdirs.cmake
│ │ └── Makefile
│ └── Makefile
├── CMakeLists.txt
├── doc
│ └── CMake入门.md
├── include
│ └── hello
│ └── hello.hpp
├── lib
└── src
└── hello
└── hello.cpp
61 directories, 294 files
我编写了一个引用外部库fmt
输出hello,world
的程序src/hello/hello.cpp
:
# include "hello/hello.hpp"
void stdSayHello(int i){
while(i--) fmt::print("hello world_{}\n", i);
}
void fmtSayHello(int i){
while(i--) std::cout<< "hello world_"<<i<<std::endl;
}
int main(){
stdSayHello(3);
fmtSayHello(3);
}
在include/
中,头文件include/hello/hello.hpp
也很简单:
# include <iostream>
# define FMT_HEADER_ONLY // 推荐
# include "fmt/core.h"
cd build & cmake .. & cmake --build .
执行便在bin/
生成了可执行文件,这表明我们编译成功了!