[SV 62654] Support GNU Make on z/OS

Original patches provided by Igor Todorovski <itodorov@ca.ibm.com>
Reworked by Paul Smith <psmith@gnu.org>.
Thanks to IBM for providing a test system.

* NEWS: Announce support.
* AUTHORS: Ditto.
* README.zOS: Provide details on building GNU Make on z/OS.
* build.sh (get_mk_var): z/OS sh has a strange bug which causes it to
generate extra lines of output: rework the function to print output
as we compute it instead of collecting it into a variable, which
works around this bug.
* src/makeint.h: Declare MK_OS_ZOS if we're building for z/OS.
* src/arscan.c: Don't include <ar.h> on z/OS.
* src/job.c: We can't change environ in ASCII mode on z/OS.
* src/main.c: Ditto.  Also we can't use pselect() on z/OS.
* src/posixos.c: pselect() seems to hang on z/OS: don't use it.
* tests/run_make_tests.pl: Handle different exit codes on z/OS.
* tests/test_driver.pl: Preserve some special z/OS env.vars.
Add special checks to output comparisons when on z/OS.
* tests/scripts/features/archives: Don't validate names.  Don't
try to compile empty files as IBM compilers complain.
* tests/scripts/features/shell_assignment: Fix octal value of #.
* tests/scripts/features/temp_stdin: Don't print "term".
* tests/scripts/functions/shell: Handle shell exit codes.
* tests/scripts/targets/ONESHELL: Ditto.
* tests/scripts/targets/POSIX: sh -x prints differently.
* tests/scripts/variables/SHELL: Ditto.
This commit is contained in:
Paul Smith 2023-01-07 21:50:59 -05:00
parent 0de7a0d3bf
commit 11444fb001
21 changed files with 201 additions and 43 deletions

View file

@ -48,6 +48,9 @@ GNU Make porting efforts:
Troy Runkel <Troy.Runkel@mathworks.com>
Juan M. Guerrero <juan.guerrero@gmx.de>
Port to z/OS by:
Igor Todorovski <itodorov@ca.ibm.com>
-----------------------------------
Other contributors:

View file

@ -112,7 +112,7 @@ test_FILES = tests/run_make_tests tests/run_make_tests.bat \
# test/scripts are added via dist-hook below.
EXTRA_DIST = ChangeLog INSTALL README build.sh build.cfg.in $(man_MANS) \
src/mkconfig.h README.customs README.OS2 \
src/mkconfig.h README.customs README.OS2 README.zOS \
README.Amiga SCOPTIONS src/config.ami \
README.DOS builddos.bat src/configh.dos \
README.W32 build_w32.bat src/config.h.W32 \

4
NEWS
View file

@ -31,6 +31,10 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=110&se
builds with archive creation. See the "Dangers When Using Archives" section
of the GNU Make manual, and https://savannah.gnu.org/bugs/index.php?14927
* New platform: GNU Make is supported on z/OS
Thanks to Igor Todorovski <itodorov@ca.ibm.com> for the patches and testing
assistance.
* Previously target-specific variables would inherit their "export" capability
from parent target-specific variables even if they were marked private. Now
private parent target-specific variables have no affect. For more details

83
README.zOS Normal file
View file

