How to create gcov files for a project in a different dir?
You have the commands, so put them in a script!
To run a bunch of commands on different data, put the changing data in a variable.
To run gcov
and mv
on all the files, there are several possible methods, including:
- Run
gcov
on all files, then move them. - Run
gcov
on one file, then move its output. - Run
gconv
on the files in a directory, then move them.
The first approach doesn't work because gcov
needs to be executed in the directory containing the source files. The third directory-based approach is in fact the most complicated of the three: the simplest method would be to run gcov
on one file at a time.
In bash, you can enumerate all the C files in a directory and its subdirectories recursively with the wildcard pattern **/*.c
. The **
wildcard needs to be enabled with the globstar
option. To iterate over the files, use a for loop
.
To change into a directory just to run one command, run cd
and that command in a subshell: (cd … && gcov …)
.
You need one more type of shell construct: a bit of manipulation of file names to extract the directory part. The parameter expansion construct ${x%/*}
expands to the value of the variable x
with the shortest suffix matching the pattern /*
removed. In other words, that's the directory part of the file name stored in x
. This wouldn't work if x
consisted only of a file name with no directory part (i.e. foo
as opposed to bar/foo
); it so happens that there's no .c
file at the root of the OpenSSL source tree, but a simple way to make sure the file name starts with ./
, which designates the current directory.
Invoke this script at the root of the OpenSSL source tree, after running ./config
with your desired options.
#!/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
To avoid having to move the .gcov
files, an alternative approach would be to create a forest of symbolic links to the compilation directory, and run gcov
in the gcovdata
directory. With GNU coreutils (i.e. on non-embedded Linux or Cygwin), you can do that with cp -al
.
cp -al openssl-1.0.0 gcovdata
cd gcovdata
for x in ./**/*.c; do
(cd "${x%/*}" && gcov "${x##*/}")
done
Related videos on Youtube
BlackCat
Updated on September 18, 2022Comments
-
BlackCat over 1 year
I want to analyze code coverage datas. I want to create gcov files from OpenSSL (and from other projects), but I can only create them in the same directory of the project, and only for the files in the current folder.
I want to create them in a different directory, preserve the source original directory structure, and make the whole process as automatic as possible.
source:
~/mygcovproject/projects/openssl-1.0.0
output:
~/mygcovproject/gcovdata/openssl-1.0.0
Currently I can create the files only in this way:
$ 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)
But there is 2 big problem with this method:
1) There are many folders and subfolders.
2) I have to move the files manually.
How should I do this? Can you help me please?
Upd:
Thanks Gilles, it helped me a lot, but I still struggle with the last part. I get error messages from 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 ...
I tried this too, but it did not work, i get errors:
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 ...
I tried a single command:
$ 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
Looks like I can only run gcov on the files in the same folder. How should I solve this? Should I cd in the directories in the loop, then move the files? Or am I doing something wrong?
I tried in the folders with the -o options, but it did not worked:
$ 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'
Upd2: Starting from Gilles solution I created a working code. Thanks. In the end I put all of them in the same directory, but I created a prefix from their path.
### 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
-
Gilles 'SO- stop being evil' almost 9 years@BlackCat Sorry for the delay. I hadn't realized that gcov always writes to the current directory. I've updated my answer.
-
Scott - Слава Україні about 4 yearsI'm not sure how this is different from what the OP already knows how to do (and said so in the question). I don't see how this addresses the issue "There are many folders and subfolders." and "I want to ... make the whole process as automatic as possible."
-
Kurt Stewart about 4 yearsjust add them to a shell script file and call it compciv.org/recipes/cli/basic-shell-scripts