入门CMake
参考教程: YouTube-Simplified CMake Tutorial, Codevion vimwiki-Modern Simple CMake Tutorial,本笔记所用的全部代码整合GitHub - cmake_tutorial.7z
CMake可以完成复杂项目的编译任务,编译一个C++项目可能需要:
- 一个包含
main()
的主程序入口;
- 多个联合编译
*.cpp
文件(对头文件各种声明的实现);
- 多个头文件
*.h
;
- 多个链接库
*.so
;
- 编译指令
-pthread, -O2, -O3
等。
下面我们将在VSCode上逐步完成这些功能,系统Ubuntu 22.04:
单个文件编译
首先我们创建一个空文件夹,里面写一个main.cpp
文件:
最简单的编译方法是在终端中使用g++
编译并运行起来
下面我们来用CMake实现这一操作,在和main.cpp
的同级目录下创建CMakeLists.txt
文件:
真正有用的就是一句话,给出了编译出的可执行文件名称,以及联合编译的cpp文件
执行CMake编译方法:
- VSCode插件:在VSCode中安装CMake, CMake Tools, CMake Highlight插件,按
ctrl+f5
就会弹出对g++编译器的选择,选择一个编译器即可,再按ctrl+f5
即可看到CMake创建了一个build
文件夹,在其中已经编译出了hi
可执行文件,下方打印出了我们代码的结果。(CMake会在右边打开Workbench side bar中显示输出信息,非常麻烦,我们可以把右侧边栏上方的输出图表拖到下方的panel面板中,这样就可以不用每次自动在右边显示啦)
- 终端:首先我们创建一个新文件夹
mkdir my_build
,进入该文件夹cd my_build
,执行cmake ..
即可看到创建了很多缓存文件,再执行make
开始编译,完成后会产生可执行文件hi
,运行./hi
即可。
添加头文件
在main.cpp
同级目录下创建include/
文件夹,里面创建include/bar.h
头文件:
我们在CMakeLists.txt
中add_executable(hi main.cpp)
下方加入
这里的PUBLIC
表示当前编译的目标对于头文件中内容的可见程度,有如下三个选项(这个一般只有在多层调用时会用到,一般写PUBLIC
就完了):
PRIVATE
:如果只有*.cpp
文件用到头文件中的内容;
INTERFACE
:如果只有*.h
文件用到头文件中的内容;
PUBLIC
:两者都用到。
修改完成CMakeLists.txt
后就可以对main.cpp
修改如下:
用ctrl+f5
编译运行了,但是我们发现vscode还是无法找到#include "bar.h"
头文件位置,需要手动添加下路径,ctrl+shift+p
输入c/c++ ui
进入C/C++:编辑配置(UI)
,找到包含路径中发现已经添加了${workspaceFolder}/**
,它就会自动递归寻找工作路径下的头文件了(如果不在本工作路径下的,需要手动添加哦)
添加库文件
手动创建库文件
我们新创建一个文件夹bar/
,将刚才写的include/bar.h
文件放到该文件夹下,并创建一个bar/bar.cpp
文件用来定义其中声明的函数,文件结构如下:
每个文件内容如下
bar.cpp
bar.h
main.cpp
我们需要将bar/
文件夹下的内容作为一个整体编译成一个.so
或.a
连接文件用于main.cpp
的链接,所以在该目录下也需要一个bar/CMakeLists.txt
:
这样我们就可以在编译main.cpp
时调用生成出来的libbar.a
库文件了,修改CMakeLists.txt
如下:
在main.cpp
下执行ctrl+f5
即可完成编译运行了。
调用外部库
我们将分别调用SFML, 与Python相关的matplotlib-cpp, tensorboard_looger以及torch的原生C++库libtorch
SFML
以SFML可视化窗口库为例,安装SFML:
安装的SFML会在/usr/include/SFML/
下创建所需的头文件,在/usr/lib/x86_64-linux-gnu/
下创建链接所需的文件libsfml-*.so.x.x
,在/usr/lib/x86_64-linux-gnu/cmake/SFML/
创建CMake配置所需的SFMLConfig.cmake
文件,用于find_package
命令寻找包文件位置,在安装到/usr/lib
中后就不用再执行find_package
,链接库会自动查找文件位置,创建sfml.cpp
和对应的CMakeLists.cpp
如下
sfml.cpp
CMakeLists.txt
ctrl+f5
执行后就会弹出一个可以通过上下左右移动的绿色长方形。
matplotlib
使用本用例需要我们先安装Python,并使用pip install matplotlib
安装matplotlib,使用GitHub - matplotlib-cpp可以只用一个头文件matplotlibcpp.h
直接通过C++调用Python接口,他需要python, numpy
的头文件和python
的链接库,按照如下步骤进行使用:
- 创建
matplotlib.cpp
源文件,下载matplotlibcpp.h
,在cpp
的同目录下创建一个include
文件夹,将matplotlibcpp.h
放进去;
which python
找到Python的可执行文件位置,例如我的在/home/wty/Programs/mambaforge/envs/yy/bin/python
,那么相对可以找到如下位置:
- Python头文件:
/home/wty/Programs/mambaforge/envs/yy/include/python3.11
,记为PYTHON_INCLUDE_DIR
;
- Numpy头文件:
/home/wty/Programs/mambaforge/envs/yy/lib/python3.11/site-packages/numpy/core/include
,记为NUMPY_INCLUDE_DIR
;
- Python链接库:
/home/wty/Programs/mambaforge/envs/yy/lib
,记为PYTHON_LINK_DIR
;
为了支持输出中文以及公式,我修改了matplotlibcpp.h
中的rcparams
函数:
matplotlibcpp.h中的rcparams函数
然后在rcparams
函数的下方我加入了fontsize
函数,可以更容易的调节字体大小,并保证上文的配置会随着该函数的调用而被配置:
文件架构如下
分别编辑文件:
matplotlib.cpp
CMakeLists.txt
执行上述matplotlib.cpp
文件会生成./build/love.png
图像,绘制效果如下(和Python完全一致,就是调用Python嘛😂)
tensorboard
这里我们使用GitHub - tensorboard_logger,这是一个独立的可执行文件,我们只需编译安装后就可以直接使用,步骤如下:
安装完成后,可以用官方仓库中给的测试用例test_tensorboard_logger.cc
测试各种绘制方法(注意:测试图像时,需要将仓库中assets/
文件夹拷贝到当前项目的./build/
文件夹下,否则找不到文件),文件结构如下
编辑文件如下:
tensorboard.cpp仅使用add_scalar绘制曲线测试
CMakeLists.txt
通过修改CMakeLists.txt
可以分别对tensorboard.cpp
和test_tensorboard_logger.cc
进行编译&执行,在./build/demo/
文件夹下创建日志文件,我们在Python中安装pip install tensorboard
,执行tensorboard --logdir ./build/demo
进入localhost:6006
即可看到绘制的日志内容:
libtorch
最后我们来尝试下libtorch的效果,这就是PyTorch的底层库,有两种安装方法(这里先以CPU版本为例,后续添加CUDA版本):
- Python安装:
conda install pytorch
(如果是用conda
安装的,否则用pip
安装),进入环境终端里面执行python -c 'import torch; print(torch.utils.cmake_prefix_path)'
,即可看到输出的cmake
路径,例如我的是/home/wty/Programs/mambaforge/envs/jax/lib/python3.11/site-packages/torch/share/cmake
;
- 直接下载PyTorch官网中选择
LibTorch
以及对应的cuda
或cpu
版本,下载完成后找到.../libtorch/
对应的目录即可。
把包含TorchConfig.cmake
的路径记录下来称为TORCH_PATH
,只需包含两个文件troch_tensor.cpp
和CMakeLists.txt
,编辑文件如下:
torch_tensor.cpp
CMakeLists.txt
相应的如果VsCode没有找到libtorch相关的头文件位置,我们只需在C/C++:编辑配置(UI)
中包含路径里面加入如下两个即可(相对你的libtorch文件夹,肯定也能找到的):
上面跑的torch_tensor.cpp
是一段测速代码1024×4096和4096×1024矩阵乘法计算100次所需的平均时间(我的CPU为4800U):
- libtorch(C++): 用时44.7ms
- pytorch(Python): 用时84.29ms
- numpy(Python): 用时134.83ms
GPU测速待补充
可以看出C++不是一般的快,Python所用的测速代码如下:
torch_tensor.py PyTorch测速代码
numpy.py Numpy测速代码
多个项目编译
在上文中我们一共创建了5个不同的*.cpp, *.h
文件以及对应的CMakeLists.txt
文件,我们可以通过一个CMakeLists.txt
文件对他们一起编译,并选择其中某一个运行,文件结构如下:
其中./CMakeLists.txt
文件中只需要将每个项目通过add_subdirectory(...)
加入到编译路径中即可:
运行的方法有两种:
- VSCode:在左边栏找到CMake图标,在左侧的项目状态中,可以进行如下设置:
- 设置生成目标:可以选择ALL编译全部文件,也可选择某个项目仅对其编译;
- 设置启动/调试目标:在5个项目中选择一个你当下想要启动的,按
ctrl+f5
即可启动程序。
- 终端:
全部用例代码整合GitHub - cmake_tutorial.7z