@ -0,0 +1,83 @@
-*-text-*-
GNU Make has been ported to z/OS, tested on z/OS V2R4.
PREREQUISITES
-------------
Building GNU Make requires certain tools be installed on your z/OS system.
These tools can be downloaded from: https://github.com/ZOSOpenTools
For detailed instructions on how to set up these tools, visit
https://zosopentools.github.io/meta/#/Guides/Pre-req
You will need curl, tar, and gzip to download and unpack the GNU Make release
package, but presumably you've already worked this out if you're reading this
document!
You will need the IBM C/C++ compiler. You can download a web deliverable
add-on feature to your XL C/C++ compiler here:
https://www-40.ibm.com/servers/resourcelink/svc00100.nsf/pages/xlCC++V241ForZOsV24
Alternatively, you can install and manage C/C++ for Open Enterprise Languages
on z/OS using RedHat OpenShift Container Platform and IBM Z and Cloud
Modernization Stack.
GNU Make has a dependency on the ZOSLIB library, which is documented here:
https://zosopentools.github.io/meta/#/Guides/Zoslib.
To obtain the latest release of zoslib, you can download it from here:
https://github.com/ZOSOpenTools/zoslibport/releases.
BUILDING
--------
If you are trying to build from a checked-out Git workspace, see README.git.
Before building GNU Make, you will need to ensure that the following
environment variables are set, to turn on z/OS enhanced ASCII support:
export _BPXK_AUTOCVT=ON
export _CEE_RUNOPTS="$_CEE_RUNOPTS FILETAG(AUTOCVT,AUTOTAG) POSIX(ON)"
export _TAG_REDIR_ERR=txt
export _TAG_REDIR_IN=txt
export _TAG_REDIR_OUT=txt
To ensure proper functioning of xlclang, set the following environment
variables before building:
export _CC_CCMODE=1
export _C89_CCMODE=1
export _CXX_CCMODE=1
Set PATH_TO_ZOSLIB to the location of your zoslib installation; e.g.:
PATH_TO_ZOSLIB=$HOME/zopen/prod/zoslib
Invoke ./configure as follows:
./configure \
CC=xlclang \
CPPFLAGS="-DNSIG=42 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE -D_OPEN_SYS_FILE_EXT=1 -D_AE_BIMODAL=1 -D_ENHANCED_ASCII_EXT=0xFFFFFFF -DZOSLIB_OVERRIDE_CLIB=1" \
CFLAGS="-qascii -std=gnu11 -qnocsect -qenum=int -I$PATH_TO_ZOSLIB/include" \
LDFLAGS="-L$PATH_TO_ZOSLIB/lib" \
LIBS="-lzoslib $PATH_TO_ZOSLIB/lib/CXXRT64.x"
If you have an instance of make already available you can build with:
make
If not, you can build with:
./build.sh
TESTING
-------
To run the regression tests you'll need to install Perl and enable it.
Then you can run:
./make check
INSTALLING
----------
Copy the "make" program to wherever you want it to be installed, on your PATH.

View file

@ -42,19 +42,13 @@ defines="-DLOCALEDIR=\"$localedir\" -DLIBDIR=\"$libdir\" -DINCLUDEDIR=\"$include
# Print the value to stdout.
get_mk_var ()
{
file=$1
var=$2
val=
v=$(sed -e :a -e '/\\$/N; s/\\\n//; ta' "$file" | sed -n "s=^ *$var *\= *==p")
v=$(sed -e :a -e '/\\$/N; s/\\\n//; ta' "$1" | sed -n "s=^ *$2 *\= *==p")
for w in $v; do
case $w in
(\$[\(\{]*[\)\}]) w=${w#\$[\(\{]}; w=$(get_mk_var "$file" "${w%[\)\}]}") ;;
(\$[\(\{]*[\)\}]) w=${w#\$[\(\{]}; (get_mk_var "$1" "${w%[\)\}]}") ;;
(*) echo "$w" ;;
esac
val="${val:+$val }$w"
done
printf '%s\n' "$val"
}
# Compile source files. Object files are put into $objs.

View file

@ -331,7 +331,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *varg)
#endif
#ifndef WINDOWS32
# if !defined (__ANDROID__) && !defined (__BEOS__)
# if !defined (__ANDROID__) && !defined (__BEOS__) && !defined(MK_OS_ZOS)
# include <ar.h>
# else
/* These platforms don't have <ar.h> but have archives in the same format

View file

@ -2586,6 +2586,11 @@ exec_command (char **argv, char **envp)
if (errno == ENOENT)
errno = ENOEXEC;
# elif MK_OS_ZOS
/* In z/OS we can't set environ in ASCII mode. */
environ = envp;
execvpe(argv[0], argv, envp);
# else
/* Run the program. Don't use execvpe() as we want the search for argv[0]
@ -2653,6 +2658,9 @@ exec_command (char **argv, char **envp)
pid = spawnvpe (P_NOWAIT, shell, new_argv, envp);
if (pid >= 0)
break;
# elif MK_OS_ZOS
/* In z/OS we can't set environ in ASCII mode. */
execvpe(shell, new_argv, envp);
# else
execvp (shell, new_argv);
# endif

View file

@ -1159,7 +1159,11 @@ temp_stdin_unlink ()
}
}
#ifdef _AMIGA
#ifdef MK_OS_ZOS
extern char **environ;
#endif
#if defined(_AMIGA) || defined(MK_OS_ZOS)
int
main (int argc, char **argv)
#else
@ -1477,6 +1481,10 @@ main (int argc, char **argv, char **envp)
done before $(MAKE) is figured out so its definitions will not be
from the environment. */
#ifdef MK_OS_ZOS
char **envp = environ;
#endif
#ifndef _AMIGA
{
unsigned int i;
@ -1997,7 +2005,7 @@ main (int argc, char **argv, char **envp)
# endif
}
#ifdef HAVE_PSELECT
#if defined(HAVE_PSELECT) && !defined(MK_OS_ZOS)
/* If we have pselect() then we need to block SIGCHLD so it's deferred. */
{
sigset_t block;

View file

@ -82,6 +82,11 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
extern int errno;
#endif
/* Define macros specifying which OS we are building for. */
#if defined(__MVS__)
# define MK_OS_ZOS 1
#endif
#ifdef __VMS
/* In strict ANSI mode, VMS compilers should not be defining the
VMS macro. Define it here instead of a bulk edit for the correct code.

View file

@ -24,6 +24,10 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
#elif defined(HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#if MK_OS_ZOS
/* FIXME: HAVE_PSELECT path hangs on z/OS */
#undef HAVE_PSELECT
#endif
#if !defined(FD_OK)
# define FD_OK(_f) 1
@ -617,7 +621,7 @@ jobserver_acquire (int timeout)
go back and reap_children(), and try again. */
errno = saved_errno;
if (errno != EINTR && errno != EBADF)
if (errno != EINTR && errno != EBADF && errno != EAGAIN)
pfatal_with_name (_("read jobs pipe"));
if (errno == EBADF)

View file

@ -104,6 +104,7 @@ if ($^O eq 'VMS')
# We want them from the C locale regardless of our current locale.
$ERR_no_such_file = undef;
$ERR_no_such_file_code = "2";
$ERR_read_only_file = undef;
$ERR_unreadable_file = undef;
$ERR_nonexe_file = undef;
@ -423,6 +424,9 @@ sub set_defaults
print "Opened non-existent file! Skipping related tests.\n";
} else {
$ERR_no_such_file = "$!";
if ($osname eq 'os390') {
$ERR_no_such_file_code = "129";
}
}
unlink('file.out');

