mirror of
https://git.savannah.gnu.org/git/make.git
synced 2025-02-04 22:02:19 +00:00
07187db947
Appending to a pattern specific variable produces an incorrect value in the presence of a command line definition or an env override of the variable. Also, fix pattern/target-specific appending to a variable with origin override. * At parse time record_target_var sets the value of a pattern specific variable to the value defined on command line or to the value of the env override. * Later, at build time, recursively_expand_for_file appends this value of the variable (set in record_target_var) to the command line value again, regardless of the origin of the variable. This patch modifies recursively_expand_for_file to avoid appending, unless the origin of the variable beats or equals the origin of one of the parent definitions of this variable. Reported by Rob <robw9739@gmail.com>, Brian Vandenberg <phantall@gmail.com>, Markus Oberhumer <markus@oberhumer.com>. * NEWS: Note the change. * src/variable.c (do_variable_definition): Avoid merging a pattern-specific variable with the parent definition when a command line or env override is present. * src/expand.c (recursively_expand_for_file): Avoid appending to a pattern-specific variable, unless the origin of this pattern-specific variable beats or equals the origin of one of the parent definitions of this variable. * doc/make.texi (Override Directive): Add missing cross-reference. * tests/scripts/variables/append: Add tests.
280 lines
8.4 KiB
Perl
280 lines
8.4 KiB
Perl
# -*-perl-*-
|
|
|
|
use warnings;
|
|
|
|
my $description = "Test appending to variables of various origins.";
|
|
|
|
# sv 64822, sv 36486.
|
|
# Test various combinations of appends in the presence and absence of command
|
|
# line definitions, env overrides and makefile overrides.
|
|
# Test the following statements.
|
|
# A target or pattern specific definition or append is available at build time
|
|
# only.
|
|
# A definition with a makefile override can only be appended to with another
|
|
# override.
|
|
# A definition with a makefile override can only be redefined with another
|
|
# override.
|
|
# A target or pattern specific definition takes precedence over a global
|
|
# definition for that target.
|
|
# A global variable is immune to a target or pattern specific definition or
|
|
# append.
|
|
# A target or pattern specific definition is immune to another target or pattern
|
|
# specific definition or append.
|
|
# A prerequisite inherits a target or pattern specific value from its target.
|
|
# "phobos" inherits the value of "hello" from "mars".
|
|
|
|
my @goals = ('phobos', 'mars');
|
|
my @specificities = ('', 's: ', '%: ');
|
|
my @inits = ('', 'hello=file', 'hello:=file', 'override hello=file');
|
|
my @global_append = ('', 'hello+=red');
|
|
my @blue_override = ('', 'override ');
|
|
my @yellow_override = ('', 'override ');
|
|
my @cmdline = ('', 'hello=cmd', 'hello:=cmd hello+=cmd2');
|
|
my @env_ovr = ('', '-e');
|
|
my @envs = ('', 'env');
|
|
|
|
for my $goal (@goals) {
|
|
for my $spec (@specificities) {
|
|
for my $init (@inits) {
|
|
for my $ga (@global_append) {
|
|
for my $bovr (@blue_override) {
|
|
for my $yovr (@yellow_override) {
|
|
for my $dashe (@env_ovr) {
|
|
for my $env (@envs) {
|
|
for my $cmd (@cmdline) {
|
|
|
|
if ($env) {
|
|
$ENV{'hello'} = 'env';
|
|
} else {
|
|
delete $ENV{'hello'};
|
|
}
|
|
|
|
my $parse_time_answer = '';
|
|
my $build_time_answer = '';
|
|
|
|
# For goal "phobos" target is "", "phobos: " and "phobo%: ".
|
|
# For goal "mars" target is "", "mars: " and "mar%: ".
|
|
my $target = '';
|
|
if ($spec) {
|
|
$target = $goal;
|
|
chop($target);
|
|
$target .= $spec;
|
|
}
|
|
|
|
if ($init =~ 'override') {
|
|
$build_time_answer = 'file';
|
|
} elsif ($cmd) {
|
|
$build_time_answer = $cmd =~ 'cmd2' ? 'cmd cmd2' : 'cmd';
|
|
} elsif ($dashe and $env) {
|
|
$build_time_answer = 'env';
|
|
} elsif ($init and !$target and $ga) {
|
|
$build_time_answer = 'file red';
|
|
} elsif ($init) {
|
|
$build_time_answer = 'file';
|
|
} elsif ($env and $ga) {
|
|
$build_time_answer = 'env red';
|
|
} elsif ($env) {
|
|
$build_time_answer = 'env';
|
|
} elsif ($ga) {
|
|
$build_time_answer = 'red';
|
|
}
|
|
|
|
if ($bovr and $yovr) {
|
|
$build_time_answer .= ' ' if ($build_time_answer);
|
|
$build_time_answer .= 'blue yellow';
|
|
} elsif ($bovr) {
|
|
$build_time_answer .= ' ' if ($build_time_answer);
|
|
$build_time_answer .= 'blue';
|
|
} elsif ($yovr and !($init =~ 'override') and !$cmd and !($dashe and $env)) {
|
|
$build_time_answer .= ' ' if ($build_time_answer);
|
|
$build_time_answer .= 'blue yellow';
|
|
} elsif ($yovr) {
|
|
$build_time_answer .= ' ' if ($build_time_answer);
|
|
$build_time_answer .= 'yellow';
|
|
} elsif ($init =~ 'override') {
|
|
} elsif ($cmd) {
|
|
} elsif ($dashe and $env) {
|
|
} else {
|
|
$build_time_answer .= ' ' if ($build_time_answer);
|
|
$build_time_answer .= 'blue yellow';
|
|
}
|
|
|
|
|
|
if ($cmd and $target) {
|
|
$parse_time_answer = $cmd =~ 'cmd2' ? 'cmd cmd2' : 'cmd';
|
|
} elsif ($env and !$dashe and $target and $ga) {
|
|
$parse_time_answer = 'env red';
|
|
} elsif ($env and $target) {
|
|
$parse_time_answer = 'env';
|
|
} elsif ($target and $ga) {
|
|
$parse_time_answer = 'red';
|
|
} elsif ($target) {
|
|
$parse_time_answer = '';
|
|
} else {
|
|
$parse_time_answer = $build_time_answer;
|
|
}
|
|
|
|
my $i = $init ? "$target$init" : '';
|
|
|
|
# moon and satur% specific settings test that target and pattern
|
|
# settings specific to one target do not affect another target.
|
|
|
|
my $answer = $goal eq "mars" ?
|
|
"$parse_time_answer\n$build_time_answer\n" # From parse time and from "phobos" recipe.
|
|
. "$build_time_answer\n#MAKE#: 'mars' is up to date.\n" : # From "mars" recipe.
|
|
"$parse_time_answer\n$build_time_answer\n#MAKE#: 'phobos' is up to date.\n";
|
|
|
|
|
|
run_make_test("
|
|
# goal = $goal
|
|
# init = $init
|
|
# target = $target
|
|
# ga = $ga
|
|
# bovr = $bovr
|
|
# yovr = $yovr
|
|
# cmd = $cmd
|
|
# env = $env
|
|
# dashe = $dashe
|
|
|
|
moon: hello=1
|
|
moon: override hello+=2
|
|
|
|
$i
|
|
$ga
|
|
$target${bovr}hello+=blue
|
|
$target${yovr}hello+=yellow
|
|
|
|
satur%: override hello:=3
|
|
satur%: hello+=4
|
|
|
|
\$(info \$(hello))
|
|
phobos:; \$(info \$(hello))
|
|
mars: phobos; \$(info \$(hello))
|
|
saturn:; \$(info \$(hello))
|
|
", "$dashe $cmd $goal", "$answer");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Preferably, we would want to run the tests below for all the combinations,
|
|
# generated by the loop above. However, that causes the test to take a lot of
|
|
# time.
|
|
|
|
# The fix for sv 64822 went to recursively_expand_for_file.
|
|
# There are three code paths that lead to recursively_expand_for_file.
|
|
# - export of a variable to target environment.
|
|
# - expansion of a substitution reference.
|
|
# - other expansions of a variable that was appended to.
|
|
# Test target env, substitution reference in parse and build modes.;
|
|
# Also test a mix of pattern and target specific definitions and appends.
|
|
|
|
run_make_test(q!
|
|
al%: hello=file
|
|
al%: hello+=one
|
|
all: hello+=two
|
|
$(info $(hello))
|
|
all:; $(info $(hello))
|
|
!, "", "\nfile one two\n#MAKE#: 'all' is up to date.\n");
|
|
|
|
run_make_test(q!
|
|
hello=file
|
|
al%: hello+=one
|
|
all: hello+=two
|
|
$(info $(hello:X=Y))
|
|
all:; $(info $(hello:X=Y))
|
|
!, "", "file\nfile one two\n#MAKE#: 'all' is up to date.\n");
|
|
|
|
run_make_test(q!
|
|
hello=file
|
|
al%: hello+=one
|
|
all: hello+=two
|
|
export hello
|
|
$(info $(shell echo $$hello))
|
|
all:; $(info $(shell echo $$hello))
|
|
!, "", "file\nfile one two\n#MAKE#: 'all' is up to date.\n");
|
|
|
|
# "phobos" inherits the value of "hello" from "mars". On top of that there are
|
|
# also "phobos" specific appends.
|
|
for my $goal (@goals) {
|
|
my $answer = $goal eq "mars" ?
|
|
"\nminit mone mtwo pone ptwo\n" # From parse time and from "phobos" recipe.
|
|
. "minit mone mtwo\n#MAKE#: 'mars' is up to date.\n" : # From "mars" recipe.
|
|
"\npone ptwo\n#MAKE#: 'phobos' is up to date.\n"; # From parse time and from "phobos" recipe.
|
|
|
|
run_make_test("
|
|
mar%: hello=minit
|
|
mar%: hello+=mone
|
|
mars: hello+=mtwo
|
|
phobo%: hello+=pone
|
|
phobos: hello+=ptwo
|
|
\$(info \$(hello))
|
|
phobos:; \$(info \$(hello))
|
|
mars: phobos; \$(info \$(hello))
|
|
", "$goal", "$answer");
|
|
}
|
|
|
|
# This test is similar to the one above. The difference is that here there is a
|
|
# pattern-specific definition of "hello" that matches "phobos".
|
|
run_make_test(q!
|
|
mar%: hello:=minit
|
|
mar%: hello+=mone
|
|
mars: hello+=mtwo
|
|
phobo%: hello:=pinit
|
|
phobo%: hello+=pone
|
|
phobos: hello+=ptwo
|
|
$(info $(hello))
|
|
phobos:; $(info $(hello))
|
|
mars: phobos; $(info $(hello))
|
|
!, 'phobos', "\npinit pone ptwo\n#MAKE#: 'phobos' is up to date.\n");
|
|
|
|
# Test pattern and target specific appends to a global variable that has origin override.
|
|
# sv 36486.
|
|
my @ops = ('=', '+=', ':=');
|
|
@inits = ('', 'override ', 'al%: override ');
|
|
@specificities = ('', 'all: ', 'al%: ');
|
|
for my $init (@inits) {
|
|
for my $spec (@specificities) {
|
|
for my $op (@ops) {
|
|
|
|
my $build_time_answer = '';
|
|
if ($init =~ ':' and $op eq '+=' and !$spec) {
|
|
# This is the case where global variable obtains value 'one two three' at
|
|
# parse time and later at build time a pattern or target specific
|
|
# 'hello+=file' appends 'file'.
|
|
# e.g.
|
|
# al%: override hello+=file
|
|
# hello+=one
|
|
# hello+=two
|
|
# hello+=three
|
|
$build_time_answer = 'one two three file';
|
|
} elsif ($init =~ 'override') {
|
|
$build_time_answer = 'file';
|
|
} else {
|
|
$build_time_answer = 'file one two three';
|
|
}
|
|
|
|
my $parse_time_answer = $init =~ ':' ? '' : 'file';
|
|
if (!$spec and ($init ne 'override ')) {
|
|
$parse_time_answer .= ' ' if $parse_time_answer;
|
|
$parse_time_answer .= 'one two three';
|
|
}
|
|
|
|
run_make_test("
|
|
${init}hello${op}file
|
|
${spec}hello+=one
|
|
${spec}hello+=two
|
|
${spec}hello+=three
|
|
\$(info \$(hello))
|
|
all:; \$(info \$(hello))
|
|
", "", "$parse_time_answer\n$build_time_answer\n#MAKE#: 'all' is up to date.\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
1;
|