Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lcovrc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@
# Note that this example script does not include all configuration options
# see 'man lcovrc(5) for a complete list and usage description.

# include some other config file
# e.g, user-specific options. Note the environment variable expansion
# config_file = $ENV{HOME}/.user_lcovrc
# or project specific - hard-coded from environment variable
# config_file = /path/to/myproject/.lcovrc
# or in the current run directory
# config_file = $ENV{PWD}/.lcovrc

# Specify an external style sheet file (same as --css-file option of genhtml)
#genhtml_css_file = gcov.css

Expand Down
133 changes: 60 additions & 73 deletions lib/lcovutil.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1009,57 +1009,6 @@ sub cleanup_callbacks
}
}

#
# apply_config(REF, ref)
#
# REF is a reference to a hash containing the following mapping:
#
# key_string => var_ref
#
# where KEY_STRING is a keyword and VAR_REF is a reference to an associated
# variable. If the global configuration hashes CONFIG or OPT_RC contain a value
# for keyword KEY_STRING, VAR_REF will be assigned the value for that keyword.
#
# Return 1 if we set something

sub _set_config($$$)
{
my ($ref, $key, $value) = @_;
my $r = $ref->{$key};
my $t = ref($r);
if ('ARRAY' eq $t) {
info(2, " append $value to list $key\n");
if ('ARRAY' eq ref($value)) {
push(@$r, @$value);
} else {
push(@$r, $value);
}
} else {
# opt is a scalar or not defined
# only way for $value to NOT be an array is if there is a bug in
# the caller such that a scalar ref was passed where a prior call
# had passed a list ref for the same RC option name
die("unexpected ARRAY for $key value")
if ('ARRAY' eq ref($value));
$$r = $value;
info(2, " assign $$r to $key\n");
}
}

sub apply_config($$)
{
my ($ref, $config) = @_;
my $set_value = 0;
foreach (keys(%{$ref})) {
# if sufficiently verbose, could mention that key is ignored
next unless exists($config->{$_});
my $v = $config->{$_};
$set_value = 1;
_set_config($ref, $_, $v); # write into options
}
return $set_value;
}

# use these list values from the RC file unless the option is
# passed on the command line
my (@rc_filter, @rc_ignore, @rc_exclude_patterns,
Expand Down Expand Up @@ -1284,27 +1233,66 @@ sub warnDeprecated
return $opt_used;
}

sub _set_config($$$)
{
# write an RC configuration value - array or scalar
my ($ref, $key, $value) = @_;
my $r = $ref->{$key};
my $t = ref($r);
if ('ARRAY' eq $t) {
info(2, " append $value to list $key\n");
if ('ARRAY' eq ref($value)) {
push(@$r, @$value);
} else {
push(@$r, $value);
}
} else {
# opt is a scalar or not defined
# only way for $value to NOT be an array is if there is a bug in
# the caller such that a scalar ref was passed where a prior call
# had passed a list ref for the same RC option name
die("unexpected ARRAY for $key value")
if ('ARRAY' eq ref($value));
$$r = $value;
info(2, " assign $$r to $key\n");
}
}

#
# read_config(filename)
#
# Read configuration file FILENAME and return a reference to a hash containing
# all valid key=value pairs found.
# read_config(filename, $optionsHash)
#
# Read configuration file FILENAME and write supported key/values into
# RC options hash
# Return: 1 if some config value was set, 0 if not (used for error messaging)

sub read_config($)
sub read_config($$); # forward decl, to make perl happy about recursive call
my %included_config_files;
my @include_stack;

