git: 129043849f62 - main - Merge bmake-20211212
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 18 Dec 2021 18:14:49 UTC
The branch main has been updated by sjg: URL: https://cgit.FreeBSD.org/src/commit/?id=129043849f62f9cfa72f6fae68417d9995860f3f commit 129043849f62f9cfa72f6fae68417d9995860f3f Merge: 7ed5694dd9b9 2935fe8237c8 Author: Simon J. Gerraty <sjg@FreeBSD.org> AuthorDate: 2021-12-18 18:09:14 +0000 Commit: Simon J. Gerraty <sjg@FreeBSD.org> CommitDate: 2021-12-18 18:09:14 +0000 Merge bmake-20211212 commit '2935fe8237c83c1dcb113dd5335733263e68e6fd' contrib/bmake/ChangeLog | 231 ++++++++ contrib/bmake/FILES | 15 +- contrib/bmake/Makefile | 17 +- contrib/bmake/Makefile.config.in | 2 +- contrib/bmake/VERSION | 2 +- contrib/bmake/_strtol.h | 213 +++++++ contrib/bmake/arch.c | 124 ++-- contrib/bmake/bmake.1 | 19 +- contrib/bmake/bmake.cat1 | 12 +- contrib/bmake/boot-strap | 17 +- contrib/bmake/bsd.after-import.mk | 3 +- contrib/bmake/buf.c | 23 +- contrib/bmake/buf.h | 3 +- contrib/bmake/compat.c | 28 +- contrib/bmake/cond.c | 342 +++++------ contrib/bmake/config.h.in | 46 ++ contrib/bmake/configure | 481 ++++++++++++++-- contrib/bmake/configure.in | 200 +++++-- contrib/bmake/dir.c | 33 +- contrib/bmake/enum.c | 80 --- contrib/bmake/enum.h | 179 ------ contrib/bmake/filemon/filemon_ktrace.c | 3 +- contrib/bmake/for.c | 130 +++-- contrib/bmake/hash.c | 15 +- contrib/bmake/hash.h | 11 +- contrib/bmake/import.sh | 13 +- contrib/bmake/job.c | 43 +- contrib/bmake/lst.h | 6 +- contrib/bmake/main.c | 8 +- contrib/bmake/make-bootstrap.sh.in | 2 +- contrib/bmake/make.1 | 19 +- contrib/bmake/make.c | 140 +++-- contrib/bmake/make.h | 87 +-- contrib/bmake/meta.c | 50 +- contrib/bmake/metachar.c | 6 +- contrib/bmake/metachar.h | 10 +- contrib/bmake/mk/ChangeLog | 104 ++++ contrib/bmake/mk/FILES | 1 + contrib/bmake/mk/auto.dep.mk | 52 +- contrib/bmake/mk/autoconf.mk | 23 +- contrib/bmake/mk/autodep.mk | 7 +- contrib/bmake/mk/compiler.mk | 10 +- contrib/bmake/mk/dep.mk | 4 +- contrib/bmake/mk/dirdeps.mk | 57 +- contrib/bmake/mk/doc.mk | 4 +- contrib/bmake/mk/dpadd.mk | 4 +- contrib/bmake/mk/final.mk | 4 +- contrib/bmake/mk/init.mk | 4 +- contrib/bmake/mk/install-mk | 4 +- contrib/bmake/mk/java.mk | 4 +- contrib/bmake/mk/ldorder.mk | 4 +- contrib/bmake/mk/lib.mk | 6 +- contrib/bmake/mk/man.mk | 54 +- contrib/bmake/mk/meta.autodep.mk | 12 +- contrib/bmake/mk/meta.stage.mk | 11 +- contrib/bmake/mk/meta.sys.mk | 26 +- contrib/bmake/mk/meta2deps.py | 29 +- contrib/bmake/mk/obj.mk | 4 +- contrib/bmake/mk/options.mk | 38 +- contrib/bmake/mk/own.mk | 6 +- contrib/bmake/mk/prlist.mk | 4 +- contrib/bmake/mk/prog.mk | 4 +- contrib/bmake/mk/stage-install.sh | 10 +- contrib/bmake/mk/sys.mk | 9 +- contrib/bmake/mk/sys.vars.mk | 4 +- contrib/bmake/mk/sys/SCO_SV.mk | 13 + contrib/bmake/mk/sys/UnixWare.mk | 24 +- contrib/bmake/nonints.h | 9 +- contrib/bmake/os.sh | 4 +- contrib/bmake/parse.c | 171 +++--- contrib/bmake/sigact.h | 104 ++++ contrib/bmake/sigaction.c | 397 +++++++++++++ contrib/bmake/str.c | 9 +- contrib/bmake/str.h | 27 +- contrib/bmake/suff.c | 119 ++-- contrib/bmake/targ.c | 83 +-- contrib/bmake/trace.c | 6 +- contrib/bmake/unit-tests/Makefile | 75 ++- contrib/bmake/unit-tests/Makefile.config.in | 4 +- contrib/bmake/unit-tests/cond-cmp-numeric.exp | 4 + contrib/bmake/unit-tests/cond-cmp-numeric.mk | 18 +- contrib/bmake/unit-tests/cond-cmp-string.mk | 4 +- contrib/bmake/unit-tests/cond-eof.exp | 3 - contrib/bmake/unit-tests/cond-eof.mk | 12 +- contrib/bmake/unit-tests/cond-func-defined.mk | 4 +- contrib/bmake/unit-tests/cond-func-empty.exp | 4 +- contrib/bmake/unit-tests/cond-func-empty.mk | 73 +-- contrib/bmake/unit-tests/cond-func.exp | 2 +- contrib/bmake/unit-tests/cond-op-and.exp | 5 +- contrib/bmake/unit-tests/cond-op-and.mk | 30 +- contrib/bmake/unit-tests/cond-op-or.exp | 5 +- contrib/bmake/unit-tests/cond-op-or.mk | 30 +- contrib/bmake/unit-tests/cond-op.exp | 34 +- contrib/bmake/unit-tests/cond-op.mk | 39 +- contrib/bmake/unit-tests/cond-short.mk | 69 ++- contrib/bmake/unit-tests/cond-token-plain.exp | 27 +- contrib/bmake/unit-tests/cond-token-plain.mk | 35 +- contrib/bmake/unit-tests/deptgt-default.exp | 1 + contrib/bmake/unit-tests/deptgt-default.mk | 17 +- contrib/bmake/unit-tests/deptgt-makeflags.mk | 29 +- contrib/bmake/unit-tests/directive-else.exp | 6 +- contrib/bmake/unit-tests/directive-endif.exp | 8 +- contrib/bmake/unit-tests/directive-export-impl.exp | 4 +- contrib/bmake/unit-tests/directive-for-escape.exp | 63 +- contrib/bmake/unit-tests/directive-for-escape.mk | 49 +- contrib/bmake/unit-tests/directive-for-if.exp | 8 + contrib/bmake/unit-tests/directive-for-if.mk | 86 +++ contrib/bmake/unit-tests/directive-for-null.exp | 2 +- contrib/bmake/unit-tests/directive-include.exp | 3 + contrib/bmake/unit-tests/directive-include.mk | 24 +- contrib/bmake/unit-tests/export.mk | 4 +- contrib/bmake/unit-tests/job-output-null.exp | 6 +- contrib/bmake/unit-tests/job-output-null.mk | 21 +- contrib/bmake/unit-tests/lint.exp | 2 +- contrib/bmake/unit-tests/objdir-writable.exp | 2 +- contrib/bmake/unit-tests/objdir-writable.mk | 11 +- contrib/bmake/unit-tests/opt-debug-errors-jobs.exp | 10 + contrib/bmake/unit-tests/opt-debug-errors-jobs.mk | 14 +- contrib/bmake/unit-tests/opt-debug-graph1.exp | 1 - contrib/bmake/unit-tests/opt-debug-graph2.exp | 1 - contrib/bmake/unit-tests/opt-debug-graph3.exp | 1 - contrib/bmake/unit-tests/opt-file.mk | 12 +- contrib/bmake/unit-tests/opt-tracefile.exp | 11 + contrib/bmake/unit-tests/opt-tracefile.mk | 18 +- contrib/bmake/unit-tests/suff-main-several.exp | 1 - contrib/bmake/unit-tests/suff-transform-debug.exp | 1 - contrib/bmake/unit-tests/var-eval-short.exp | 14 +- contrib/bmake/unit-tests/var-eval-short.mk | 18 +- contrib/bmake/unit-tests/var-op-expand.exp | 8 +- contrib/bmake/unit-tests/var-op-expand.mk | 105 +++- contrib/bmake/unit-tests/vardebug.exp | 4 +- contrib/bmake/unit-tests/varmisc.mk | 12 +- contrib/bmake/unit-tests/varmod-assign.exp | 12 - contrib/bmake/unit-tests/varmod-assign.mk | 107 ++-- contrib/bmake/unit-tests/varmod-defined.exp | 2 +- contrib/bmake/unit-tests/varmod-defined.mk | 5 +- contrib/bmake/unit-tests/varmod-gmtime.exp | 10 +- contrib/bmake/unit-tests/varmod-indirect.exp | 2 +- contrib/bmake/unit-tests/varmod-localtime.exp | 10 +- contrib/bmake/unit-tests/varmod-localtime.mk | 2 +- contrib/bmake/unit-tests/varmod-loop-delete.exp | 4 + contrib/bmake/unit-tests/varmod-loop-delete.mk | 33 ++ contrib/bmake/unit-tests/varmod-loop-varname.exp | 16 +- contrib/bmake/unit-tests/varmod-loop-varname.mk | 7 +- contrib/bmake/unit-tests/varmod-loop.exp | 6 +- contrib/bmake/unit-tests/varmod-loop.mk | 10 +- contrib/bmake/unit-tests/varmod-order-numeric.exp | 1 + contrib/bmake/unit-tests/varmod-order-numeric.mk | 54 ++ contrib/bmake/unit-tests/varmod-order-reverse.mk | 9 +- contrib/bmake/unit-tests/varmod-order-shuffle.mk | 19 +- contrib/bmake/unit-tests/varmod-order-string.exp | 1 + contrib/bmake/unit-tests/varmod-order-string.mk | 28 + contrib/bmake/unit-tests/varmod-order.exp | 25 +- contrib/bmake/unit-tests/varmod-order.mk | 91 ++- contrib/bmake/unit-tests/varmod-root.exp | 10 - contrib/bmake/unit-tests/varmod-root.mk | 37 +- contrib/bmake/unit-tests/varmod-select-words.mk | 5 +- contrib/bmake/unit-tests/varmod-subst.mk | 15 +- contrib/bmake/unit-tests/varmod-to-separator.exp | 4 +- contrib/bmake/unit-tests/varmod-unique.mk | 35 +- .../unit-tests/varname-dot-make-save_dollars.mk | 130 ++++- contrib/bmake/unit-tests/varname-dot-suffixes.exp | 39 ++ contrib/bmake/unit-tests/varname-dot-suffixes.mk | 104 ++++ contrib/bmake/unit-tests/varname-empty.exp | 4 - contrib/bmake/util.c | 82 ++- contrib/bmake/var.c | 631 ++++++++++++--------- 166 files changed, 4798 insertions(+), 1888 deletions(-) diff --cc contrib/bmake/Makefile index 38ccb8a6a636,000000000000..82d9db52af76 mode 100644,000000..100644 --- a/contrib/bmake/Makefile +++ b/contrib/bmake/Makefile @@@ -1,220 -1,0 +1,221 @@@ - # $Id: Makefile,v 1.114 2020/11/13 21:47:25 sjg Exp $ ++# $Id: Makefile,v 1.117 2021/12/04 18:51:30 sjg Exp $ + +PROG= bmake + +SRCS= \ + arch.c \ + buf.c \ + compat.c \ + cond.c \ + dir.c \ - enum.c \ + for.c \ + hash.c \ + job.c \ + lst.c \ + main.c \ + make.c \ + make_malloc.c \ + meta.c \ + metachar.c \ + parse.c \ + str.c \ + suff.c \ + targ.c \ + trace.c \ + util.c \ + var.c + +.-include "VERSION" +.-include "Makefile.inc" + +# this file gets generated by configure +.-include "Makefile.config" + +.if !empty(LIBOBJS) +SRCS+= ${LIBOBJS:T:.o=.c} +.endif + +# just in case +prefix?= /usr +srcdir?= ${.CURDIR} + +DEFAULT_SYS_PATH?= ${prefix}/share/mk + +CPPFLAGS+= -DUSE_META +CFLAGS+= ${CPPFLAGS} +CFLAGS+= -D_PATH_DEFSYSPATH=\"${DEFAULT_SYS_PATH}\" +CFLAGS+= -I. -I${srcdir} ${XDEFS} -DMAKE_NATIVE +CFLAGS+= ${COPTS.${.ALLSRC:M*.c:T:u}} +COPTS.main.c+= "-DMAKE_VERSION=\"${_MAKE_VERSION}\"" + +.for x in FORCE_MACHINE FORCE_MACHINE_ARCH +.ifdef $x +COPTS.main.c+= "-D$x=\"${$x}\"" +.endif +.endfor + +# meta mode can be useful even without filemon +# should be set by now +USE_FILEMON ?= no +.if ${USE_FILEMON:tl} != "no" +.PATH: ${srcdir}/filemon +SRCS+= filemon_${USE_FILEMON}.c +COPTS.meta.c+= -DUSE_FILEMON -DUSE_FILEMON_${USE_FILEMON:tu} +COPTS.job.c+= ${COPTS.meta.c} + +.if ${USE_FILEMON} == "dev" +FILEMON_H ?= /usr/include/dev/filemon/filemon.h +.if exists(${FILEMON_H}) && ${FILEMON_H:T} == "filemon.h" +COPTS.filemon_dev.c += -DHAVE_FILEMON_H -I${FILEMON_H:H} +.endif +.endif # USE_FILEMON == dev + +.endif # USE_FILEMON + +.PATH: ${srcdir} + +.if make(obj) || make(clean) +SUBDIR+= unit-tests +.endif + +# start-delete1 for bsd.after-import.mk +# we skip a lot of this when building as part of FreeBSD etc. + +# list of OS's which are derrived from BSD4.4 +BSD44_LIST= NetBSD FreeBSD OpenBSD DragonFly MirBSD Bitrig +# we are... +OS := ${.MAKE.OS:U${uname -s:L:sh}} +# are we 4.4BSD ? +isBSD44:=${BSD44_LIST:M${OS}} + +.if ${isBSD44} == "" +MANTARGET= cat +INSTALL?=${srcdir}/install-sh - .if (${MACHINE} == "sun386") ++.if ${MACHINE} == "sun386" +# even I don't have one of these anymore :-) +CFLAGS+= -DPORTAR - .elif (${MACHINE} != "sunos") ++.elif ${OS} != "SunOS" ++# assume the worst +SRCS+= sigcompat.c +CFLAGS+= -DSIGNAL_FLAGS=SA_RESTART +.endif +.else +MANTARGET?= man +.endif + +# turn this on by default - ignored if we are root +WITH_INSTALL_AS_USER= + +# suppress with -DWITHOUT_* +OPTIONS_DEFAULT_YES+= \ + AUTOCONF_MK \ + INSTALL_MK \ + PROG_LINK + +OPTIONS_DEFAULT_NO+= \ + PROG_VERSION + +# process options now +.include <own.mk> + +.if ${MK_PROG_VERSION} == "yes" +PROG_NAME= ${PROG}-${_MAKE_VERSION} +.if ${MK_PROG_LINK} == "yes" +SYMLINKS+= ${PROG_NAME} ${BINDIR}/${PROG} +.endif +.endif + +EXTRACT_MAN=no +# end-delete1 + +MAN= ${PROG}.1 +MAN1= ${MAN} + - .if (${PROG} != "make") ++.if ${PROG} != "make" +CLEANFILES+= my.history +.if make(${MAN}) || !exists(${srcdir}/${MAN}) +my.history: + @(echo ".Nm"; \ + echo "is derived from NetBSD"; \ + echo ".Xr make 1 ."; \ + echo "It uses autoconf to facilitate portability to other platforms."; \ + echo ".Pp") > $@ + +.NOPATH: ${MAN} +${MAN}: make.1 my.history + @echo making $@ + @sed \ + -e '/^.Dt/s/MAKE/${PROG:tu}/' \ + -e 's/^.Nx/NetBSD/' \ + -e '/^.Nm/s/make/${PROG}/' \ + -e '/^.Sh HISTORY/rmy.history' \ + -e '/^.Sh HISTORY/,$$s,^.Nm,make,' ${srcdir}/make.1 > $@ + +all beforeinstall: ${MAN} +_mfromdir=. +.endif +.endif + +MANTARGET?= cat +MANDEST?= ${MANDIR}/${MANTARGET}1 + +.if ${MANTARGET} == "cat" +_mfromdir=${srcdir} +.endif + +.include <prog.mk> + +CPPFLAGS+= -DMAKE_NATIVE -DHAVE_CONFIG_H +COPTS.var.c += -Wno-cast-qual +COPTS.job.c += -Wno-format-nonliteral +COPTS.parse.c += -Wno-format-nonliteral +COPTS.var.c += -Wno-format-nonliteral + +# Force these +SHAREDIR= ${SHAREDIR.bmake:U${prefix}/share} +BINDIR= ${BINDIR.bmake:U${prefix}/bin} +MANDIR= ${MANDIR.bmake:U${SHAREDIR}/man} + +.if !exists(.depend) +${OBJS}: config.h +.endif + +# start-delete2 for bsd.after-import.mk + +# make sure that MAKE_VERSION gets updated. +main.o: ${srcdir}/VERSION + +.if ${MK_AUTOCONF_MK} == "yes" +CONFIGURE_DEPS += ${.CURDIR}/VERSION +# we do not need or want the generated makefile +CONFIGURE_ARGS += --without-makefile ++AUTOCONF_GENERATED_MAKEFILE = Makefile.config +.include <autoconf.mk> +.endif - SHARE_MK?=${SHAREDIR}/mk - MKSRC=${srcdir}/mk - INSTALL?=${srcdir}/install-sh ++SHARE_MK ?= ${SHAREDIR}/mk ++MKSRC = ${srcdir}/mk ++INSTALL ?= ${srcdir}/install-sh + +.if ${MK_INSTALL_MK} == "yes" +install: install-mk +.endif + +beforeinstall: + test -d ${DESTDIR}${BINDIR} || ${INSTALL} -m 775 -d ${DESTDIR}${BINDIR} + test -d ${DESTDIR}${MANDEST} || ${INSTALL} -m 775 -d ${DESTDIR}${MANDEST} + +install-mk: +.if exists(${MKSRC}/install-mk) + test -d ${DESTDIR}${SHARE_MK} || ${INSTALL} -m 775 -d ${DESTDIR}${SHARE_MK} + sh ${MKSRC}/install-mk -v -m 644 ${DESTDIR}${SHARE_MK} +.else + @echo need to unpack mk.tar.gz under ${srcdir} or set MKSRC; false +.endif +# end-delete2 + +# A simple unit-test driver to help catch regressions +TEST_MAKE ?= ${.OBJDIR}/${PROG:T} +accept test: + cd ${.CURDIR}/unit-tests && \ + MAKEFLAGS= ${TEST_MAKE} -r -m / ${.TARGET} ${TESTS:DTESTS=${TESTS:Q}} + diff --cc contrib/bmake/_strtol.h index 000000000000,51c71490ae57..51c71490ae57 mode 000000,100644..100644 --- a/contrib/bmake/_strtol.h +++ b/contrib/bmake/_strtol.h diff --cc contrib/bmake/job.c index e4b77477e816,000000000000..f90c35bb6d49 mode 100644,000000..100644 --- a/contrib/bmake/job.c +++ b/contrib/bmake/job.c @@@ -1,3050 -1,0 +1,3067 @@@ - /* $NetBSD: job.c,v 1.435 2021/06/16 09:47:51 rillig Exp $ */ ++/* $NetBSD: job.c,v 1.440 2021/11/28 19:51:06 rillig Exp $ */ + +/* + * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Adam de Boor. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 1988, 1989 by Adam de Boor + * Copyright (c) 1989 by Berkeley Softworks + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Adam de Boor. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * job.c -- + * handle the creation etc. of our child processes. + * + * Interface: + * Job_Init Called to initialize this module. In addition, + * the .BEGIN target is made including all of its + * dependencies before this function returns. + * Hence, the makefiles must have been parsed + * before this function is called. + * + * Job_End Clean up any memory used. + * + * Job_Make Start the creation of the given target. + * + * Job_CatchChildren + * Check for and handle the termination of any + * children. This must be called reasonably + * frequently to keep the whole make going at + * a decent clip, since job table entries aren't + * removed until their process is caught this way. + * + * Job_CatchOutput + * Print any output our children have produced. + * Should also be called fairly frequently to + * keep the user informed of what's going on. + * If no output is waiting, it will block for + * a time given by the SEL_* constants, below, + * or until output is ready. + * + * Job_ParseShell Given a special dependency line with target '.SHELL', + * define the shell that is used for the creation + * commands in jobs mode. + * + * Job_Finish Perform any final processing which needs doing. + * This includes the execution of any commands + * which have been/were attached to the .END + * target. It should only be called when the + * job table is empty. + * + * Job_AbortAll Abort all currently running jobs. Do not handle + * output or do anything for the jobs, just kill them. + * Should only be called in an emergency. + * + * Job_CheckCommands + * Verify that the commands for a target are + * ok. Provide them if necessary and possible. + * + * Job_Touch Update a target without really updating it. + * + * Job_Wait Wait for all currently-running jobs to finish. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <sys/time.h> +#include "wait.h" + +#include <errno.h> +#if !defined(USE_SELECT) && defined(HAVE_POLL_H) +#include <poll.h> +#else +#ifndef USE_SELECT /* no poll.h */ +# define USE_SELECT +#endif +#if defined(HAVE_SYS_SELECT_H) +# include <sys/select.h> +#endif +#endif +#include <signal.h> +#include <utime.h> +#if defined(HAVE_SYS_SOCKET_H) +# include <sys/socket.h> +#endif + +#include "make.h" +#include "dir.h" +#include "job.h" +#include "pathnames.h" +#include "trace.h" + +/* "@(#)job.c 8.2 (Berkeley) 3/19/94" */ - MAKE_RCSID("$NetBSD: job.c,v 1.435 2021/06/16 09:47:51 rillig Exp $"); ++MAKE_RCSID("$NetBSD: job.c,v 1.440 2021/11/28 19:51:06 rillig Exp $"); + +/* + * A shell defines how the commands are run. All commands for a target are + * written into a single file, which is then given to the shell to execute + * the commands from it. The commands are written to the file using a few + * templates for echo control and error control. + * + * The name of the shell is the basename for the predefined shells, such as + * "sh", "csh", "bash". For custom shells, it is the full pathname, and its + * basename is used to select the type of shell; the longest match wins. + * So /usr/pkg/bin/bash has type sh, /usr/local/bin/tcsh has type csh. + * + * The echoing of command lines is controlled using hasEchoCtl, echoOff, + * echoOn, noPrint and noPrintLen. When echoOff is executed by the shell, it + * still outputs something, but this something is not interesting, therefore + * it is filtered out using noPrint and noPrintLen. + * + * The error checking for individual commands is controlled using hasErrCtl, + * errOn, errOff and runChkTmpl. + * + * In case a shell doesn't have error control, echoTmpl is a printf template + * for echoing the command, should echoing be on; runIgnTmpl is another + * printf template for executing the command while ignoring the return + * status. Finally runChkTmpl is a printf template for running the command and + * causing the shell to exit on error. If any of these strings are empty when + * hasErrCtl is false, the command will be executed anyway as is, and if it + * causes an error, so be it. Any templates set up to echo the command will + * escape any '$ ` \ "' characters in the command string to avoid unwanted + * shell code injection, the escaped command is safe to use in double quotes. + * + * The command-line flags "echo" and "exit" also control the behavior. The + * "echo" flag causes the shell to start echoing commands right away. The + * "exit" flag causes the shell to exit when an error is detected in one of + * the commands. + */ +typedef struct Shell { + + /* + * The name of the shell. For Bourne and C shells, this is used only + * to find the shell description when used as the single source of a + * .SHELL target. For user-defined shells, this is the full path of + * the shell. + */ + const char *name; + + bool hasEchoCtl; /* whether both echoOff and echoOn are there */ + const char *echoOff; /* command to turn echoing off */ + const char *echoOn; /* command to turn echoing back on */ + const char *noPrint; /* text to skip when printing output from the + * shell. This is usually the same as echoOff */ + size_t noPrintLen; /* length of noPrint command */ + + bool hasErrCtl; /* whether error checking can be controlled + * for individual commands */ + const char *errOn; /* command to turn on error checking */ + const char *errOff; /* command to turn off error checking */ + + const char *echoTmpl; /* template to echo a command */ + const char *runIgnTmpl; /* template to run a command + * without error checking */ + const char *runChkTmpl; /* template to run a command + * with error checking */ + + /* string literal that results in a newline character when it appears + * outside of any 'quote' or "quote" characters */ + const char *newline; + char commentChar; /* character used by shell for comment lines */ + + const char *echoFlag; /* shell flag to echo commands */ + const char *errFlag; /* shell flag to exit on error */ +} Shell; + +typedef struct CommandFlags { + /* Whether to echo the command before or instead of running it. */ + bool echo; + + /* Run the command even in -n or -N mode. */ + bool always; + + /* + * true if we turned error checking off before writing the command to + * the commands file and need to turn it back on + */ + bool ignerr; +} CommandFlags; + +/* + * Write shell commands to a file. + * + * TODO: keep track of whether commands are echoed. + * TODO: keep track of whether error checking is active. + */ +typedef struct ShellWriter { + FILE *f; + + /* we've sent 'set -x' */ + bool xtraced; + +} ShellWriter; + +/* + * FreeBSD: traditionally .MAKE is not required to + * pass jobs queue to sub-makes. + * Use .MAKE.ALWAYS_PASS_JOB_QUEUE=no to disable. + */ +#define MAKE_ALWAYS_PASS_JOB_QUEUE "${.MAKE.ALWAYS_PASS_JOB_QUEUE:U}" +static bool Always_pass_job_queue = true; +/* + * FreeBSD: aborting entire parallel make isn't always + * desired. When doing tinderbox for example, failure of + * one architecture should not stop all. + * We still want to bail on interrupt though. + */ +#define MAKE_JOB_ERROR_TOKEN "${MAKE_JOB_ERROR_TOKEN:U}" +static bool Job_error_token = true; + +/* + * error handling variables + */ +static int job_errors = 0; /* number of errors reported */ +static enum { /* Why is the make aborting? */ + ABORT_NONE, + ABORT_ERROR, /* Aborted because of an error */ + ABORT_INTERRUPT, /* Aborted because it was interrupted */ + ABORT_WAIT /* Waiting for jobs to finish */ +} aborting = ABORT_NONE; +#define JOB_TOKENS "+EI+" /* Token to requeue for each abort state */ + +/* + * this tracks the number of tokens currently "out" to build jobs. + */ +int jobTokensRunning = 0; + +typedef enum JobStartResult { + JOB_RUNNING, /* Job is running */ + JOB_ERROR, /* Error in starting the job */ + JOB_FINISHED /* The job is already finished */ +} JobStartResult; + +/* + * Descriptions for various shells. + * + * The build environment may set DEFSHELL_INDEX to one of + * DEFSHELL_INDEX_SH, DEFSHELL_INDEX_KSH, or DEFSHELL_INDEX_CSH, to + * select one of the predefined shells as the default shell. + * + * Alternatively, the build environment may set DEFSHELL_CUSTOM to the + * name or the full path of a sh-compatible shell, which will be used as + * the default shell. + * + * ".SHELL" lines in Makefiles can choose the default shell from the + * set defined here, or add additional shells. + */ + +#ifdef DEFSHELL_CUSTOM +#define DEFSHELL_INDEX_CUSTOM 0 +#define DEFSHELL_INDEX_SH 1 +#define DEFSHELL_INDEX_KSH 2 +#define DEFSHELL_INDEX_CSH 3 +#else /* !DEFSHELL_CUSTOM */ +#define DEFSHELL_INDEX_SH 0 +#define DEFSHELL_INDEX_KSH 1 +#define DEFSHELL_INDEX_CSH 2 +#endif /* !DEFSHELL_CUSTOM */ + +#ifndef DEFSHELL_INDEX +#define DEFSHELL_INDEX 0 /* DEFSHELL_INDEX_CUSTOM or DEFSHELL_INDEX_SH */ +#endif /* !DEFSHELL_INDEX */ + +static Shell shells[] = { +#ifdef DEFSHELL_CUSTOM + /* + * An sh-compatible shell with a non-standard name. + * + * Keep this in sync with the "sh" description below, but avoid + * non-portable features that might not be supplied by all + * sh-compatible shells. + */ + { + DEFSHELL_CUSTOM, /* .name */ + false, /* .hasEchoCtl */ + "", /* .echoOff */ + "", /* .echoOn */ + "", /* .noPrint */ + 0, /* .noPrintLen */ + false, /* .hasErrCtl */ + "", /* .errOn */ + "", /* .errOff */ + "echo \"%s\"\n", /* .echoTmpl */ + "%s\n", /* .runIgnTmpl */ + "{ %s \n} || exit $?\n", /* .runChkTmpl */ + "'\n'", /* .newline */ + '#', /* .commentChar */ + "", /* .echoFlag */ + "", /* .errFlag */ + }, +#endif /* DEFSHELL_CUSTOM */ + /* + * SH description. Echo control is also possible and, under + * sun UNIX anyway, one can even control error checking. + */ + { + "sh", /* .name */ + false, /* .hasEchoCtl */ + "", /* .echoOff */ + "", /* .echoOn */ + "", /* .noPrint */ + 0, /* .noPrintLen */ + false, /* .hasErrCtl */ + "", /* .errOn */ + "", /* .errOff */ + "echo \"%s\"\n", /* .echoTmpl */ + "%s\n", /* .runIgnTmpl */ + "{ %s \n} || exit $?\n", /* .runChkTmpl */ + "'\n'", /* .newline */ + '#', /* .commentChar*/ +#if defined(MAKE_NATIVE) && defined(__NetBSD__) + /* XXX: -q is not really echoFlag, it's more like noEchoInSysFlag. */ + "q", /* .echoFlag */ +#else + "", /* .echoFlag */ +#endif + "", /* .errFlag */ + }, + /* + * KSH description. + */ + { + "ksh", /* .name */ + true, /* .hasEchoCtl */ + "set +v", /* .echoOff */ + "set -v", /* .echoOn */ + "set +v", /* .noPrint */ + 6, /* .noPrintLen */ + false, /* .hasErrCtl */ + "", /* .errOn */ + "", /* .errOff */ + "echo \"%s\"\n", /* .echoTmpl */ + "%s\n", /* .runIgnTmpl */ + "{ %s \n} || exit $?\n", /* .runChkTmpl */ + "'\n'", /* .newline */ + '#', /* .commentChar */ + "v", /* .echoFlag */ + "", /* .errFlag */ + }, + /* + * CSH description. The csh can do echo control by playing + * with the setting of the 'echo' shell variable. Sadly, + * however, it is unable to do error control nicely. + */ + { + "csh", /* .name */ + true, /* .hasEchoCtl */ + "unset verbose", /* .echoOff */ + "set verbose", /* .echoOn */ + "unset verbose", /* .noPrint */ + 13, /* .noPrintLen */ + false, /* .hasErrCtl */ + "", /* .errOn */ + "", /* .errOff */ + "echo \"%s\"\n", /* .echoTmpl */ + "csh -c \"%s || exit 0\"\n", /* .runIgnTmpl */ + "", /* .runChkTmpl */ + "'\\\n'", /* .newline */ + '#', /* .commentChar */ + "v", /* .echoFlag */ + "e", /* .errFlag */ + } +}; + +/* + * This is the shell to which we pass all commands in the Makefile. + * It is set by the Job_ParseShell function. + */ +static Shell *shell = &shells[DEFSHELL_INDEX]; +const char *shellPath = NULL; /* full pathname of executable image */ +const char *shellName = NULL; /* last component of shellPath */ +char *shellErrFlag = NULL; +static char *shell_freeIt = NULL; /* Allocated memory for custom .SHELL */ + + +static Job *job_table; /* The structures that describe them */ +static Job *job_table_end; /* job_table + maxJobs */ +static unsigned int wantToken; /* we want a token */ +static bool lurking_children = false; +static bool make_suspended = false; /* Whether we've seen a SIGTSTP (etc) */ + +/* + * Set of descriptors of pipes connected to + * the output channels of children + */ +static struct pollfd *fds = NULL; +static Job **jobByFdIndex = NULL; +static nfds_t fdsLen = 0; +static void watchfd(Job *); +static void clearfd(Job *); +static bool readyfd(Job *); + +static char *targPrefix = NULL; /* To identify a job change in the output. */ +static Job tokenWaitJob; /* token wait pseudo-job */ + +static Job childExitJob; /* child exit pseudo-job */ +#define CHILD_EXIT "." +#define DO_JOB_RESUME "R" + +enum { + npseudojobs = 2 /* number of pseudo-jobs */ +}; + +static sigset_t caught_signals; /* Set of signals we handle */ +static volatile sig_atomic_t caught_sigchld; + +static void CollectOutput(Job *, bool); +static void JobInterrupt(bool, int) MAKE_ATTR_DEAD; +static void JobRestartJobs(void); +static void JobSigReset(void); + +static void +SwitchOutputTo(GNode *gn) +{ + /* The node for which output was most recently produced. */ + static GNode *lastNode = NULL; + + if (gn == lastNode) + return; + lastNode = gn; + + if (opts.maxJobs != 1 && targPrefix != NULL && targPrefix[0] != '\0') + (void)fprintf(stdout, "%s %s ---\n", targPrefix, gn->name); +} + +static unsigned +nfds_per_job(void) +{ +#if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) + if (useMeta) + return 2; +#endif + return 1; +} + +void +Job_FlagsToString(const Job *job, char *buf, size_t bufsize) +{ + snprintf(buf, bufsize, "%c%c%c", + job->ignerr ? 'i' : '-', + !job->echo ? 's' : '-', + job->special ? 'S' : '-'); +} + +static void +DumpJobs(const char *where) +{ + Job *job; + char flags[4]; + + debug_printf("job table @ %s\n", where); + for (job = job_table; job < job_table_end; job++) { + Job_FlagsToString(job, flags, sizeof flags); + debug_printf("job %d, status %d, flags %s, pid %d\n", + (int)(job - job_table), job->status, flags, job->pid); + } +} + +/* + * Delete the target of a failed, interrupted, or otherwise + * unsuccessful job unless inhibited by .PRECIOUS. + */ +static void +JobDeleteTarget(GNode *gn) +{ + const char *file; + + if (gn->type & OP_JOIN) + return; + if (gn->type & OP_PHONY) + return; + if (Targ_Precious(gn)) + return; + if (opts.noExecute) + return; + + file = GNode_Path(gn); + if (eunlink(file) != -1) + Error("*** %s removed", file); +} + +/* + * JobSigLock/JobSigUnlock + * + * Signal lock routines to get exclusive access. Currently used to + * protect `jobs' and `stoppedJobs' list manipulations. + */ +static void +JobSigLock(sigset_t *omaskp) +{ + if (sigprocmask(SIG_BLOCK, &caught_signals, omaskp) != 0) { + Punt("JobSigLock: sigprocmask: %s", strerror(errno)); *** 2587 LINES SKIPPED ***