2005-06-27 01:01:07 +00:00
|
|
|
# -*-perl-*-
|
|
|
|
|
|
|
|
$description = 'Test the $(shell ...) function.';
|
|
|
|
|
|
|
|
$details = '';
|
|
|
|
|
2015-07-13 01:03:24 +00:00
|
|
|
# Test standard shell
|
|
|
|
run_make_test('.PHONY: all
|
|
|
|
OUT := $(shell echo hi)
|
|
|
|
all: ; @echo $(OUT)
|
|
|
|
','','hi');
|
2005-06-27 01:01:07 +00:00
|
|
|
|
|
|
|
# Test shells inside rules.
|
|
|
|
run_make_test('.PHONY: all
|
|
|
|
all: ; @echo $(shell echo hi)
|
2015-07-13 01:03:24 +00:00
|
|
|
','','hi');
|
|
|
|
|
|
|
|
# Verify .SHELLSTATUS
|
|
|
|
run_make_test('.PHONY: all
|
|
|
|
PRE := $(.SHELLSTATUS)
|
|
|
|
$(shell exit 0)
|
|
|
|
OK := $(.SHELLSTATUS)
|
|
|
|
$(shell exit 1)
|
|
|
|
BAD := $(.SHELLSTATUS)
|
|
|
|
all: ; @echo PRE=$(PRE) OK=$(OK) BAD=$(BAD)
|
|
|
|
','','PRE= OK=0 BAD=1');
|
2005-06-27 01:01:07 +00:00
|
|
|
|
2009-09-28 23:08:49 +00:00
|
|
|
# Test unescaped comment characters in shells. Savannah bug #20513
|
2016-12-22 23:47:26 +00:00
|
|
|
run_make_test(q!
|
2009-09-28 23:08:49 +00:00
|
|
|
FOO := $(shell echo '#')
|
|
|
|
foo: ; echo '$(FOO)'
|
|
|
|
!,
|
2016-12-22 23:47:26 +00:00
|
|
|
'', "echo '#'\n#\n");
|
2009-09-28 23:08:49 +00:00
|
|
|
|
2022-06-19 00:25:30 +00:00
|
|
|
# Test that exported variables are passed to $(shell ...)
|
|
|
|
$ENV{FOO} = 'baz';
|
|
|
|
run_make_test(q!
|
|
|
|
OUT = $(shell echo $$FOO)
|
|
|
|
foo: ; @echo '$(OUT)'
|
|
|
|
!,
|
|
|
|
'', 'baz');
|
|
|
|
|
|
|
|
$ENV{FOO} = 'baz';
|
|
|
|
run_make_test(q!
|
|
|
|
FOO = bar
|
|
|
|
OUT = $(shell echo $$FOO)
|
|
|
|
foo: ; @echo '$(OUT)'
|
|
|
|
!,
|
|
|
|
'', 'bar');
|
|
|
|
|
|
|
|
run_make_test(q!
|
|
|
|
export FOO = bar
|
|
|
|
OUT = $(shell echo $$FOO)
|
|
|
|
foo: ; @echo '$(OUT)'
|
|
|
|
!,
|
|
|
|
'', 'bar');
|
|
|
|
|
|
|
|
# Test shells inside exported environment variables, simply expanded.
|
|
|
|
run_make_test('
|
|
|
|
export HI := $(shell echo hi)
|
|
|
|
.PHONY: all
|
|
|
|
all: ; @echo $$HI
|
|
|
|
',
|
|
|
|
'','hi');
|
|
|
|
|
|
|
|
# Test shells inside exported environment variables. See SV 10593
|
2005-06-27 01:01:07 +00:00
|
|
|
run_make_test('
|
|
|
|
export HI = $(shell echo hi)
|
|
|
|
.PHONY: all
|
|
|
|
all: ; @echo $$HI
|
2022-06-19 00:25:30 +00:00
|
|
|
',
|
|
|
|
'',"hi");
|
|
|
|
|
|
|
|
$ENV{HI} = 'foo';
|
|
|
|
run_make_test('
|
|
|
|
HI = $(shell echo hi)
|
|
|
|
.PHONY: all
|
|
|
|
all: ; @echo $$HI
|
|
|
|
',
|
|
|
|
'',"hi");
|
|
|
|
|
|
|
|
$ENV{HI} = 'foo';
|
|
|
|
run_make_test('
|
|
|
|
HI = $(shell echo hi)
|
|
|
|
bad := $(HI)
|
|
|
|
.PHONY: all
|
|
|
|
all: ; @echo $$HI $(bad)
|
|
|
|
',
|
|
|
|
'',"hi hi");
|
2005-06-27 01:01:07 +00:00
|
|
|
|
2022-09-08 06:25:20 +00:00
|
|
|
# SV 63016: Exported variable that contains a variable containing $(shell...)
|
|
|
|
|
|
|
|
run_make_test('
|
|
|
|
HI = $(shell echo hi)
|
|
|
|
export bad = $(HI)
|
|
|
|
.PHONY: all
|
|
|
|
all:; : $(HI)
|
|
|
|
',
|
|
|
|
'',": hi");
|
|
|
|
|
2022-09-10 20:21:23 +00:00
|
|
|
$ENV{HI} = 'outer';
|
|
|
|
run_make_test('
|
|
|
|
export HI = $(shell echo $$HI)
|
|
|
|
.PHONY: all
|
|
|
|
all:; @echo $$HI
|
|
|
|
',
|
|
|
|
'',"outer");
|
|
|
|
|
|
|
|
$ENV{HI} = 'outer';
|
|
|
|
run_make_test('
|
|
|
|
export HI = $(shell echo $$HI)
|
|
|
|
.PHONY: all
|
|
|
|
all:; : $(HI)
|
|
|
|
',
|
|
|
|
'',": outer");
|
|
|
|
|
2017-04-17 19:37:57 +00:00
|
|
|
if ($port_type ne 'W32') {
|
2018-07-01 20:13:13 +00:00
|
|
|
# Test shell errors in recipes including offset
|
|
|
|
# This needs to be ported to Windows, or else Windows error messages
|
|
|
|
# need to converted to look like more normal make errors.
|
2017-04-17 19:37:57 +00:00
|
|
|
run_make_test('
|
2022-02-06 21:22:40 +00:00
|
|
|
.RECIPEPREFIX = >
|
2016-04-10 21:12:48 +00:00
|
|
|
all:
|
2022-02-06 21:22:40 +00:00
|
|
|
>@echo hi
|
|
|
|
>$(shell ./basdfdfsed there)
|
|
|
|
>@echo $(.SHELLSTATUS)
|
2016-04-10 21:12:48 +00:00
|
|
|
',
|
2018-08-04 16:20:11 +00:00
|
|
|
'', "#MAKE#: ./basdfdfsed: $ERR_no_such_file\nhi\n127\n");
|
|
|
|
|
|
|
|
run_make_test('
|
|
|
|
$(shell ./basdfdfsed where)
|
|
|
|
all: ; @echo $(.SHELLSTATUS)
|
|
|
|
',
|
|
|
|
'', "#MAKE#: ./basdfdfsed: $ERR_no_such_file\n127\n");
|
2018-07-01 20:13:13 +00:00
|
|
|
|
|
|
|
# Test SHELLSTATUS for kill.
|
|
|
|
# This test could be ported to Windows, using taskkill ... ?
|
2019-09-21 18:01:19 +00:00
|
|
|
|
|
|
|
# Figure out the exit code for SIGINT
|
|
|
|
my $pid = fork();
|
|
|
|
if (! $pid) {
|
|
|
|
exec('kill -2 $$') or die "exec: Cannot execute sleep\n";
|
|
|
|
}
|
|
|
|
waitpid($pid, 0);
|
|
|
|
# .SHELLSTATUS for a signal gives 128 + the signal number
|
2019-10-08 22:28:10 +00:00
|
|
|
my $ret = $?;
|
|
|
|
if ($ret > 255) {
|
|
|
|
# Solaris 10 perl 5.8.4 puts signal number + 128 into the high 8 bits.
|
|
|
|
$ret >>= 8;
|
|
|
|
}
|
2023-01-08 02:50:59 +00:00
|
|
|
if ($osname ne 'os390') {
|
|
|
|
$ret |= 128;
|
|
|
|
}
|
2019-09-21 18:01:19 +00:00
|
|
|
|
2018-07-01 20:13:13 +00:00
|
|
|
run_make_test('.PHONY: all
|
|
|
|
$(shell kill -2 $$$$)
|
2019-09-21 18:01:19 +00:00
|
|
|
STAT := $(.SHELLSTATUS)
|
|
|
|
all: ; @echo STAT=$(STAT)
|
|
|
|
','',"STAT=$ret\n");
|
2022-02-06 21:22:40 +00:00
|
|
|
|
|
|
|
# Test that not-found errors can be redirected
|
|
|
|
if ($ERR_command_not_found) {
|
|
|
|
$_ = $ERR_command_not_found;
|
|
|
|
s/#CMDNAME#/bad-command/g;
|
|
|
|
run_make_test(q!
|
|
|
|
out := $(shell bad-command 2>&1)
|
|
|
|
all: ; @echo '$(.SHELLSTATUS): $(out)'
|
|
|
|
!,
|
|
|
|
'', "127: $_\n");
|
|
|
|
}
|
2022-07-16 23:43:34 +00:00
|
|
|
|
|
|
|
# If we're using pipes for jobserver, then we will close them and not
|
|
|
|
# allow them to be available to sub-makes invoked via $(shell ...)
|
Rework output sync to lock a temp file on POSIX
Some POSIX systems do not allow locks to be taken on non-files, such
as pipes. This is a problem since very often make is invoked with
its stdout redirected to a pipe. Also, if stdout is redirected to a
file that already has a lock on it for some other reason (perhaps a
shared file such as /dev/null) it can cause a hang.
This means our previous method of locking stdout, although it had some
nice advantages, is not portable enough. Instead, use a temporary
file and take the lock on that. We pass the name of the file to child
make processes. On Windows we continue to use a shared mutex for
output sync.
Remove POSIX emulation functions like fcntl from Windows; instead
follow the lead of the jobserver and create an interface in os.h for
output sync, and move the OS-specific content to posixos.c and
w32os.c.
* NEWS: Add a note.
* src/makeint.h (ALL_SET): Check that all bits are set.
* src/os.h: Add bits for checking the state of stdin/stdout/stderr.
Add prototypes for OS-specific output sync methods.
* src/posixos.c (check_io_state): Determine the status of stdin,
stdout, stderr an return a suite of bits describing them.
(osync_enabled): If the global variable holding the FD of the lock
file (osync_handle) is valid return true.
(osync_setup): Create a temporary file and remember its name in a
global variable (osync_tmpfile), and set osync_handle.
(osync_get_mutex): If output sync is enabled, return the filename
of the lock file prefixed with "fnm:" to denote a filename.
(osync_parse_mutex): If the provided filename has the wrong format
disable output sync. Else open the lock file and set osync_handle.
(osync_clear): Close osync_handle. If we're the parent make, then
also unlink the temporary file.
(osync_acquire): Take a lock on the osync_handle descriptor.
(osync_release): Release the lock on the osync_handle descriptor.
(fd_set_append): Add APPEND mode to a file descriptor.
* src/w32/w32os.c: Perform the same actions as posixos.c, copying
the details from src/w32/compat/posixfcn.c. Use a mutex rather
than locking a temporary file.
* src/output.h: Remove all the OS-specific content.
* src/output.c: Remove all the OS-specific content.
(set_append_mode): Remove and replace with fd_set_append().
(sync_init): Remove and replace with check_io_state().
(acquire_semaphore): Remove and replace with osync_acquire().
(release_semaphore): Remove and replace with osync_release().
(setup_tmpfile): If the IO state is not obtained, get it. If stdout
and/or stderr are valid, set up a tempfile to capture them.
(output_init): Set io_state if not set already, and check it when
deciding whether to close stdout on exit.
* src/main.c (main): If we're syncing, set up the mutex using the
new osync_setup() / osync_parse_mutex() methods.
(prepare_mutex_handl_string): Replace with osync_parse_mutex().
(die): Call osync_clear().
* src/w32/compat/posixfcn.c: Remove implementations of fcntl(),
record_sync_mutex(), create_mutex(), and same_stream().
2022-08-29 00:15:35 +00:00
|
|
|
if (exists $FEATURES{'jobserver'}) {
|
|
|
|
run_make_test(q!
|
2022-07-16 23:43:34 +00:00
|
|
|
ifeq ($(ELT),)
|
|
|
|
default:; @$(MAKE) -f #MAKEFILE# ELT=1
|
|
|
|
else ifeq ($(ELT),1)
|
|
|
|
OUTPUT := $(shell $(MAKE) -f #MAKEFILE# ELT=2)
|
|
|
|
$(info $(OUTPUT))
|
|
|
|
default:;: $(ELT)
|
|
|
|
else
|
|
|
|
default:;: $(ELT)
|
|
|
|
endif
|
|
|
|
!,
|
2023-04-01 19:57:04 +00:00
|
|
|
'--no-print-directory -j2 --jobserver-style=pipe', "#MAKE#[2]: warning: jobserver unavailable: using -j1 (add '+' to parent make rule)\n: 2\n: 1");
|
Rework output sync to lock a temp file on POSIX
Some POSIX systems do not allow locks to be taken on non-files, such
as pipes. This is a problem since very often make is invoked with
its stdout redirected to a pipe. Also, if stdout is redirected to a
file that already has a lock on it for some other reason (perhaps a
shared file such as /dev/null) it can cause a hang.
This means our previous method of locking stdout, although it had some
nice advantages, is not portable enough. Instead, use a temporary
file and take the lock on that. We pass the name of the file to child
make processes. On Windows we continue to use a shared mutex for
output sync.
Remove POSIX emulation functions like fcntl from Windows; instead
follow the lead of the jobserver and create an interface in os.h for
output sync, and move the OS-specific content to posixos.c and
w32os.c.
* NEWS: Add a note.
* src/makeint.h (ALL_SET): Check that all bits are set.
* src/os.h: Add bits for checking the state of stdin/stdout/stderr.
Add prototypes for OS-specific output sync methods.
* src/posixos.c (check_io_state): Determine the status of stdin,
stdout, stderr an return a suite of bits describing them.
(osync_enabled): If the global variable holding the FD of the lock
file (osync_handle) is valid return true.
(osync_setup): Create a temporary file and remember its name in a
global variable (osync_tmpfile), and set osync_handle.
(osync_get_mutex): If output sync is enabled, return the filename
of the lock file prefixed with "fnm:" to denote a filename.
(osync_parse_mutex): If the provided filename has the wrong format
disable output sync. Else open the lock file and set osync_handle.
(osync_clear): Close osync_handle. If we're the parent make, then
also unlink the temporary file.
(osync_acquire): Take a lock on the osync_handle descriptor.
(osync_release): Release the lock on the osync_handle descriptor.
(fd_set_append): Add APPEND mode to a file descriptor.
* src/w32/w32os.c: Perform the same actions as posixos.c, copying
the details from src/w32/compat/posixfcn.c. Use a mutex rather
than locking a temporary file.
* src/output.h: Remove all the OS-specific content.
* src/output.c: Remove all the OS-specific content.
(set_append_mode): Remove and replace with fd_set_append().
(sync_init): Remove and replace with check_io_state().
(acquire_semaphore): Remove and replace with osync_acquire().
(release_semaphore): Remove and replace with osync_release().
(setup_tmpfile): If the IO state is not obtained, get it. If stdout
and/or stderr are valid, set up a tempfile to capture them.
(output_init): Set io_state if not set already, and check it when
deciding whether to close stdout on exit.
* src/main.c (main): If we're syncing, set up the mutex using the
new osync_setup() / osync_parse_mutex() methods.
(prepare_mutex_handl_string): Replace with osync_parse_mutex().
(die): Call osync_clear().
* src/w32/compat/posixfcn.c: Remove implementations of fcntl(),
record_sync_mutex(), create_mutex(), and same_stream().
2022-08-29 00:15:35 +00:00
|
|
|
}
|
2022-09-25 17:29:59 +00:00
|
|
|
|
|
|
|
# This crashes if we use vfork and don't reset environ properly
|
|
|
|
run_make_test(q!
|
|
|
|
export PATH = $(shell echo "tests:$$PATH")
|
|
|
|
foo = $(shell echo yes)
|
|
|
|
|
|
|
|
all:;echo $(foo)
|
|
|
|
!,
|
|
|
|
'', "echo yes\nyes\n");
|
Support implementing the jobserver using named pipes
Using anonymous pipes for jobserver support has some advantages:
for example there is nothing on disk that needs to be cleaned up.
However it has many obscure problems, related to the fact that in
order for it to work we need to ensure these resources are properly
passed through to child processes that want to use the jobserver.
At the same time we don't want to pass the pipe to process which
DON'T know about the jobserver.
Other processes can open file descriptors which we then think are
our jobserver, but aren't. And, we open the pipe file descriptors
in blocking mode which doesn't work for all users.
See issues such as SV 57178, SV 57242, and SV 62397
To avoid these issues, use named pipes (on systems where they are
available) instead of anonoymous pipes. This simplifies many things:
we never need to pass open file descriptors to our children; they
can open the jobserver named pipe. We don't need to worry about
recursive vs. non-recursive children. Users don't have to "pass
through" the resources if they are invoking sub-makes. Each child
can open its own file descriptor and set blocking as needed.
The downside is the named pipe exists on disk and so must be cleaned
up when the "top-level" make instance exits.
In order to allow make to continue to be used in build systems where
older versions of GNU make, or other tools that want to use the
jobserver, but don't understand named pipes, introduce a new option
--jobserver-style that allows the user to choose anonymous pipes.
* NEWS: Announce the change and the --jobserver-style option.
* doc/make.1: Add --jobserver-style documentation.
* doc/make.texi (Special Variables): Add missing items to .FEATURES.
(Options Summary): Add --jobserver-style.
(POSIX Jobserver): Named pipes, changes to --jobserver-auth, and the
--jobserver-style option.
(Windows Jobserver): Document --jobserver-style for Windows.
* configure.ac: Check for mkfifo.
* src/config.h-vms.template: Undefined HAVE_MKFIFO.
* src/config.h.W32.template: Ditto.
* src/main.c: Add jobserver-style as a new command line option.
(main): Add jobserver-fifo to .FEATURES if supported. Pass the style
option to jobserver_setup().
* src/os.h (jobserver_setup): Accept a style string option.
* src/posixos.c (enum js_type): Enumeration of the jobserver style.
(js_type): Which style we are currently using.
(fifo_name): The path to the named pipe (if in use).
(jobserver_setup): If no style is given, or "fifo" is given, set up a
named pipe: get a temporary file and use mkfifo() on it, then open it
for reading and writing. If something fails fall back to anonymous
pipes.
(jobserver_parse_auth): Parse jobserver-auth to determine the style.
If we are using a named pipe, open it. If we're using anonymous pipes
ensure they're valid as before.
(jobserver_get_invalid_auth): Don't invalidate the jobserver when
using named pipes.
(jobserver_clear): Clean up memory used for named pipes.
(jobserver_acquire_all): Unlink the named pipe when done.
* src/w32/w32os.c (jobserver_setup): Check the style argument.
* tests/scripts/features/jobserver: Use --jobserver-style to test
the anonymous pipe behavior, and also test named pipe/semaphore
behavior. Check invalid jobserver-style options.
* tests/scripts/functions/shell: Use --jobserver-style to test the
anonymous pipe behavior, and also test named pipe/semaphore
behavior.
2022-08-02 22:07:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# If we're not using pipes for jobserver, then they are available in sub-makes
|
|
|
|
# invoked by $(shell ...)
|
|
|
|
if ($port_type eq 'W32' || exists $FEATURES{'jobserver-fifo'}) {
|
|
|
|
run_make_test(q!
|
|
|
|
ifeq ($(ELT),)
|
|
|
|
default:; @$(MAKE) -f #MAKEFILE# ELT=1
|
|
|
|
else ifeq ($(ELT),1)
|
|
|
|
OUTPUT := $(shell $(MAKE) -f #MAKEFILE# ELT=2)
|
|
|
|
$(info $(OUTPUT))
|
|
|
|
default:;: $(ELT)
|
|
|
|
else
|
|
|
|
default:;: $(ELT)
|
|
|
|
endif
|
|
|
|
!,
|
|
|
|
'--no-print-directory -j2', ": 2\n: 1");
|
2017-04-17 19:37:57 +00:00
|
|
|
}
|
2016-04-10 21:12:48 +00:00
|
|
|
|
2024-04-21 17:35:33 +00:00
|
|
|
# sv 65323. Check for bash, because such long variable name causes ksh to
|
|
|
|
# segfault.
|
|
|
|
if (-x '/bin/bash') {
|
2024-01-18 22:54:59 +00:00
|
|
|
# sv 65172.
|
|
|
|
# Buffer overrun in recursively_expand_for_file on a variable with a long
|
|
|
|
# name.
|
|
|
|
my $v = "a1234567890" x 4 x 1000;
|
|
|
|
run_make_test("
|
2024-04-21 17:35:33 +00:00
|
|
|
SHELL:=/bin/bash
|
2024-01-18 22:54:59 +00:00
|
|
|
export $v=\$(shell echo hello)
|
|
|
|
all:; \@echo \$\$$v
|
|
|
|
", '', "hello\n");
|
|
|
|
}
|
|
|
|
|
2005-06-27 01:01:07 +00:00
|
|
|
1;
|