C/C++ 代码覆盖率工具:gcov+lcov

GCOV是一个测试C/C++代码覆盖率的工具,使用它可以看出哪些代码被执行了,被执行的次数和时间。

1 gcov简介

GCOV随着gcc安装,不需要我们另外再进行安装,gcov的使用如下。

1.1 代码编译

想要用 gcov 收集代码覆盖信息, 需要在编译代码的时候加上这 2 个选项 -fprofile-arcs -ftest-coverage,编译后会生成gcno文件。

1.1.1 直接编译单个文件

g++ -fprofile-arcs -ftest-coverage hello.cpp -o hello 
#include 
using namespace std;

int main()
{
    cout << "Hello, World!";
    return 0;
}

1.1.2 使用Makefile进行编译

修改Makefile文件,补充以下内容

GCOV_FLAGS=-fprofile-arcs -ftest-coverage
CFLAGS+=$(GCOV_FLAGS)
LDFLAGS+=-lpthread $(GCOV_FLAGS)
CXXFLAGS+=$(GCOV_FLAGS) 
CPPFLAGS+=$(GCOV_FLAGS)

1.1.3 使用configure文件生成makefile再进行编译

configure过程中,增加以下参数:

  LDFLAGS+='-fprofile-arcs' CFLAGS+='-fprofile-arcs -ftest-coverage' CXXFLAGS+='-fprofile-arcs -ftest-coverage' CPPFLAGS+='-fprofile-arcs -ftest-coverage' ./configure --without-system-libs --without-system-headers LIBS=-lgcov

之后make,与正常编译一样。

1.2 代码执行&覆盖率信息查看

运行相应的case可以看到生成了gcda文件,这时可以使用命令将这些文件合成最终的gcov文件,命令如下

gcov hello.cpp

运行结束以后会生成存有具体覆盖率信息的文件hello.cpp.gcov。打开看里面的信息:

        -:    0:Source:hello.cpp
        -:    0:Graph:hello.gcno
        -:    0:Data:hello.gcda
        -:    0:Runs:1
        -:    0:Programs:1
        -:    1:#include 
        -:    2:using namespace std;
        -:    3:
        1:    4:int main()
        -:    5:{
        1:    6:    cout << "Hello, World!";
        1:    7:    return 0;
        3:    8:}

添加以下参数可以看到更多覆盖率信息:

Usage: gcov [OPTION]... SOURCE|OBJ...

显示代码覆盖信息。

  -h, --help                      打印此帮助并退出
  -v, --version                    打印版本号并退出
  -a, --all-blocks                显示每个基本块的信息
  -b, --branch-probabilities      输出包含分支概率
  -c, --branch-counts             给出跳转的分支数,而不是百分比
  -n, --no-output                 不创建输出文件
  -l, --long-file-names           为包含进来的源文件使用长输出文件名
  -f, --function-summaries        输出每个函数的小结信息
  -o, --object-directory DIR|FILE 在 DIR 中搜索目标文件,或搜索名为 FILE 的目标文件
  -s, --source-prefix DIR         Source prefix to elide
  -r, --relative-only             Only show data for relative sources
  -p, --preserve-paths            保留所有路径名
  -u, --unconditional-branches    同时显示无条件跳转数
  -d, --display-progress          显示进度信息
 

2 lcov简介

从1.2看到的代码覆盖的信息是正确的, 但是既不直观也不方便。lcov可以用程序解析这些晦涩的字符, 最终输出成 html格式的报告。

2.1 lcov生成info数据

lcov 可以在指定目录去找代码覆盖的信息, 输出为 *.info, 这个 *.info 是一个中间结果

lcov -c -o collector.info -d .

更多使用方法见:

Usage: lcov [OPTIONS]

Use lcov to collect coverage data from either the currently running Linux
kernel or from a user space application. Specify the --directory option to
get coverage data for a user space program.

Misc:
  -h, --help                      Print this help, then exit
  -v, --version                   Print version number, then exit
  -q, --quiet                     Do not print progress messages

Operation:
  -z, --zerocounters              Reset all execution counts to zero
  -c, --capture                   Capture coverage data
  -a, --add-tracefile FILE        Add contents of tracefiles
  -e, --extract FILE PATTERN      Extract files matching PATTERN from FILE
  -r, --remove FILE PATTERN       Remove files matching PATTERN from FILE
  -l, --list FILE                 List contents of tracefile FILE
      --diff FILE DIFF            Transform tracefile FILE according to DIFF
      --summary FILE              Show summary coverage data for tracefiles

