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