上周接到mentor给的一个task,目的是为了完善我们整个项目的C++标准开发流程的一套pipeline,包括clang-format这些引入企业级测试框架。需求是调研目前社区中流行的以及成熟的开源项目中使用的测试框架,比较优劣之后选择一个移植到我们自己的项目中。具体我们自己的项目细节由于隐私问题不谈,本文主要想谈谈移植框架中遇到的困难与解决方案。
目前市面上流行的测试框架有很多,但更为成熟并广泛使用的主要有三种:Catch, Boost Test和Google Test,三种框架也各有其优劣,这里简单对比一下:
![](https://img.haomeiwen.com/i13068367/ca107b1c1cdbaf62.png)
如果想了解更多关于各种框架的优劣对比可以访问这个链接:https://stackoverflow.com/questions/242926/comparison-of-c-unit-test-frameworks
由于当初在头条实习研究过小部分chromium的源码,里面的unittest很好用就选择了GoogleTest。(毕竟更相信google的code quality和框架的integration。之后就开始了“开心”的框架移植之旅。第一件事情是找到googletest在github上的源码,把官方的一些document全都读了一遍熟悉googletest的写法和流程,然后读了一些example熟悉测试的写法。(从一些google的开源项目里的注释来看,一部分google的工程师真是自恋lol)
好了终于要开始说正题了,需求的核心就在于移植和对接,按常理说如何在新项目或者已有项目中部署一个框架在开源文档里应该有guide。好了,打开googletest里的readme,读了一会儿发现了“Incorporating Into An Existing CMake Project”这一部分, 惊不惊喜意不意外。正在我开心并且天真幼稚地以为这个task要完成了的时候我惊奇的发现事情并没有那么简单lol,理由有两点,相较简单的cmake工程来讲我们的项目层级更多并且编译流程更加复杂。仔细阅读发现readme里提供了三种方式将googletest移植到已有的cmake工程中:
1. 手动clone下来GoogleTest源码并且把它放到一个已知的位置上,这种方法最不灵活
2. 把GoogleTest源码直接嵌入到已有工程的目录树中
3. 把GoogleTest加入并作为git的submodule,这种方法并不总是可行的
4. 使用CMake去下载GoogleTest作为build流程中的一部分
根据官网的说法,第四种方式虽然稍微复杂些但最为灵活并且不会有其他几种方法的limitation。于是乖乖的选择了第四种说法。指示的说法是这样的,新建一个CMakeLists.txt.in文件,代码文档中已经给出,之后在cmake文件中嵌入文档给出的一段代码,然后告诉你大功告成了,就是这么的easy。然鹅,我们自身的项目层级很多,一个project中有若干个sub-proj,并且编译顺序与外部依赖也较为复杂,说白了就是我们的项目build之后会生成很多.exe,再换句话说我们的项目有很多cmake文件(每个sub-proj都会有一个cmake来控制编译的流程以及头文件的include),你说我应该把官网的代码嵌入到哪个cmake文件?思考的同时还查阅了一些中文文档。这个时候插一句一个很重要的小tips:尽量少看中文文档!stackoverflow,google,github或者等等都可以为你提供优质并且完整的解答,事实证明,我查到的很多中文document里面都是直接google翻译那些官方文档,很多翻译的还很拙劣。
之后回到正题,到底嵌入到哪个cmake中能使得代码生效,并且后来发现光嵌入官方的代码也是不够的,为了在整个项目的各个地方都能够随时include gtest,还需要在各个子项目cmake中修改控制编译的include。研究发现官网给的cmake code会在generate cache的阶段download googletest的源码到工程中,注意此时还未build,因此并没有lib或so生成。 之后设计了一下开始移植。取代码download和防止覆盖已有项目的compile和link的配置的那部分code而暂时不去link。之后在全局cmake中定义GTEST宏,在子项目的cmake中根据平台来选择link的文件,这部分的目的是由于我们的项目是cross device and platform的,因此主要需要区别linux下和windows下build生成的文件。基本完成,后来测试的时候发现一个奇怪的bug就是在release下能build通过但是debug模式下却build不过,由于debug是项目中必不可少的一环,因此这样也是不能接受的。后来跟mentor调了一晚上最后也没成功lol,开始怀疑是ninja的问题,后来发现也不是。到后来晚上十点多了我俩都非常绝望说明天再说吧,如果尝试再不行就只能选择别的方法但是又会引入很多问题。
第二天来了绝望的调了一阵,逐渐缩小出现问题code的定位最后居然神奇的调通了。具体的bug是link的方式不对,由于googletest项目本身的cmake已经考虑了平台问题,也就是会根据平台来控制link文件的不同,因此不需要判断平台,直接target_link_libraries(XXX gmock_main)就可以了。(这里关于gtest和gmock的问题就不说了)
所以这个task带来的思考是,除了熟悉自身项目的cmake流程还要熟悉引入项目的cmake流程,不然build的过程中就会出现各种神奇的bug。在复杂的项目中引入gtest的时候尽量把官网给的code拆开控制。后续测试code的书写方式就不说了,大家可以阅读官网提供的那些document,有primer和advanced的。
网友评论