View file

@ -212,7 +212,7 @@ if ($osname eq 'VMS') {
# Check long names for archive members.
# See Savannah bug #54395
if ($osname ne 'VMS') {
if ($osname ne 'VMS' && $osname ne 'os390') {
my $pre = '1234567890123456';
my $lib = 'libxx.a';
my $cr = $created;
@ -238,6 +238,9 @@ $pre%: ; touch \$\@
# SV 61436 : Allow redefining archive rules to propagate timestamps
# These don't work right on z/OS for some reason: archives not fully supported?
if ($osname ne 'os390') {
# Find the output when creating an archive from multiple files
utouch(-10, 'a.o', 'b.o');
@ -246,6 +249,9 @@ touch('b.o');
my $add2 = `$ar $arflags mylib.a b.o $redir`;
unlink('a.o', 'b.o', 'mylib.a');
# Some systems complain when compiling empty files
create_file('a.c', 'int i;');
create_file('b.c', 'int j;');
utouch(-20, 'a.c', 'b.c');
run_make_test(q!
@ -267,6 +273,7 @@ run_make_test(undef, $arvar, "Compile b.c\n$ar $arflags mylib.a b.o\n${add2}rm b
run_make_test(undef, $arvar, "#MAKE#: 'mylib.a' is up to date.");
unlink('a.c', 'b.c', 'a.o', 'b.o', 'mylib.a');
}
# This tells the test driver that the perl test script executed properly.
1;

View file

@ -360,8 +360,8 @@ use POSIX ();
# file.
run_make_test(q!
pid:=$(shell echo $$PPID)
all:; @#HELPER# term $(pid) sleep 10
!, '-O -j2', '/#MAKE#: \*\*\* \[#MAKEFILE#:3: all] Terminated/', POSIX::SIGTERM);
all:; @#HELPER# -q term $(pid) sleep 10
!, '-O -j2', '#MAKE#: *** [#MAKEFILE#:3: all] Terminated', POSIX::SIGTERM);
}
unlink($fout);

View file

@ -19,10 +19,14 @@ all: ; @echo "<$(demo1)> <$(demo2)> <$(demo3)> <$(demo4)> <${demo5}>"
'', "< 1 2 3 4 5 6 > <7 8 > <7 8 > < 2 3 > < 2 3 >\n");
# TEST 1: Handle '#' the same way as BSD make
$hashOctal = "\\043";
if ($osname eq 'os390') {
$hashOctal = "\\173";
}
run_make_test('
foo1!=echo bar#baz
hash != printf \'\043\'
hash != printf \'' . $hashOctal . '\'
foo2!= echo "bar$(hash)baz"
all: ; @echo "<$(foo1)> <$(hash)> <$(foo2)>"

View file

@ -67,13 +67,15 @@ use POSIX ();
&utouch(-600, 'bye.mk');
close(STDIN);
open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!";
run_make_test(q!
include bye.mk
pid:=$(shell echo $$PPID)
pid := $(shell echo $$PPID)
all:;
bye.mk: force; @#HELPER# term $(pid) sleep 10
bye.mk: force; @#HELPER# -q term $(pid) sleep 10
force:
!, '-f-', '/#MAKE#: \*\*\* \[#MAKEFILE#:5: bye.mk] Terminated/', POSIX::SIGTERM);
!,
'-f-', '#MAKE#: *** [#MAKEFILE#:5: bye.mk] Terminated', POSIX::SIGTERM);
}
unlink($fout);

View file

@ -148,7 +148,9 @@ all: ; @echo $(.SHELLSTATUS)
# Solaris 10 perl 5.8.4 puts signal number + 128 into the high 8 bits.
$ret >>= 8;
}
$ret |= 128;
if ($osname ne 'os390') {
$ret |= 128;
}
run_make_test('.PHONY: all
$(shell kill -2 $$$$)

View file

@ -115,7 +115,7 @@ all:; @print "it works\n"
SHELL = #PERL#
.SHELLFLAGS =
all:; @print "it works"
!, '', "Can't open perl script \"print \"it works\"\": $ERR_no_such_file\n#MAKE#: *** [#MAKEFILE#:5: all] Error 2", 512);
!, '', "Can't open perl script \"print \"it works\"\": $ERR_no_such_file\n#MAKE#: *** [#MAKEFILE#:5: all] Error $ERR_no_such_file_code", 512);
# No .SHELLFLAGS.
# sv 61805.
@ -123,7 +123,7 @@ all:; @print "it works"
.ONESHELL:
SHELL = #PERL#
all:; @print "it works"
!, '', "Can't open perl script \"print \"it works\"\": $ERR_no_such_file\n#MAKE#: *** [#MAKEFILE#:4: all] Error 2", 512);
!, '', "Can't open perl script \"print \"it works\"\": $ERR_no_such_file\n#MAKE#: *** [#MAKEFILE#:4: all] Error $ERR_no_such_file_code", 512);
# Pass a quoted string with spaces to oneshell.
# sv 61805.

