小小博客,不足为外人道
分类: C/C++
2017-03-03 17:01:40
这个过程几乎从0开始,在此之前,我几乎没有在 linux 下编译链接过项目、没有接触过 makefile、没有读过 man-db、只 gcov 过一个仅有几个C文件的项目
现在,我用 gcov 完成了对 VIM 源码的覆盖,并通过 lcov 生成了非常易读的覆盖率报告
中间碰到了许多疑难杂症,但是更多的是若干教程中叮嘱的“不要放弃”,所以我大概按照下面的节点完成了这个工具的入门:
虚拟机安装Ubuntu,配置gcov和lcov环境
--> 编译链接单个C文件
--> 写一个多个C文件的项目,用 makefile 进行编译连接,完成覆盖
--> 覆盖优秀的开源软件,例如 VIM
这里会按照上述节点逐渐展开,希望帮助和我一样从0开始的朋友们更容易的完成这个过程
如果您对一些问题已经有了研究,那么这里的内容可能太过浅显,敬请继续往下翻阅
如果您没有碰到这些问题,那么恭喜一切都很顺利
如果您要深究一些技术的原理,那么这里可能无法提供您所需要的信息:一是我期望在这里精炼出成功配置环境的方法,更倾向于去解决问题而非深入研究;二是掌握一项技术归根结底还要自己一步一步走下去,一点一点踏实学,绝不是一篇博文就能简单解决的
好了,下面开始 :-)
gcov 适用的场合:GNU C/C++,因此适用的编译器:cc, gcc, g++
这里举斐波那契数列的一个程序为例
.gcno是由-ftest-coverage产生的,它包含了重建基本块图和相应的块的源码的行号的信息。
2. 链接
我当时邮件给时光机的两个主角问了一下 gcov 的近况,并没有期望得到回复
但是就在昨天 Nathan 他老人家竟然回邮件了!带上以上所有已经提供的信息,他还感慨了一下 gcov has changed a lot since then...
回归正题,链接的时候下面三条任选一个执行即可
应该会正常生成 fib
3. 运行程序 fib
会生成 .gcda 文件,.gcda是由加了-fprofile-arcs编译参数的编译后的文件运行所产生的,它包含了弧跳变的次数和其他的概要信息。
4. 生成 gcov 报告
至于 gcov 的更多选项,例如 -b 分支覆盖 -f 函数覆盖, 就 man 吧。
5. 存在的问题
gcov 对每个源码的分析分散在对应的 .cov 文件中,不容易整理分析;文本,无图表……
这就是要使用 lcov 的原因
另外,如果您对gcc也十分不熟悉,正在寻求入门的话,可以参考这里:
1. 汇总覆盖率数据,使用已经生成的 .gcno .gcda 文件生成覆盖率数据
简单解释一下三个选项
-c: lcov 的一个操作,表示要去捕获覆盖率数据
-o: 输出文件
-d: .gcno .gcda 所在的文件夹,注意这里有个“.”,是从当前文件夹中获取数据的
问题又来了,开始在 lcov 的过程中,碰到 Negative length 的问题,顺着提示找到 lcov 源码中的一处 $(length) ,之后并没有头绪为什么会是负值传入的,于是根据 sourceforge 上面的地址,发了一封邮件询问了一下,回信意思是我使用的 gcc 版本为 4.7.2,需要 lcov 1.10+ 版本支持,使用 1.09 或更低版本的 lcov 会出现这样的问题。于是到以下地址去下载了最新的 lcov
在 lcov 1.10 的 release notes 中写明了对 gcc 4.7+ 提供了支持。
2. 生成 html 格式的报告
genhtml 是安装 lcov 时附带的,使用上面产生的 .info 文件生成报告,存放于 fib_result 文件夹中
没错,这里的报告并不只是一个文件,有好多存放在你 -o 指定的目录下,生成之后进入 fib_result 就可以看见念想很久的 index.html 了
这里再分享一下怎么从 terminal 用浏览器打开网页:
3. gcov lcov 资料汇总
在学习过程中检索到的一些文章有对这两个工具的解读,我将有所收获、编排整齐的几篇列举如下,由浅入深,您也可以直接参考他们的文章:
i) gcov 和 lcov 的简明使用教程:http://magustest.com/blog/whiteboxtesting/using-gcov-lcov/
ii) gcov 和 lcov 的简单介绍,包括一些选项的含义,
gcov: http://blog.csdn.net/livelylittlefish/article/details/6321861
lcov: http://blog.csdn.net/livelylittlefish/article/details/6321887
iii) gcov 产生的覆盖率结果会存放在 .cov 文件中,这里有对 .cov 文件的解读:http://blog.csdn.net/ashhyc/article/details/1558598
iv) lcov 中间产物 .info 文件的解读:http://blog.csdn.net/vivasoft/article/details/8330186
v) gcov lcov 产生各类文件的简介:http://wx782870649.blog.163.com/blog/static/12989164120127224317532/
vi) gcov official online manual:
vii) gcov FAQ:
viii) 这里提到了怎么用 gcov 对 linux kernel 进行覆盖:http://blog.csdn.net/yukin_xue/article/details/7653482
ix) 这里分析了 gcov 的工作原理,并直接操纵其获取数据的出入口,实现了对后台进程的覆盖统计:
http://blog.linezing.com/2011/03/使用gcov完成代码覆盖率的测试
为什么要有 makefile ?
因为编译、链接项目如果需要一条一条手动敲命令的话,那对那种动辄几十几百个文件的项目实在太恐怖了,需要这样一个建设性的懒惰,于是有了 makefile
makefile 是什么?
原本归根结底,makefile 是原来的编译、链接命令的集合,把源文件逐个编译、最后链接,产生可执行文件
至于为了灵活性而衍生出来的各类语法、变量、函数、隐晦规则……刚入门时可以先不必纠结
makefile 我还总结不出什么心得,这一阵儿学习是参考的陈皓老师的博客:http://blog.csdn.net/haoel/article/details/2886
或者这里有 pdf 文档,
我觉得,为了后面的工作,至少读通这份 pdf 的前8页,知道 makefile 怎么使用变量
1. 环境变量
相信您或多或少都听说过环境变量这个词,也知道他大概是什么意思,很多我们看不到的系统调用会用到这些变量,举个栗子:
打出命令 gcc 干嘛干嘛的时候,系统怎么执行你这个命令?系统不会听人说话,其实您已经调用了一个可执行文件 gcc
那这个 gcc 又是从哪调用的?其实系统会从一些目录下去找这个执行文件 gcc ,而这些目录就写在环境变量 $(PATH) 中,可以打印这个变量出来看看
而 gcc 可执行程序在 /usr/bin 这个文件夹中,他的路径已经写在 $(PATH) 里了,应该可以看到
Ubuntu 系统的环境变量存储在以下5个配置文件中:
/etc/environment
系统登录时读取的第一个文件,用于为所有进程设置环境变量
/etc/profile
系统登录时读取的第二个文件,会设定所有用户的环境变量
~/.profile
对应当前登录用户的 profile 文件,用于定制当前用户的个人工作环境
/etc/bash.bashrc
对应所有用户的 bash 初始化文件,这里设定的环境变量将应用于所有用户的 shell 中,此文件会在用户每次打开 shell 时执行一次
~/.bashrc
对应当前登录用户 bash 的初始化文件,当用户每次打开shell时,系统都会执行此文件一次
这几个文件的读取书序依此是:
/etc/environment -> /etc/profile -> ~/.profile -> /etc/bash.bashrc -> ~/.bashrc
还可以进行一些实验验证,请参考:http://blog.sina.com.cn/s/blog_6405313801012pxw.html
2. makefile 中的变量
为什么要用变量?
再举个栗子,gcc 有选项 -O0 -O2,前者表示编译时不优化,后者表示最大程度优化,现在有个 makefile 如下:
当你要做覆盖率分析的时候,你期望编译过程不要优化,于是又要把所有的 -O2 改为 -O0 ……
当未来有一个比 gcc 更好的编译器 xcc ,又要把所有的 gcc 改为 xcc ......
当然,现在可以用 replace ,但是不管是期望更灵活的在以后来修改,还是强迫症……不如这样改写上述 makefile :
至于 CFLAGS, CXXFLAGS, LIBS 这些变量的含义,请参考:http://www.cnblogs.com/taskiller/archive/2012/12/14/2817650.html
这里我用了另一种方法来确定我需要关注那些变量,在项目路径下,执行:
把 gcvo lcov 中提到的知识应用到这儿,我们只需要设定好编译和链接相关的两个环境变量 CFLAGS 和 LIBS
如下设定:
在 /src/objects 中应该生成了许多 .o 和 .gcno 文件吧,随后运行 VIM 生成 .gcda ,汇总覆盖率数据生成 .info ,将信息整理成 html 格式的命令都可以参考上面有关 gcov lcov 的使用
最后打开 index.html,就可以看到本文最开始出现的覆盖率数据了