我想分析代码覆盖率数据。我想从 OpenSSL(以及其他项目)创建 gcov 文件,但我只能在项目的同一目录中创建它们,并且只能针对当前文件夹中的文件。
我想在不同的目录中创建它们,保留源原始目录结构,并使整个过程尽可能自动化。
来源:
~/mygcovproject/projects/openssl-1.0.0
输出:
~/mygcovproject/gcovdata/openssl-1.0.0
目前我只能通过这种方式创建文件:
$ cd ~/mygcovproject/projects/openssl-1.0.0
$ make clean
$ export CC="gcc -fprofile-arcs -ftest-coverage"; ./config
$ make
$ make tests
$ cd test
$ gcov *.c
$ mv *.gcov ~/mygcovproject/gcovdata/openssl-1.0.0/test/
$ cd ..
$ cd apps
$ gcov *.c
$ mv *.gcov ~/mygcovproject/gcovdata/openssl-1.0.0/apps/
$ cd ..
$cd crypto
... (for all the folders)
但这种方法有两个大问题:
1)有很多文件夹和子文件夹。
2)我必须手动移动文件。
我该怎么做?你能帮我吗?
更新:
谢谢吉尔斯,它对我帮助很大,但我仍然很难理解最后一部分。我从 gcov 收到错误消息:
$ cat dothemagic.sh
#!/bin/bash
shopt -s globstar
gcov_data_dir="../../gcovdata/${PWD##*/}"
mkdir -p "$gcov_data_dir"
#make
#make tests
for x in ./**/*.c; do
gcov "$gcov_data_dir/${x%/*}/$x"
done
exit
$ ./dothemagic.sh
../../gcovdata/openssl-1.0.0/./apps/./apps/app_rand.gcno:cannot open notes file
../../gcovdata/openssl-1.0.0/./apps/./apps/apps.gcno:cannot open notes file
../../gcovdata/openssl-1.0.0/./apps/./apps/asn1pars.gcno:cannot open notes file
../../gcovdata/openssl-1.0.0/./apps/./apps/ca.gcno:cannot open notes file
../../gcovdata/openssl-1.0.0/./apps/./apps/ciphers.gcno:cannot open notes file
../../gcovdata/openssl-1.0.0/./apps/./apps/cms.gcno:cannot open notes file
../../gcovdata/openssl-1.0.0/./apps/./apps/crl2p7.gcno:cannot open notes file
...
我也尝试过这个,但它不起作用,我收到错误:
for x in ./**/*.c; do
echo $x
gcov $x
done
$ ./run_tests.sh openssl-1.0.0
./apps/app_rand.c
File 'app_rand.c'
Lines executed:37.50% of 40
Creating 'app_rand.c.gcov'
Cannot open source file app_rand.c
./apps/apps.c
File 'apps.c'
Lines executed:33.76% of 939
Creating 'apps.c.gcov'
Cannot open source file apps.c
...
我尝试了一个命令:
$ gcov ./apps/app_rand.c
File 'app_rand.c'
Lines executed:37.50% of 40
Creating 'app_rand.c.gcov'
Cannot open source file app_rand.c
看起来我只能对同一文件夹中的文件运行 gcov 。我应该如何解决这个问题?我应该在循环中的目录中进行 cd,然后移动文件吗?或者我做错了什么?
我在文件夹中尝试使用 -o 选项,但它不起作用:
$ pwd
/home/blackcat/gcov_project/projects/openssl-1.0.0/test
$ ls bftest.*
bftest.c bftest.c.gcov bftest.gcda bftest.gcno bftest.o
$ gcov -o ~/gcov_project/gcov/ bftest.c
/home/blackcat/gcov_project/gcov/bftest.gcno:cannot open notes file
$ gcov bftest.c
File 'bftest.c'
Lines executed:47.52% of 101
Creating 'bftest.c.gcov'
File '/usr/include/x86_64-linux-gnu/bits/stdio2.h'
Lines executed:100.00% of 1
Creating 'stdio2.h.gcov'
File '/usr/include/x86_64-linux-gnu/bits/string3.h'
Lines executed:100.00% of 2
Creating 'string3.h.gcov'
更新2:从 Gilles 解决方案开始,我创建了一个工作代码。谢谢。最后,我将它们全部放在同一个目录中,但我从它们的路径创建了一个前缀。
### Generate and copy gcov files ###
cd "$TARGET_DIR"
mkdir -p "$OUTPUT_DIR"
CDIR=""
for x in **/*.c; do
if [ "$CDIR" != "$TARGET_DIR/${x%/*}" ]; then
CDIR="$TARGET_DIR/${x%/*}"
cd $CDIR
gcov -p *.c
SUBDIR="${x%/*}"
PREFIX="#${SUBDIR/\//\#}"
for f in *.gcov; do
if [[ $f == \#* ]] ;
then
cp $f "$OUTPUT_DIR/$f"
else
cp $f "$OUTPUT_DIR/$PREFIX#$f"
fi
done
fi
done
答案1
您拥有命令,因此请将它们放入脚本中!
要对不同的数据运行一堆命令,请将变化的数据放入多变的。
要运行gcov
所有mv
文件,有几种可能的方法,包括:
- 运行
gcov
所有文件,然后移动它们。 - 在一个文件上运行
gcov
,然后移动其输出。 gconv
对目录中的文件运行,然后移动它们。
第一种方法不起作用,因为gcov
需要在包含源文件的目录中执行。第三种基于目录的方法实际上是三种方法中最复杂的一种:最简单的方法是gcov
一次运行一个文件。
在 bash 中,您可以使用以下命令递归枚举目录及其子目录中的所有 C 文件通配符模式 **/*.c
。**
需要使用以下命令启用通配符globstar
选项。要迭代文件,请使用for loop
。
要更改到某个目录只是为了运行一个命令,请cd
在 a 中运行该命令子外壳: (cd … && gcov …)
。
您还需要另一种类型的 shell 构造:对文件名进行一些操作以提取目录部分。这参数扩展构造扩展为具有与删除的模式匹配的最短后缀${x%/*}
的变量的值。换句话说,这是存储在.如果仅包含没有目录部分的文件名(即与 相对),则这将不起作用;碰巧OpenSSL 源代码树的根部没有文件,但有一个简单的方法可以确保文件名以 开头,它指定当前目录。x
/*
x
x
foo
bar/foo
.c
./
./config
使用所需选项运行后,在 OpenSSL 源代码树的根部调用此脚本。
#!/bin/bash
shopt -s globstar
gcov_data_dir="../../gcovdata/${PWD##*/}"
make
make tests
for x in ./**/*.c; do
mkdir -p "$gcov_data_dir/${x%/*}"
(cd "${x%/*}" && gcov "${x##*/}") &&
mv "$x.gcov" "$gcov_data_dir/${x%/*}"
done
为了避免移动文件.gcov
,另一种方法是创建一个指向编译目录的符号链接林,并gcov
在该gcovdata
目录中运行。借助 GNU coreutils(即在非嵌入式 Linux 或 Cygwin 上),您可以使用cp -al
.
cp -al openssl-1.0.0 gcovdata
cd gcovdata
for x in ./**/*.c; do
(cd "${x%/*}" && gcov "${x##*/}")
done
答案2
运行 gcov 后,只需执行以下操作:
mv *.gcov sub-folder-name
mv *.gcda sub-folder-name
mv *.gcno sub-folder-name