sub read_config($$)
{
my $filename = shift;
my %result;
my ($filename, $opts) = @_;
my $key;
my $value;
local *HANDLE;

my $set_value = 0;
info(1, "read_config: $filename\n");
if (exists($included_config_files{abs_path($filename)})) {
lcovutil::ignorable_error($lcovutil::ERROR_USAGE,
'config file inclusion loop detected: "' .
join('" -> "', @include_stack) .
'" -> "' . $filename . '"');
return 0;
}

if (!open(HANDLE, "<", $filename)) {
lcovutil::ignorable_error($lcovutil::ERROR_USAGE,
"cannot read configuration file '$filename': $!");
return undef;
return 0; # didn't set anything
}
$included_config_files{abs_path($filename)} = 1;
push(@include_stack, $filename);
VAR: while (<HANDLE>) {
chomp;
# Skip comments
Expand Down Expand Up @@ -1337,15 +1325,15 @@ sub read_config($)
}
if (defined($key) && defined($value)) {
info(2, " set: $key = $value\n");
if (exists($result{$key})) {
if ('ARRAY' eq ref($result{$key})) {
push(@{$result{$key}}, $value);
} else {
$result{$key} = [$result{$key}, $value];
}
} else {
$result{$key} = $value;
# special case: read included file
if ($key eq 'config_file') {
$set_value |= read_config($value, $opts);
next;
}
# skip if application doesn't use this setting
next unless exists($opts->{$key});
_set_config($opts, $key, $value);
$set_value = 1;
} else {
my $context = MessageContext::context();
push(
Expand All @@ -1357,7 +1345,9 @@ sub read_config($)
}
}
close(HANDLE) or die("unable to close $filename: $!\n");
return \%result;
delete $included_config_files{abs_path($filename)};
pop(@include_stack);
return $set_value;
}

# common utility used by genhtml, geninfo, lcov to clean up RC options,
Expand Down Expand Up @@ -1387,17 +1377,14 @@ sub apply_rc_params($)

if (0 != scalar(@opt_config_files)) {
foreach my $f (@opt_config_files) {
my $cfg = read_config($f);
$set_value |= apply_config(\%rcHash, $cfg);
$set_value |= read_config($f, \%rcHash);
}
} else {
foreach my $v (['HOME', '.lcovrc'], ['LCOV_HOME', 'etc', 'lcovrc']) {
next unless exists($ENV{$v->[0]});
my $f = File::Spec->catfile($ENV{$v->[0]}, splice(@$v, 1));
if (-r $f) {
my $config = read_config($f);
# Copy configuration file and --rc values to variables
$set_value |= apply_config(\%rcHash, $config);
$set_value |= read_config($f, \%rcHash);
last;
}
}
Expand Down
5 changes: 4 additions & 1 deletion man/genhtml.1
Original file line number Diff line number Diff line change
Expand Up @@ -3231,7 +3231,10 @@ for more details.
Specify a configuration file to use.
See man
.B lcovrc(5)
for details of the file format and options.
for details of the file format and options. Also see the
.I config_file
entry in the same man page for details on how to include one config file into
another.

When this option is specified, neither the system\-wide configuration file
/etc/lcovrc, nor the per\-user configuration file ~/.lcovrc is read.
Expand Down
8 changes: 7 additions & 1 deletion man/geninfo.1
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,13 @@ libtool, disable this option to prevent problems when capturing coverage data.
.br
.RS
Specify a configuration file to use.
See the lcovrc man page for details of the file format and options.
See man
.B lcovrc(5)
for details of the file format and options.
Also see the
.I config_file
entry in the same man page for details on how to include one config file into
another.

When this option is specified, neither the system\-wide configuration file
/etc/lcovrc, nor the per\-user configuration file ~/.lcovrc is read.
Expand Down
5 changes: 4 additions & 1 deletion man/lcov.1
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,10 @@ libtool, disable this option to prevent problems when capturing coverage data.
Specify a configuration file to use.
See man
.B lcovrc(5)
for details of the file format and options.
for details of the file format and options. Also see the
.I config_file
entry in the same man page for details on how to include one config file into
another.

When this option is specified, neither the system\-wide configuration file
/etc/lcovrc, nor the per\-user configuration file ~/.lcovrc is read.
Expand Down
54 changes: 53 additions & 1 deletion man/lcovrc.5
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,21 @@ See the OPTIONS section below for details.
.br
#
.br

# include some other config file
.br
# e.g, user-specific options. Note the environment variable expansion
.br
# config_file = $ENV{HOME}/.user_lcovrc
.br
# or project specific - hard-coded from environment variable
.br
# config_file = /path/to/myproject/.lcovrc
.br
# or in the current run directory
.br
# config_file = $ENV{PWD}/.lcovrc
.br
.br
# External style sheet file
.br
#genhtml_css_file = gcov.css
Expand Down Expand Up @@ -727,6 +741,44 @@ maximum during parallel processing.

.SH OPTIONS

.BR config_file " ="
.I filename
.IP

Include another config file.

Inclusion is equivalent to inserting the text from
.I filename
at this point in the current file. As a result, settings from the included
file are processed after earlier settings in the current file, but before later settings from the current file.
As a result:

.BR "Scalar options"
set earlier in the current file are overridden by settings from the included file, and scalar options from the included file are overridden by later setting in the current file.

.BR "Array options"
from earlier in the current file appear before setting from the included file, and array options from later in the current file appear after.

Config file inclusion is recursive: an included config file may include another file - and so on.
Inclusion loops are not supported and will result in a
.I usage
error.

The most common usecase for config file inclusion is so that a site-wide or project-wide options file can include a user-specific or module-specific options file - for example, as

.RS 3
.IP
...
.br
config_file = $ENV{HOME}/.lcovrc_user
.br
...
.PP
.RE


.PP

.BR genhtml_css_file " ="
.I filename
.IP
Expand Down
26 changes: 25 additions & 1 deletion tests/gendiffcov/errs/msgtest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ set +x

source ../../common.tst

rm -f test.cpp *.gcno *.gcda a.out *.info *.log *.json diff.txt
rm -f test.cpp *.gcno *.gcda a.out *.info *.log *.json diff.txt loop*.rc markers.err*
rm -rf select criteria annotate empty unused_src scriptErr scriptFixed epoch inconsistent highlight etc mycache cacheFail expect subset context labels

clean_cover
Expand Down Expand Up @@ -203,6 +203,30 @@ if [ 0 != $? ] ; then
fi
fi

# loop in config file inclusion
echo "config_file = loop1.rc" > loop1.rc
echo lcov $LCOV_OPTS --summary initial.info --config-file loop1.rc --ignore usage
$COVER $LCOV_TOOL $LCOV_OPTS --summary initial.info --config-file loop1.rc --ignore usage 2>&1 | tee err_selfloop.log
grep "config file inclusion loop" err_selfloop.log
if [ 0 != $? ] ; then
echo "ERROR: missing config file message"
if [ 0 == $KEEP_GOING ] ; then
exit 1
fi
fi

echo "config_file = loop3.rc" > loop2.rc
echo 'config_file = $ENV{PWD}/loop2.rc' > loop3.rc
echo lcov $LCOV_OPTS --summary initial.info --config-file loop2.rc --ignore usage
$COVER $LCOV_TOOL $LCOV_OPTS --summary initial.info --config-file loop2.rc --ignore usage 2>&1 | tee err_loop.log
grep "config file inclusion loop" err_loop.log
if [ 0 != $? ] ; then
echo "ERROR: missing config file message"
if [ 0 == $KEEP_GOING ] ; then
exit 1
fi
fi


echo lcov $LCOV_OPTS --capture -d . -o build.info --build-dir $LCOV_HOME
$COVER $LCOV_TOOL $LCOV_OPTS --capture -d . -o build.info --build-dir $LCOV_HOME 2>&1 | tee build_dir_unused.log
Expand Down