summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorDmitry Goncharov <dgoncharov@users.sf.net>2022-11-27 14:09:17 -0500
committerPaul Smith <psmith@gnu.org>2022-11-28 10:50:55 -0500
commitdc2d963989b96161472b2cd38cef5d1f4851ea34 (patch)
treed86b04155c58dee7f478d5501d565a3d45f0e09b /tests
parent53b8f6a5da5cd8c585d0de28d7ad6a8912061c64 (diff)
downloadmake-git-dc2d963989b96161472b2cd38cef5d1f4851ea34.tar.gz
[SV 63347] Always add command line variable assignments to MAKEFLAGS
This commit introduces two visible changes: 1. Keep command line variable assignments in MAKEFLAGS at all times, even while parsing makefiles. 2. Define makeflags immediately when a makefile modifies MAKEFLAGS. The new MAKEFLAGS and MAKEOVERRIDES initialization procedure: 1. decode_switches (argc, argv, o_command) is called to parse command line variable assignments. 2. Command line variable assignments go through quote_for_env. Initialize -*-command-variables-*- to the quoted values. 3. MAKEOVERRIDES is initialized to refer to -*-command-variables-*- with origin o_env to keep the definitions in the database intact. 4. define_makeflags() is called which adds MAKEOVERRIDES to MAKEFLAGS. 5. Makefiles are parsed. If a makefile modifies MAKEFLAGS, the new value of MAKEFLAGS is defined right away. 6. Env switches are decoded again as o_env. The definitions set by decode_switches at step 1 stay intact, as o_command beats o_env. We must preserve the original intact definitions in order to detect failure cases; for example: $ cat makefile all:; $(hello) $ make hello='$(world' makefile:1: *** unterminated variable reference. Stop. * src/makeint.h: Declare enum variable_origin, struct variable and define_makeflags(). Add parameter origin to decode_env_switches(). * src/main.c (define_makeflags): Remove "all". If a variable is assigned on the command line then append MAKEOVERRIDES to MAKEFLAGS. (decode_env_switches): Replace parameter env with origin. (decode_switches): Replace parameter env with origin. Treat origin == o_command as env == 0. (handle_non_switch_argument): Replace parameter env with origin. Treat origin == o_command as env == 0. (main): Call decode_switches() with origin==o_command before parsing makefiles. Call decode_switches() with origin==o_env after parsing makefiles. * src/variable.c (set_special_var): Define makeflags at parse time, each time a makefile modifies MAKEFLAGS. (do_variable_definition): Strip command line variable assignments from MAKEFLAGS before appending extra flags. set_special_var() adds them back. * tests/scripts/variables/MAKEFLAGS: Add tests.
Diffstat (limited to 'tests')
-rw-r--r--tests/scripts/variables/MAKEFLAGS273
1 files changed, 243 insertions, 30 deletions
diff --git a/tests/scripts/variables/MAKEFLAGS b/tests/scripts/variables/MAKEFLAGS
index a41f1cf0..e81c3277 100644
--- a/tests/scripts/variables/MAKEFLAGS
+++ b/tests/scripts/variables/MAKEFLAGS
@@ -65,79 +65,113 @@ rmdir('bar');
# Test that command line switches are all present in MAKEFLAGS.
# sv 62514.
my @opts;
+my @flavors;
# Simple flags.
@opts = ('i', 'k', 'n', 'q', 'r', 's', 'w', 'd');
exists $FEATURES{'check-symlink'} and push @opts, 'L';
+@flavors = ('=', ':=', ':::=', '+=-');
+for my $fl (@flavors) {
for my $opt (@opts) {
- run_make_test(q!
-MAKEFLAGS:=B
-all:; $(info makeflags='$(MAKEFLAGS)')
-!, "-$opt", "/makeflags='B$opt'/");
+ run_make_test("
+MAKEFLAGS${fl}B
+all:; \$(info makeflags='\$(MAKEFLAGS)')
+", "-$opt", "/makeflags='B$opt'/");
+}
}
# Switches which carry arguments.
@opts = (' -I/tmp', ' -Onone', ' --debug=b', ' -l2.5');
+for my $fl (@flavors) {
for my $opt (@opts) {
- run_make_test(q!
-MAKEFLAGS:=B
-all:; $(info makeflags='$(MAKEFLAGS)')
-!, "$opt", "/makeflags='B$opt'/");
+ run_make_test("
+MAKEFLAGS${fl}B
+all:; \$(info makeflags='\$(MAKEFLAGS)')
+", "$opt", "/makeflags='B$opt'/");
+}
}
# Long options which take no arguments.
# sv 62514.
@opts = (' --no-print-directory', ' --warn-undefined-variables', ' --trace');
+for my $fl (@flavors) {
for my $opt (@opts) {
-run_make_test(q!
-MAKEFLAGS:=B
-all:; $(info makeflags='$(MAKEFLAGS)')
-!, "$opt", "/makeflags='B$opt'/");
+run_make_test("
+MAKEFLAGS${fl}B
+all:; \$(info makeflags='\$(MAKEFLAGS)')
+", "$opt", "/makeflags='B$opt'/");
+}
}
# Test that make filters out duplicates.
# Each option is specified in the makefile, env and on the command line.
@opts = (' -I/tmp', ' -Onone', ' --debug=b', ' -l2.5');
-$ENV{'MAKEFLAGS'} = $opt;
+for my $fl (@flavors) {
for my $opt (@opts) {
+$ENV{'MAKEFLAGS'} = $opt;
run_make_test("
-MAKEFLAGS:=B $opt
+MAKEFLAGS${fl}B $opt
all:; \$(info makeflags='\$(MAKEFLAGS)')
", "$opt", "/makeflags='B$opt'/");
}
+}
# Test that make filters out duplicates.
# Each option is specified in the makefile, env and on the command line.
# decode_switches reallocates when the number of parameters in sl->list exceeds 5.
# This test exercises the realloc branch.
+for my $fl (@flavors) {
$ENV{'MAKEFLAGS'} = '-I1 -Onone --debug=b -l2.5 -I2 -I3 -I4 -I5 -I6 -I2 -I2';
-run_make_test(q!
-MAKEFLAGS:=B -I1 -Onone --debug=b -l2.5 -I2 -I3 -I4 -I5 -I6 -I2 -I2
-all:; $(info makeflags='$(MAKEFLAGS)')
-!,
+run_make_test("
+MAKEFLAGS${fl}B -I1 -Onone --debug=b -l2.5 -I2 -I3 -I4 -I5 -I6 -I2 -I2
+all:; \$(info makeflags='\$(MAKEFLAGS)')
+",
'-I1 -Onone --debug=b -l2.5 -I2 -I3 -I4 -I5 -I6',
"/makeflags='B -I1 -I2 -I3 -I4 -I5 -I6 -l2.5 -Onone --debug=b'/");
+}
# A mix of multiple flags from env, the makefile and command line.
# Skip -L since it's not available everywhere
+for my $fl (@flavors) {
$ENV{'MAKEFLAGS'} = 'ikB --no-print-directory --warn-undefined-variables --trace';
-run_make_test(q!
-MAKEFLAGS:=iknqrswd -I/tmp -I/tmp -Onone -Onone -l2.5 -l2.5
-all:; $(info makeflags='$(MAKEFLAGS)')
-!,
+run_make_test("
+MAKEFLAGS${fl}iknqrswd -I/tmp -I/tmp -Onone -Onone -l2.5 -l2.5
+all:; \$(info makeflags='\$(MAKEFLAGS)')
+",
'-Onone -l2.5 -l2.5 -Onone -I/tmp -iknqrswd -i -n -s -k -I/tmp',
"/makeflags='Bdiknqrsw -I/tmp -l2.5 -Onone --trace --warn-undefined-variables'/");
+}
-# Verify MAKEFLAGS are all available to shell functions
+# Verify MAKEFLAGS are all available to shell function at parse time.
+for my $fl (@flavors) {
+my $answer = 'Biknqrs -I/tmp -l2.5 -Onone --no-print-directory --warn-undefined-variables';
$ENV{'MAKEFLAGS'} = 'ikB --no-print-directory --warn-undefined-variables';
-run_make_test(q!
-MAKEFLAGS := iknqrsw -I/tmp -I/tmp -Onone -Onone -l2.5 -l2.5 --no-print-directory
-XX := $(shell echo "$$MAKEFLAGS")
-all:; $(info makeflags='$(XX)')
-!,
- '-Onone -l2.5 -l2.5 -Onone -I/tmp -iknqrs -i -n -s -k -I/tmp',
- "makeflags='iknqrsw -I/tmp -I/tmp -Onone -Onone -l2.5 -l2.5 --no-print-directory'");
+run_make_test("
+MAKEFLAGS${fl}iknqrsw -I/tmp -I/tmp -Onone -Onone -l2.5 -l2.5 --no-print-directory
+\$(info at parse time '\$(MAKEFLAGS)')
+XX := \$(shell echo \"\$\$MAKEFLAGS\")
+all:; \$(info at build time makeflags='\$(XX)')
+",
+'-Onone -l2.5 -l2.5 -Onone -I/tmp -iknqrs -i -n -s -k -I/tmp',
+"at parse time '$answer'
+at build time makeflags='$answer'");
+}
+
+# Verify MAKEFLAGS and command line definitions are all available to shell function at parse time.
+for my $fl (@flavors) {
+$ENV{'MAKEFLAGS'} = 'ikB --no-print-directory --warn-undefined-variables';
+my $answer = 'Biknqrs -I/tmp -l2.5 -Onone --no-print-directory --warn-undefined-variables -- hello=world';
+run_make_test("
+MAKEFLAGS${fl}iknqrsw -I/tmp -I/tmp -Onone -Onone -l2.5 -l2.5 --no-print-directory
+\$(info at parse time '\$(MAKEFLAGS)')
+XX := \$(shell echo \"\$\$MAKEFLAGS\")
+all:; \$(info at build time makeflags='\$(XX)')
+",
+'-Onone -l2.5 -l2.5 -Onone -I/tmp -iknqrs -i -n -s -k -I/tmp hello=world',
+"at parse time '$answer'
+at build time makeflags='$answer'");
+}
# Verify that command line arguments are included in MAKEFLAGS
run_make_test(q!
@@ -155,4 +189,183 @@ echo /erR --trace --no-print-directory -- FOO=bar/
/erR --trace --no-print-directory -- FOO=bar/");
+# sv 63347.
+# Verify that command line arguments are included in MAKEFLAGS
+# when makefiles are parsed.
+my $answer = 'erR -- hello:=world FOO=bar';
+run_make_test(q!
+$(info $(MAKEFLAGS))
+all:; $(info $(MAKEFLAGS))
+!, '-e FOO=bar -r -R hello:=world',
+"$answer
+$answer
+#MAKE#: 'all' is up to date.\n");
+
+# sv 63347.
+# Same as above, with makefile setting the value of the same variables as
+# defined on the cli.
+my $answer = 'erR -- hello:=world FOO=bar';
+run_make_test(q!
+$(info $(MAKEFLAGS))
+FOO=moon
+hello:=moon
+$(info $(MAKEFLAGS))
+all:; $(info $(MAKEFLAGS))
+!, '-e FOO=bar -r -R hello:=world',
+"$answer
+$answer
+$answer
+#MAKE#: 'all' is up to date.\n");
+
+# sv 63347.
+# Same as above, with makefile overriding the value of cli definition.
+my $answer = 'erR -- hello:=world FOO=bar';
+run_make_test(q!
+$(info $(MAKEFLAGS))
+override FOO=moon
+override hello:=moon
+export hello
+$(info $(MAKEFLAGS))
+all:; $(info $(MAKEFLAGS))
+!, '-e FOO=bar -r -R hello:=world',
+"$answer
+$answer
+$answer
+#MAKE#: 'all' is up to date.\n");
+
+# Same as above, and makefile overrides the value of cli definition.
+# resets MAKEOVERRIDES.
+my $answer = 'rR -- hello:=world FOO=bar';
+run_make_test(q!
+$(info $(MAKEFLAGS))
+override FOO=moon
+override hello:=moon
+export hello
+$(info $(MAKEFLAGS))
+MAKEOVERRIDES=
+$(info $(MAKEFLAGS))
+all:; $(info $(MAKEFLAGS))
+!, 'FOO=bar -r -R hello:=world',
+"$answer
+$answer
+rR -- \nrR
+#MAKE#: 'all' is up to date.\n");
+
+# sv 63347.
+# MAKEFLAGS set is env and makefile sets MAKEFLAGS and there is a command
+# line definition.
+my $answer = ' -- bye=moon hello=world';
+$ENV{'MAKEFLAGS'} = 'hello=world';
+run_make_test(q!
+$(info $(MAKEFLAGS))
+all:; $(info $(MAKEFLAGS))
+!, 'bye=moon',
+" -- bye=moon hello=world
+ -- bye=moon hello=world
+#MAKE#: 'all' is up to date.\n");
+
+# sv 63347.
+# Conditional assignment and MAKEFLAGS.
+my $answer = 'B -- bye=moon hello=world';
+$ENV{'MAKEFLAGS'} = 'hello=world';
+run_make_test(q!
+$(info $(MAKEFLAGS))
+MAKEFLAGS?=-k
+$(info $(MAKEFLAGS))
+all:; $(info $(MAKEFLAGS))
+!, '-B bye=moon',
+"$answer
+$answer
+$answer
+#MAKE#: 'all' is up to date.\n");
+
+# sv 63347.
+# MAKEFLAGS set is env and makefile sets MAKEFLAGS and there is a command
+# line definition.
+for my $fl (@flavors) {
+my $answer = ' -- bye=moon hello=world';
+$ENV{'MAKEFLAGS'} = 'hello=world';
+run_make_test("
+\$(info \$(MAKEFLAGS))
+MAKEFLAGS${fl}R
+\$(info \$(MAKEFLAGS))
+all:; \$(info \$(MAKEFLAGS))
+", 'bye=moon',
+"$answer
+R$answer
+rR$answer
+#MAKE#: 'all' is up to date.\n");
+}
+
+# sv 63347.
+# Test changes introduced by makefiles to MAKEFLAGS.
+for my $fl (@flavors) {
+my $answer = 'rR --no-print-directory -- hello:=world FOO=bar';
+run_make_test(q!
+MAKEFLAGS+=--no-print-directory
+$(info $(MAKEFLAGS))
+MAKEFLAGS+=-k
+$(info $(MAKEFLAGS))
+all:; $(info $(MAKEFLAGS))
+!, 'FOO=bar -r -R hello:=world',
+"$answer
+k$answer
+k$answer
+#MAKE#: 'all' is up to date.\n");
+}
+
+# sv 63347.
+# Test changes introduced by makefiles to MAKEFLAGS.
+# Same as above, but with -e.
+for my $fl (@flavors) {
+my $answer = 'erR -- hello:=world FOO=bar';
+run_make_test(q!
+MAKEFLAGS+=--no-print-directory
+$(info $(MAKEFLAGS))
+MAKEFLAGS+=-k
+$(info $(MAKEFLAGS))
+all:; $(info $(MAKEFLAGS))
+!, '-e FOO=bar -r -R hello:=world',
+"$answer
+$answer
+$answer
+#MAKE#: 'all' is up to date.\n");
+}
+
+mkdir('bye', 0777);
+
+create_file('bye/makefile',
+'hello=moon
+all:; $(info $(hello))');
+
+# sv 63347.
+# Test that a cli definition takes precendence over a definition set in
+# submake.
+run_make_test(q!
+v:=$(shell $(MAKE) -C bye --no-print-directory)
+all: ; $(info $(v))
+!, 'hello=world', "world #MAKE#[1]: 'all' is up to date.\n#MAKE#: 'all' is up to date.");
+
+# Same as above with the shell assignment operator.
+run_make_test(q!
+v \!= $(MAKE) -C bye --no-print-directory
+all: ; $(info $(v))
+!, 'hello=world', "world #MAKE#[1]: 'all' is up to date.\n#MAKE#: 'all' is up to date.");
+
+unlink('bye/makefile');
+rmdir('bye');
+
+# sv 63347
+# Invalid command line variable definition.
+run_make_test(q!
+all:; $(info $(hello))
+!, 'hello=\'$(world\'', "#MAKEFILE#:2: *** unterminated variable reference. Stop.\n", 512);
+
+# sv 63347
+# An unused invalid command line variable definition is ignored.
+run_make_test(q!
+all:; $(info good)
+!, 'hello=\'$(world\'', "good\n#MAKE#: 'all' is up to date.\n");
+
+
1;