1 简介
Linux下制作覆盖率需要以下几个步骤:
1、 编译程序时生成gcno文件;
2、 执行程序后生成gcda文件;
3、 使用lcov命令收集覆盖率信息并写入info文件;
4、 使用genhtml命令生成用于展示覆盖率的html文件。
2 生成gcno文件和gcda文件
2.1 生成方法
Gcno(gcov note)文件和gcda(gcov data)文件,用于生成覆盖率信息。Gcno文件在程序编译时生成,gcda文件在程序执行后生成。
要在编译时生成gcno文件,运行后生成gcda文件,需要在编译链接过程对相关文件进行插桩,即在编译时添加编译选项-fprofile-arcs -ftest-coverage,在链接时加上选项-fprofile-arcs -ftest-coverage和-lgcov。例如$gcc -fprolfile-arcs -ftest-coverage -lgcov -o test test.c。
当工程较复杂,编译链接分多步进行的时候,每一步都需要加上编译选项。例如:
$gcc -fprofile-arcs -ftest-coverage -c test.c
$gcc -fprofile-arcs -ftest-coverage -c demo.c
$gcc -fprofile-arcs -ftest-coverage -lgcov -o Demo demo.o test.o
正确的编译完毕后,在源程序文件的.o文件生成的地方同时生成了各程序文件的gcno文件(每一个被插桩的源程序文件都有一个gcno文件),然后正确链接生成可执行文件。运行可执行文件后,便在.gcno文件所在文件夹生成了对应的gcda文件(每一个被插桩的源程序文件都有一个gcda文件)。也可以通过修改环境变量GCOV_PREFIX和GCOV_PREFIX_STRIP来确定gcda文件的生成位置。
2.2 gcda文件生成目录
可以通过修改环境变量,指定gcda文件的生成目录。例如:
Export GCOV_PREFIX="/home/ckf72739/gcov/output"
Export GCOV_PREFIX_STRIP="20"
前一个命令指定目录,后一个命令指定目录回跳的次数,linux一般20次就可以回跳到根目录。在命令行修改了上面两个环境变量后,执行可执行文件,便可在指定的目录下生成gcda文件。
但是最终在生成info文件时,gcno文件和gcda文件需要在同一个目录下才能生成info文件。
3 生成info文件
上面的过程可以生成gcno和gcda文件,这两个文件包含了代码执行相关的覆盖率信息,接下来需要将这两个文件的信息进行整合,生成保存了整个程序完整覆盖率信息的info文件。
这个时候需要使用linux平台代码覆盖率测试工具GCOV的前端工具LCOV。
3.1 Lcov常用选项说明
Lcov的相关命令可以查看帮助:
$lcov --help
常用的选项:
3.1.1 -c, --capture
Capture coverage data
获取覆盖率信息;
3.1.2 -d, --directory DIR
Use .da files in DIR instead of kernel
覆盖率文件生成需要的用户数据文件(gcno、gcda文件)所在的目录,点号(.)表示当前目录;
3.1.3 -o, --output-file FILENAME
Write data to FILENAME instead of stdout
需要输出的覆盖率信息文件(info文件)。可以加目录,但目录必须存在,否则报错:
3.1.4 -t, --test-name NAME
Specify test name to be stored with data
指定一个保存这些信息的test名字。这个名字体现在生成的info文件中的TN项;如果没有指定则为空。
3.1.5 -e, --extract FILE PATTERN
Extract files matching PATTERN from FILE
过滤出指定的info文件中的匹配项。根据info文件中SF项进行匹配,提取PATTERN指定的文件的覆盖率信息。PATTERN必须精确到文件,如果需要提取某个目录下的所有源程序的覆盖率信息,需要加通配符星号(*)
例如:
$ lcov -e demo.info ‘/home/ckf72739/gcov/LcovDemo/myprint.c’ -o demo1.info
提取demo.info文件中关于/home/ckf72739/gcov/LcovDemo/myprint.c的覆盖率信息,并保存到demo.info中;
$ lcov -e demo.info ‘/home/ckf72739/gcov/LcovDemo/*’ -o demo1.info
提取demo.info文件中关于/home/ckf72739/gcov/LcovDemo/目录下所有源程序的覆盖率信息。
3.1.6 -r, --remove FILE PATTERN
Remove files matching PATTERN from FILE
删除指定的info文件中的匹配项,用法同-e选项。
3.1.7 -a, --add-tracefile FILE
Add contents of tracefiles
合并info文件。可以把多个info文件合并到一起。例如:
$lcov -a demo1.info -a demo2.info -a demo3.info -o demo.info
将demo1.info、demo2.info和demo3.info合并成一个demo.info文件。
3.1.8 -l, --list FILE
List contents of tracefile FILE
显示出指定的info文件的覆盖率信息,如图:
3.2 Lcov举例
一个较完整的lcov命令如下
$ lcov -c -d . -o demo.info -t Demo
将在当前目录递归查找.gcno和.gcda文件并在当前目录生成一个名为demo.info的info文件,其test name为Demo。
3.3 Lcov命令流程
执行一个lcov命令,可以在命令行生成如下信息:
可以发现,lcov命令在当前目录下(包括子目录)查找.gcda文件,根据gcda文件去查找gcno文件,生成info文件。
Locv相关操作如果没有-o指定输出文件,lcov执行后的info文件数据将会输出在命令行。
4 生成html
根据lcov命令生成的info文件,可以通过genhtml命令生成html文件,将info文件中的覆盖率信息通过以html的形式直观的展示出来。
4.1 Genhtml常用选项
相关的genhtml命令可以通过查看帮助:
$genhtml --help
常用的选项:
4.1.1 -o, --output-directory OUTDIR
Write HTML output to OUTDIR
生成的html文件的保存目录。因为生成的html文件很多,最好使用一个文件夹保存起来;
4.1.2 -t, --title TITLE
Display TITLE in header of all pages
展示在html页面上的一个titlte;
4.1.3 --legend
Include color legend in HTML output
加上该选项会在页面上显示如下内容:
4.1.4 --no-source
Do not create source code view
创建html文件时,不附带程序源文件(如.c文件)。Genhtml在生成html文件时会根据info文件中的SF指定的源文件路径去查找源文件,并附带到html文件中。如果没有源文件,可以添加这个选项,不附带源文件内容。
4.1.5 --(no-)sort
Enable (disable) sorted coverage views
能否对覆盖率显示进行排序。当选项为--no-sort时,生成的html文件无法对覆盖率显示进行排序;当选项为--sort,生成的html可以对覆盖率显示进行排序。默认的选项是—sort。
如图,可以点击Line coverage后面的箭头对覆盖率进行排序显示:
排序后:
4.2 Genhtml举例
一个较完整的genhtml命令如下:
$genhtml demo.info -o html -t Demo -legend
该命令会根据当前目录下的demo.info文件生成html文件,保存在当前目录下的html文件夹中,并在页面显示Legend。
5 总结
Linux下覆盖率生成过程总结如下:
1、 编译需要生成覆盖率的源程序文件:
$gcc -fprofile-arcs -ftest-coverage -c test.c
生成test.c的gcno文件test.gcno;
2、 链接生成可执行文件:
$gcc -fprofile-arcs -ftest-coverage -lgcov -o Demo test.o
生成可执行文件test
3、 运行可执行文件:
$./Demo
生成编译过程中加入了-fprofile-arcs -ftest-coverage选项的源程序文件对应的gcda文件,本例中生成test.gcda文件。
4、 生成info文件:
$lcov -c -d . -o demo.info
自动在当前目录查找gcno和gcda文件,并生成demo.info文件。
5、 生成html文件:
$genhtml demo.info -o html
读取当前目录的demo.info文件,并生成html文件,生成的html文件保存在当前目录下的html目录下。
6 注意事项以及可能出现的问题
通过上面几个步骤,可以生成一个包含覆盖率信息的html。但需要注意以下事项:
6.1 中文路径问题
问题描述:源程序相关的目录中,如果包含有中文路径,这样的路径在生成的html文件上无法正确显示:
而且点击后无法进入相关链接:
解决方法:查看页面源文件,发现页面编码charset=ISO-8859-1,如果在页面“查看”选项中将“编码”选择为UTF-8,页面可以正确显示及点击。所以问题出现的原因是由genhtml命令生成html文件时的编码格式导致的。找到genhtml代码文件,使用$which genhtml命令可以定位出genhtml文件所在的位置(一般在/usr/bin/genhtml),进入文件查看代码,可以发现在生成html文件时使用了ISO-8859-1:
将ISO-8859-1修改为UTF-8,重新使用genhtml命令生成html文件,便可正常显示中文:
6.2 复杂工程编译选项问题
当工程较复杂时,需要多步编译链接时,需要在每一步都加上gcov相关的选项,如果不加入选项,就会出现如下问题:
1、$gcc -c test.c
$gcc -fprofile-arcs -ftest-coverage -o test test.o
这样编译链接的过程中,不会生成任何gcno文件(同样,运行的过程中也不会生成gcda文件),无法生成覆盖率;
2、$gcc -fprofile-arcs -ftest-coverage -c test.c
$gcc -o test test.o
如上,在执行第二步的时候,将会报错:
3、$gcc -c test1.c
$gcc -fprofile-arcs -ftest-coverage -c test2.c
$gcc -fprofile-arcs -ftest-coverage -o test test1.o test2.o
如上,不会生成test1.c文件的gcno文件(同样在运行时也不会生成.gcda文件),这样在最后生成的覆盖率文件中,不会包含test1.c文件的覆盖率信息。当然,如果你不需要对test1.c文件生成覆盖率信息时,可以这么做。
6.3 -lgcov选项问题
在一些情况下,链接过程中不加入-lgcov选项,也可以正确链接生成可执行文件。但在某些情况下,需要链接gcov静态库(libgcov.a),就需要加上-lgcov选项,否则链接过程会报错。