Options:
  -i, --initial                   Capture initial zero coverage data
  -t, --test-name NAME            Specify test name to be stored with data
  -o, --output-file FILENAME      Write data to FILENAME instead of stdout
  -d, --directory DIR             Use .da files in DIR instead of kernel
  -f, --follow                    Follow links when searching .da files
  -k, --kernel-directory KDIR     Capture kernel coverage data only from KDIR
  -b, --base-directory DIR        Use DIR as base directory for relative paths
      --convert-filenames         Convert filenames when applying diff
      --strip DEPTH               Strip initial DEPTH directory levels in diff
      --path PATH                 Strip PATH from tracefile when applying diff
      --(no-)checksum             Enable (disable) line checksumming
      --(no-)compat-libtool       Enable (disable) libtool compatibility mode
      --gcov-tool TOOL            Specify gcov tool location
      --ignore-errors ERRORS      Continue after ERRORS (gcov, source, graph)
      --no-recursion              Exclude subdirectories from processing
      --to-package FILENAME       Store unprocessed coverage data in FILENAME
      --from-package FILENAME     Capture from unprocessed data in FILENAME
      --no-markers                Ignore exclusion markers in source code
      --derive-func-data          Generate function data from line data
      --list-full-path            Print full path during a list operation
      --(no-)external             Include (ignore) data for external files
      --config-file FILENAME      Specify configuration file location
      --rc SETTING=VALUE          Override configuration file setting
      --compat MODE=on|off|auto   Set compat MODE (libtool, hammer, split_crc)

2.2 生成html数据

genhtml 也是 lcov里面的一个工具,可以使用*.info 数据 生成html数据。

genhtml collector.info -o collector_result

C/C++ 代码覆盖率工具:gcov+lcov_第1张图片

更多使用方法见:

Usage: genhtml [OPTIONS] INFOFILE(S)

Create HTML output for coverage data found in INFOFILE. Note that INFOFILE
may also be a list of filenames.

Misc:
  -h, --help                        Print this help, then exit
  -v, --version                     Print version number, then exit
  -q, --quiet                       Do not print progress messages
      --config-file FILENAME        Specify configuration file location
      --rc SETTING=VALUE            Override configuration file setting
      --ignore-errors ERRORS        Continue after ERRORS (source)

Operation:
  -o, --output-directory OUTDIR     Write HTML output to OUTDIR
  -s, --show-details                Generate detailed directory view
  -d, --description-file DESCFILE   Read test case descriptions from DESCFILE
  -k, --keep-descriptions           Do not remove unused test descriptions
  -b, --baseline-file BASEFILE      Use BASEFILE as baseline file
  -p, --prefix PREFIX               Remove PREFIX from all directory names
      --no-prefix                   Do not remove prefix from directory names
      --(no-)function-coverage      Enable (disable) function coverage display
      --(no-)branch-coverage        Enable (disable) branch coverage display

HTML output:
  -f, --frames                      Use HTML frames for source code view
  -t, --title TITLE                 Display TITLE in header of all pages
  -c, --css-file CSSFILE            Use external style sheet file CSSFILE
      --no-source                   Do not create source code view
      --num-spaces NUM              Replace tabs with NUM spaces in source view
      --highlight                   Highlight lines with converted-only data
      --legend                      Include color legend in HTML output
      --html-prolog FILE            Use FILE as HTML prolog for generated pages
      --html-epilog FILE            Use FILE as HTML epilog for generated pages
      --html-extension EXT          Use EXT as filename extension for pages
      --html-gzip                   Use gzip to compress HTML
      --(no-)sort                   Enable (disable) sorted coverage views
      --demangle-cpp                Demangle C++ function names
      --precision NUM               Set precision of coverage rate

3 不同次代码覆盖率统计合并

有的时候,需要多次运行程序对应不同的测试情况,这种时候怎么将不同次的统计合并到一起形成一个统一的代码覆盖率呢?

可以使用lcov实现,每次使用lcov生成.Info文件后,可以是使用lcov -a参数合并.info文件:

Lcov -a a.info -a b.info -o all.info

然后使用all.info执行genhtml生成最终的代码覆盖率。

4 过滤部分代码覆盖率统计信息

如不需要统计覆盖率信息,则需要屏蔽,或者只需要某些文件的覆盖率,就需要对文件进行筛选

4.1 移除指定目录

lcov --remove all.info '/src/include/*' '/user/bin/*' -o result.info

此命令表示生成的覆盖率信息,屏蔽 '/src/include/*' '/user/bin/*' 两个目录的覆盖率信息

all.info  总的覆盖率信息

result.info 筛选后的覆盖率信息

4.2 只要固定目录

lcov  --extract all.info '*/src/*' '*/lib/*' -o result.info

此命令表示生成的覆盖率信息只要src和lib目录下文件的覆盖率信息

all.info  总的覆盖率信息

result.info 筛选后的覆盖率信息

 

你可能感兴趣的:(代码覆盖率)