CMake 新手向
CMake 是一个用来结构化 C++ 工程的工具,可以方便开发者跨平台的统一工程结构,并可根据个人要求输出不同的目标工程,如 vs 工程等。之前只在用 OpenCV 的过程中有过部分接触,但已经完全忘掉了,最近正好有需要,从头慢慢捡起来。
要求
自己新建一个工程并编写CMakeLists 组织工程进行编译,运行
需要链接一个三方库,例如(gtest)
需要在工程中用三方库的某些函数
能完成工程的编译、链接、运行
还是通过 msi 方式安装比较便捷一些,一开始下的是离线源码包解压缩就很慢,其他内容都还得自己手动添加。
cmake 语法不关心大小写,看个人喜好就行。但 cmake 变量名是大写敏感的,如 ${PROJECT_NAME}
。
- 第一次写 CMakeLists.txt 时,出现了两个问题,首先文件名写错了,漏了个 s;其次是文件中的空格估计是触发全角字符开关,导致空格为全角字符,执行 cmake 命令时未完整生成对应产物。
- 流程
写好源文件、头文件、暴露的共享库等等。
新建一个 CMakeLists.txt,并写好相关的配置信息。
执行 cmake,在 CMakeLists.txt 配置文件同级下执行。
生成好工程文件后即可使用。如果用的 vs,记得设置对应输出的工程文件为“启动项目”。
之前只在下载 Qt 过程中顺带下载了关联的 MinGW,原本想着直接把该 MinGW 路径直接添加到系统路径中作为 make 命令的使用,但发现 Qt 中关联的 MinGW 为便捷访问方式,显示原文件路径找到的居然是系统 cmd.exe……怀疑被 Qt 隐藏。
- 遂决定重新下载全新 MinGW,先是通过下载器安装,但在依赖文件下载时提示报错,多次尝试未果,遂重新通过源文件方式解压缩完成,成功把对应路径添加到系统路径下,通过 mingw32-make 命令可用。
- 需要注意添加到系统路径时,并不是新起一个用户变量而是直接添加到“Path”变量下,新增一列。
- make 命令调用完成,需要测试 make 直接编译
为了不干扰工程目录结构,可以参考目前流行设计,新建一个 build 文件夹,专门在其中存放编译过程产物。但 cmake
命令是本身 cmakefiles.txt 走的,在不同的文件夹下生成编译产物注意层级关系。
- 默认情况下,win10 采用 vs 进行编译,最终
cmake
命令生成的最终相关文件也是 vs 强相关的,但如果我们想过更底层一些,直接生成 makefile,需要在执行 cmake 命令时,指定编译器。 - 不同编译器所生成的 makefile 格式不同,如果你跟我一样也是 MinGW 编译器,可以使用这个命令
cmake .. -G "MinGW Makefiles"
使用 CMake 进行工程
创建好的 add.dll 动态库,在 cmakelists 中设置好了相关路径字段,cmake
和 make
都通过了,但点击构建出的产物 HELLO.exe 提示 libadd.dll 找不到,仔细检查了 cmakelists 中是否有写错什么方法,但一直无果。
后来在一篇安装 OpenCV 的文章中才找到了类似问题的解决方案,直接把对应的动态库复制一份到系统目录 windows/System32 目录下,动态库运行时 win 会按照默认设置的系统动态库路径去找。
链接 google test
没有采用 C++20 后引入的包管理 find_package
,也没有使用 git submodule 的形式,直接从 github 上拿到源码放到 cmake 工程目录下。因为 gtest 原生支持 cmake 和 bazel,对于 cmake 工程来说非常友好。
经过了前面几次的练习,对 cmake 组织一份工程有了粗浅的认识,对于已经提供原生 cmakefiles 的 gtest 来说,我们只需要通过子模块和静态库的方式进行链接和编译即可使用。
先来看看完整的工程目录。既然是一个工程,那么源文件、测试文件、编译中间产物和主工程配置文件必然都得分开。源文件存放在 src 目录,测试文件存放在 test 目录下,编译中间产物都放在 build 目录下,主工程配置文件就工程根目录吧。
创建好所需的文件夹后,接着创建工程配置文件 cmakefiles(工程根目录下),用于组织工程间的文件关系。
1 | # 限定 cmake 版本,不写会在 cmake 执行时报错提示添加 |
lib 目录下 git clone googletest 整个源文件夹进去即可。src 目录下内容:
1 | // Add.h |
1 | // Add.cpp |
1 | // main.cpp |
src 目录下的 cmakefiles 文件内容如下:
1 | # 给工程名设置别名为 BINARY(有点多余,可不用,多写几个字母也不碍事) |
test 文件夹的内容分别如下:
1 | // main.cpp |
1 | // Add-test.cpp |
test 下的 cmakefiles 内容为:
1 | set(BINARY ${CMAKE_PROJECT_NAME}_test) |
处理好以上内容后,进入到 build 目录下。因为前文也已经说过本机默认编译器为 vs,需要手动执行 cmake .. -G "MinGW Makefiles"
切换编译器为 MinGW 来生成 makefile 文件。
等待一会后,执行 minGW32-make.exe
,感觉不用重命名为 make 看上去更语义化一些就没改了,如果你觉得每次都输入这么长的命令比较烦可以加到系统 path 中。在终端中你可以看到都生成了对应的 gtest_demo、gtest_demo_run、gtest_demo_test 可执行文件(其实就是 .exe),因为偷懒了并没有在每一个可输出的地方都加上了 system("pause")
函数,所以直接双击打开会一闪而过,可以继续在终端中 ./gtest_demo_test
观察输出。
你会发现失败了一个用例,如下图所示:
至此,我们就完成了手动链接并编译 gtest!