.. include:: ../disclaimer-zh_CN.rst :Original: Documentation/dev-tools/gcov.rst :Translator: 赵军奎 Bernard Zhao <bernard@vivo.com> 在Linuxĺ†…ć ¸é‡Śä˝żç”¨gcovĺšä»Łç 覆盖率检查 ===================================== gcovĺ†ćžć ¸ĺżć”ŻćŚĺś¨Linuxĺ†…ć ¸ä¸ĺŻç”¨GCC的覆盖率测试工具 gcov_ ,Linuxĺ†…ć ¸ čżčˇŚć—¶çš„代ç 覆盖率数据会以gcovĺ…Ľĺ®ąçš„ć ĽĺĽŹĺŻĽĺ‡şĺ°â€śgcov”debugfs目录ä¸ďĽŚĺŹŻ 以通过gcovçš„ ``-o`` 选项ďĽĺ¦‚下示例)获得指定文件的代ç čżčˇŚč¦†ç›–率统计数据 ďĽéś€č¦č·łč˝¬ĺ°ĺ†…ć ¸çĽ–čŻ‘č·Żĺľ„ä¸‹ĺą¶ä¸”č¦ćś‰rootćťé™ďĽ‰:: # cd /tmp/linux-out # gcov -o /sys/kernel/debug/gcov/tmp/linux-out/kernel spinlock.c 这将在当前目录ä¸ĺ›ĺ»şĺ¸¦ćś‰ć‰§čˇŚč®ˇć•°ćł¨é‡Šçš„ćşä»Łç 文件。 在获得这些统计文件ĺŽďĽŚĺŹŻä»Ąä˝żç”¨ĺ›ľĺ˝˘ĺŚ–çš„gcov前端工具ďĽćŻ”ĺ¦‚ lcov_ ),来实现 自动化处ç†Linuxĺ†…ć ¸çš„č¦†ç›–çŽ‡čżčˇŚć•°ćŤ®ďĽŚĺŚć—¶ç”źćć“于é…读的HTMLć ĽĺĽŹć–‡ä»¶ă€‚ 可č˝çš„用途: * č°čŻ•ďĽç”¨ćťĄĺ¤ć–每一行的代ç ćŻĺ¦ĺ·˛ç»ŹčżčˇŚčż‡ďĽ‰ * 测试改进ďĽĺ¦‚何修改测试代ç ,尽可č˝ĺś°č¦†ç›–ĺ°ć˛ˇćś‰čżčˇŚčż‡çš„代ç ) * ĺ†…ć ¸ćś€ĺ°ŹĺŚ–é…Ťç˝®ďĽĺŻąäşŽćźä¸€ä¸Şé€‰éˇąé…Ťç˝®ďĽŚĺ¦‚ćžśĺ…łč”的代ç 从来没有čżčˇŚčż‡ďĽŚ ćŻĺ¦čżéś€č¦čż™ä¸Şé…Ťç˝®ďĽ‰ .. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html .. _lcov: http://ltp.sourceforge.net/coverage/lcov.php 准备 ---- ĺ†…ć ¸ć‰“ĺĽ€ĺ¦‚ä¸‹é…Ťç˝®:: CONFIG_DEBUG_FS=y CONFIG_GCOV_KERNEL=y čŽ·ĺŹ–ć•´ä¸Şĺ†…ć ¸çš„č¦†ç›–çŽ‡ć•°ćŤ®ďĽŚčżéś€č¦ć‰“开:: CONFIG_GCOV_PROFILE_ALL=y 需č¦ćł¨ć„Źçš„ćŻďĽŚć•´ä¸Şĺ†…ć ¸ĺĽ€ĺŻč¦†ç›–çŽ‡ç»źč®ˇäĽšé€ ćĺ†…ć ¸é•śĺŹć–‡ä»¶ĺ°şĺŻ¸çš„ĺ˘žĺ¤§ďĽŚ ĺŚć—¶ĺ†…ć ¸čżčˇŚäąźäĽšĺŹć…˘ä¸€äş›ă€‚ 另外,并不ćŻć‰€ćś‰çš„ćž¶ćž„é˝ć”ŻćŚć•´ä¸Şĺ†…ć ¸ĺĽ€ĺŻč¦†ç›–率统计。 代ç čżčˇŚč¦†ç›–率数据只在debugfs挂载完ćĺŽć‰ŤĺŹŻä»Ąč®żé—®:: mount -t debugfs none /sys/kernel/debug 定ĺ¶ĺŚ– ------ 如果č¦ĺŤ•独é’对ćźä¸€ä¸Şč·Żĺľ„ć–者文件进行代ç č¦†ç›–çŽ‡ç»źč®ˇďĽŚĺŹŻä»Ąĺś¨ĺ†…ć ¸ç›¸ĺş”č·Ż 径的Makefileä¸ĺ˘žĺŠ ĺ¦‚ä¸‹çš„é…Ťç˝®: - 单独统计单个文件ďĽäľ‹ĺ¦‚main.o):: GCOV_PROFILE_main.o := y - 单独统计ćźä¸€ä¸Şč·Żĺľ„:: GCOV_PROFILE := y 如果č¦ĺś¨ć•´ä¸Şĺ†…ć ¸çš„č¦†ç›–çŽ‡ç»źč®ˇďĽĺĽ€ĺŻCONFIG_GCOV_PROFILE_ALL)ä¸ĺŤ•独排除 ćźä¸€ä¸Şć–‡ä»¶ć–者路径,可以使用如下的方法:: GCOV_PROFILE_main.o := n ĺ’Ś:: GCOV_PROFILE := n ć¤ćśşĺ¶ä»…支ćŚé“ľćŽĄĺ°ĺ†…ć ¸é•śĺŹć–çĽ–čŻ‘ä¸şĺ†…ć ¸ć¨ˇĺť—çš„ć–‡ä»¶ă€‚ 相关文件 -------- gcov功č˝éś€č¦ĺś¨debugfsä¸ĺ›ĺ»şĺ¦‚下文件: ``/sys/kernel/debug/gcov`` gcov相关功č˝çš„ć ąč·Żĺľ„ ``/sys/kernel/debug/gcov/reset`` 全局复位文件:ĺ‘该文件写入数据ĺŽäĽšĺ°†ć‰€ćś‰çš„gcov统计数据清0 ``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcda`` gcov工具可以识ĺ«çš„覆盖率统计数据文件,ĺ‘čŻĄć–‡ä»¶ĺ†™ĺ…Ąć•°ćŤ®ĺŽ äĽšĺ°†ćś¬ć–‡ä»¶çš„gcov统计数据清0 ``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcno`` gcov工具需č¦çš„软连接文件ďĽćڇĺ‘编译时生ć的信ćŻç»źč®ˇć–‡ä»¶ďĽ‰ďĽŚčż™ä¸Şć–‡ä»¶ćŻ ĺś¨gcc编译时如果配置了选项 ``-ftest-coverage`` 时生ć的。 é’对模块的统计 -------------- ĺ†…ć ¸ä¸çš„模块会动ć€çš„ĺŠ č˝˝ĺ’ŚĺŤ¸č˝˝ďĽŚć¨ˇĺť—ĺŤ¸č˝˝ć—¶ĺŻąĺş”çš„ć•°ćŤ®äĽšč˘«ć¸…é™¤ćŽ‰ă€‚ gcovćŹäľ›äş†ä¸€ç§Ťćśşĺ¶ďĽŚé€ščż‡äżťç•™ç›¸ĺ…łć•°ćŤ®çš„副本来收集这é¨ĺ†ĺŤ¸č˝˝ć¨ˇĺť—的覆盖率数据。 模块卸载ĺŽčż™äş›ĺ¤‡ä»˝ć•°ćŤ®ĺś¨debugfsä¸äĽšç»§ç»ĺ在。 ä¸€ć—¦čż™ä¸Şć¨ˇĺť—é‡Ťć–°ĺŠ č˝˝ďĽŚć¨ˇĺť—ĺ…łč”çš„čżčˇŚç»źč®ˇäĽšč˘«ĺťĺ§‹ĺŚ–ćdebugfsä¸ĺ¤‡ä»˝çš„数据。 ĺŹŻä»Ąé€ščż‡ĺŻąĺ†…ć ¸ĺŹ‚ć•°gcov_persist的修改来ĺśç”¨gcov对模块的备份机ĺ¶:: gcov_persist = 0 在čżčˇŚć—¶ďĽŚç”¨ć·čżĺŹŻä»Ąé€ščż‡ĺ†™ĺ…Ąć¨ˇĺť—çš„ć•°ćŤ®ć–‡ä»¶ć–者写入gcov复位文件来丢ĺĽĺ·˛ĺŤ¸ 载模块的数据。 编译机和测试机ĺ†ç¦» ------------------ gcovçš„ĺ†…ć ¸ĺ†ćžćŹ’ćˇ©ć”ŻćŚĺ†…ć ¸çš„çĽ–čŻ‘ĺ’ŚčżčˇŚćŻĺś¨ĺŚä¸€ĺŹ°ćśşĺ™¨ä¸ŠďĽŚäąźĺŹŻä»ĄçĽ–čŻ‘ĺ’Śčż čˇŚćŻĺś¨ä¸ŤĺŚçš„机器上。 ĺ¦‚ćžśĺ†…ć ¸çĽ–čŻ‘ĺ’ŚčżčˇŚćŻä¸ŤĺŚçš„机器,那äąéś€č¦é˘ťĺ¤–的准备工作,这取决于gcovĺ·Ąĺ…· ćŻĺś¨ĺ“Şé‡Śä˝żç”¨çš„: .. _gcov-test_zh: a) 若gcovčżčˇŚĺś¨ćµ‹čŻ•ćśşä¸Š 测试机上面gcovĺ·Ąĺ…·çš„ç‰ćś¬ĺż…须č¦č·źĺ†…ć ¸çĽ–čŻ‘ćśşĺ™¨ä˝żç”¨çš„gccç‰ćś¬ç›¸ĺ…Ľĺ®ąďĽŚ ĺŚć—¶ä¸‹éť˘çš„文件č¦ä»ŽçĽ–译机拷贝ĺ°ćµ‹čŻ•ćśşä¸Š: 从ćşä»Łç ä¸: - 所有的C文件和头文件 从编译目录ä¸: - 所有的C文件和头文件 - 所有的.gcda文件和.gcno文件 - 所有目录的链接 特ĺ«éś€č¦ćł¨ć„ŹďĽŚćµ‹čŻ•ćśşĺ™¨ä¸Šéť˘çš„ç›®ĺ˝•ç»“ćž„č·źçĽ–čŻ‘ćśşĺ™¨ä¸Šéť˘çš„ç›®ĺ˝•ćśşćž„ĺż…éˇ» 完全一致。 如果文件ćŻč˝Żé“ľćŽĄďĽŚéś€č¦ć›żćŤ˘ćçśźćŁçš„目录文件ďĽčż™ćŻç”±make的当前工作 目录ĺŹé‡ŹCURDIR引起的)。 .. _gcov-build_zh: b) 若gcovčżčˇŚĺś¨çĽ–译机上 测试用例čżčˇŚç»“ćťźĺŽďĽŚĺ¦‚下的文件需č¦ä»Žćµ‹čŻ•ćśşä¸ć‹·č´ťĺ°çĽ–译机上: 从sysfsä¸çš„gcov目录ä¸: - 所有的.gcda文件 - 所有的.gcno文件软链接 这些文件可以拷贝ĺ°çĽ–译机的任意目录下,gcov使用-o选项指定拷贝的 目录。 比如一个ćŻç¤şäľ‹çš„目录结构如下:: /tmp/linux: ĺ†…ć ¸ćşç 目录 /tmp/out: ĺ†…ć ¸çĽ–čŻ‘ć–‡ä»¶č·Żĺľ„ďĽmake O=指定) /tmp/coverage: 从测试机器上面拷贝的数据文件路径 [user@build] cd /tmp/out [user@build] gcov -o /tmp/coverage/tmp/out/init main.c 关于编译器的注意事项 -------------------- GCCĺ’ŚLLVM gcov工具不一定兼容。 如果编译器ćŻGCC,使用 gcov_ 来处ç†.gcnoĺ’Ś.gcda文件,如果ćŻClang编译器, ĺ™ä˝żç”¨ llvm-cov_ 。 .. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html .. _llvm-cov: https://llvm.org/docs/CommandGuide/llvm-cov.html GCCĺ’ŚClang gcov之间的ç‰ćś¬ĺ·®ĺĽ‚ç”±Kconfig处ç†çš„。 kconfigäĽšć ąćŤ®çĽ–čŻ‘ĺ·Ąĺ…·é“ľçš„ćŁ€ćźĄč‡ŞĺŠ¨é€‰ć‹©ĺ适的gcovć ĽĺĽŹă€‚ é—®é˘ĺ®šä˝Ť -------- 可č˝ĺ‡şçŽ°çš„é—®é˘1 编译ĺ°é“ľćŽĄé¶ć®µćŠĄé”™ç»ć˘ é—®é˘ĺŽźĺ› ĺ†ćžć ‡ĺż—指定在了ćşć–‡ä»¶ä˝†ćŻć˛ˇćś‰é“ľćŽĄĺ°ä¸»ĺ†…ć ¸ďĽŚć–者客ĺ¶ĺŚ–äş†é“ľćŽĄç¨‹ĺşŹ 解决方法 通过在相应的Makefileä¸ä˝żç”¨ ``GCOV_PROFILE := n`` ć–者 ``GCOV_PROFILE_basename.o := n`` 来将链接报错的文件排除掉 可č˝ĺ‡şçŽ°çš„é—®é˘2 从sysfs复ĺ¶çš„文件ćľç¤şä¸şç©şć–不完整 é—®é˘ĺŽźĺ› ç”±äşŽseq_file的工作方式,ćźäş›ĺ·Ąĺ…·ďĽäľ‹ĺ¦‚cpć–tar)可č˝ć— ćł•ćŁçˇ®ĺś°ä»Ž sysfs复ĺ¶ć–‡ä»¶ă€‚ 解决方法 使用 ``cat`` 读取 ``.gcda`` 文件,使用 ``cp -d`` 复ĺ¶é“ľćŽĄďĽŚć–者使用附录B ä¸ć‰€ç¤şçš„ćśşĺ¶ă€‚ 附录A:collect_on_build.sh -------------------------- 用于在编译机上收集覆盖率ĺ…文件的示例脚本 ďĽč§ :ref:`编译机和测试机ĺ†ç¦» a. <gcov-test_zh>` ) .. code-block:: sh #!/bin/bash KSRC=$1 KOBJ=$2 DEST=$3 if [ -z "$KSRC" ] || [ -z "$KOBJ" ] || [ -z "$DEST" ]; then echo "Usage: $0 <ksrc directory> <kobj directory> <output.tar.gz>" >&2 exit 1 fi KSRC=$(cd $KSRC; printf "all:\n\t@echo \${CURDIR}\n" | make -f -) KOBJ=$(cd $KOBJ; printf "all:\n\t@echo \${CURDIR}\n" | make -f -) find $KSRC $KOBJ \( -name '*.gcno' -o -name '*.[ch]' -o -type l \) -a \ -perm /u+r,g+r | tar cfz $DEST -P -T - if [ $? -eq 0 ] ; then echo "$DEST successfully created, copy to test system and unpack with:" echo " tar xfz $DEST -P" else echo "Could not create file $DEST" fi 附录B:collect_on_test.sh ------------------------- 用于在测试机上收集覆盖率数据文件的示例脚本 ďĽč§ :ref:`编译机和测试机ĺ†ç¦» b. <gcov-build_zh>` ) .. code-block:: sh #!/bin/bash -e DEST=$1 GCDA=/sys/kernel/debug/gcov if [ -z "$DEST" ] ; then echo "Usage: $0 <output.tar.gz>" >&2 exit 1 fi TEMPDIR=$(mktemp -d) echo Collecting data.. find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \; find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \; find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \; tar czf $DEST -C $TEMPDIR sys rm -rf $TEMPDIR echo "$DEST successfully created, copy to build system and unpack with:" echo " tar xfz $DEST"