View file

@ -16,12 +16,18 @@ all: ; \@#HELPER# -q fail 1; true
# User settings must override .POSIX
# In the standard .POSIX must be the first thing in the makefile
# but we relax that rule in GNU Make.
# Different versions of sh generate different output for -x so check it
my $script = subst_make_string('#HELPER# -q fail 1; true');
my $flags = '-xc';
my $out = `$sh_name $flags '$script' 2>&1`;
run_make_test(qq!
.SHELLFLAGS = -xc
.SHELLFLAGS = $flags
.POSIX:
all: ; \@#HELPER# -q fail 1; true
all: ; \@$script
!,
'', "+ #HELPER# -q fail 1\n+ true\n");
'', $out);
# Test the default value of various POSIX-specific variables
my %POSIX = (AR => 'ar', ARFLAGS => '-rv',

View file

@ -66,8 +66,8 @@ one two:;@echo "$@: $(SHELL) $$SHELL"
# Test .SHELLFLAGS
# We don't know the output here: on Solaris for example, every line printed
# by the shell in -x mode has a trailing space (!!)
# We don't know the output here: on some systems, for example, every line
# printed by the shell in -x mode has a trailing space!
my $script = 'true; true';
my $flags = '-xc';
my $out = `$sh_name $flags '$script' 2>&1`;
@ -94,10 +94,14 @@ all: ; \@$script
'', $out);
}
$script = subst_make_string('true; #HELPER# -q fail 1; true');
$flags = '-xec';
$out = `$sh_name $flags '$script' 2>&1`;
run_make_test(qq!
.SHELLFLAGS = -xec
all: ; \@true; #HELPER# -q fail 1; true
.SHELLFLAGS = $flags
all: ; \@$script
!,
'', "+ true\n+ #HELPER# -q fail 1\n#MAKE#: *** [#MAKEFILE#:3: all] Error 1\n", 512);
'', "${out}#MAKE#: *** [#MAKEFILE#:3: all] Error 1", 512);
1;

View file

@ -148,7 +148,7 @@ sub resetENV
# through Perl 5.004. It was fixed in Perl 5.004_01, but we don't
# want to require that here, so just delete each one individually.
if ($^O ne 'VMS') {
if ($osname ne 'VMS') {
foreach $v (keys %ENV) {
delete $ENV{$v};
}
@ -205,6 +205,9 @@ sub toplevel
'PURIFYOPTIONS',
# Windows-specific things
'Path', 'SystemRoot', 'TEMP', 'TMP', 'USERPROFILE', 'PATHEXT',
# z/OS specific things
'LIBPATH', '_BPXK_AUTOCVT',
'_TAG_REDIR_IN', '_TAG_REDIR_OUT',
# DJGPP-specific things
'DJDIR', 'DJGPP', 'SHELL', 'COMSPEC', 'HOSTNAME', 'LFN',
'FNCASE', '387', 'EMU387', 'GROUP'
@ -417,8 +420,7 @@ sub get_osname
$port_type = 'VMS-DCL';
}
# Everything else, right now, is UNIX. Note that we should integrate
# the VOS support into this as well and get rid of $vos; we'll do
# that next time.
# the VOS support into this as well and get rid of $vos
else {
$port_type = 'UNIX';
}
@ -615,7 +617,7 @@ sub run_all_tests
$perl_testname = "$scriptpath$pathsep$testname";
$testname =~ s/(\.pl|\.perl)$//;
$testpath = "$workpath$pathsep$testname";
$extext = '_' if $^O eq 'VMS';
$extext = '_' if $osname eq 'VMS';
$log_filename = "$testpath.$logext";
$diff_filename = "$testpath.$diffext";
$base_filename = "$testpath.$baseext";
@ -906,6 +908,21 @@ sub compare_answer_vms
return 0;
}
sub compare_answer_zos
{
my ($kgo, $log) = @_;
# z/OS emits "Error 143" or "SIGTERM" instead of terminated
$log =~ s/Error 143/Terminated/gm;
$log =~ s/SIGTERM/Terminated/gm;
# z/OS error messages have a prefix
$log =~ s/EDC5129I No such file or directory\./No such file or directory/gm;
$log =~ s/FSUM7351 not found/not found/gm;
return $log eq $kgo;
}
sub compare_answer
{
my ($kgo, $log) = @_;
@ -937,7 +954,10 @@ sub compare_answer
return 1 if ($mlog eq $mkgo);
# VMS is a whole thing...
return 1 if ($^O eq 'VMS' && compare_answer_vms($kgo, $log));
return 1 if ($osname eq 'VMS' && compare_answer_vms($kgo, $log));
# z/OS has its own quirks
return 1 if ($osname eq 'os390' && compare_answer_zos($kgo, $log));
# See if the answer might be a regex.
if ($kgo =~ m,^/(.+)/$,) {
@ -1067,7 +1087,7 @@ sub detach_default_output
@OUTSTACK or error("default output stack has flown under!\n", 1);
close(STDOUT);
close(STDERR) unless $^O eq 'VMS';
close(STDERR) unless $osname eq 'VMS';
open (STDOUT, '>&', pop @OUTSTACK) or error("ddo: $! duping STDOUT\n", 1);
@ -1077,7 +1097,7 @@ sub detach_default_output
sub _run_with_timeout
{
my $code;
if ($^O eq 'VMS') {
if ($osname eq 'VMS') {
#local $SIG{ALRM} = sub {
# my $e = $ERRSTACK[0];
# print $e "\nTest timed out after $test_timeout seconds\n";
@ -1173,7 +1193,7 @@ sub run_command
print "\nrun_command: @_\n" if $debug;
my $code = _run_command(@_);
print "run_command returned $code.\n" if $debug;
print "vms status = ${^CHILD_ERROR_NATIVE}\n" if $debug and $^O eq 'VMS';
print "vms status = ${^CHILD_ERROR_NATIVE}\n" if $debug and $osname eq 'VMS';
return $code;
}
@ -1195,7 +1215,7 @@ sub run_command_with_output
$err and die $err;
print "run_command_with_output returned $code.\n" if $debug;
print "vms status = ${^CHILD_ERROR_NATIVE}\n" if $debug and $^O eq 'VMS';
print "vms status = ${^CHILD_ERROR_NATIVE}\n" if $debug and $osname eq 'VMS';
return $code;
}
@ -1243,7 +1263,7 @@ sub remove_directory_tree_inner
return 0;
}
} else {
if ($^O ne 'VMS') {
if ($osname ne 'VMS') {
if (!unlink $object) {
print "Cannot unlink $object: $!\n";
return 0;

View file

@ -108,7 +108,7 @@ sub op {
}
if ($op eq 'term') {
print "term $nm\n";
print "term $nm\n" unless $quiet;
kill('TERM', $nm);
return 1;
}