Index: vendor/NetBSD/bmake/dist/ChangeLog =================================================================== --- vendor/NetBSD/bmake/dist/ChangeLog (revision 321401) +++ vendor/NetBSD/bmake/dist/ChangeLog (revision 321402) @@ -1,2115 +1,2122 @@ +2017-07-20 Simon J. Gerraty + + * Makefile (_MAKE_VERSION): 20170720 + Merge with NetBSD make, pick up + o compat.c: pass SIGINT etc onto child and wait for it to exit + before we self-terminate. + 2017-07-11 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170711 forgot to update after merge on 20170708 ;-) o main.c: refactor to reduce size of main function. add -v option to always fully expand values. o meta.c: ensure command output in meta file has ending newline even when filemon not being used. When matching ${.MAKE.META.IGNORE_PATTERNS} do not use pathname via ':L' since any ':' in pathname breaks that. Instead set a '${.p.}' to pathname in the target context and use that. 2017-05-10 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170510 Merge with NetBSD make, pick up o main.c: Main_SetObjdir: ensure buf2 is in scope 2017-05-08 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170505 see mk/ChangeLog 2017-05-05 Simon J. Gerraty * parse.c: not everyone has stdint.h 2017-05-01 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170501 see mk/ChangeLog 2017-04-21 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170421 Merge with NetBSD make, pick up o str.c: Str_Match: fix closure tests for [^] and add unit-test. 2017-04-20 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170420 Merge with NetBSD make, pick up o main.c: only use -C arg "as is" if it contains no relative component. 2017-04-18 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170418 Merge with NetBSD make, pick up o main.c: fix Main_SetObjdir() for relative paths (eg obj). 2017-04-17 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170417 Merge with NetBSD make, pick up o fixes a number of coverity complaints - check return value of fseek, fcntl - plug memory leak in Dir_FindFile, Var_LoopExpand, JobPrintCommand, ParseTraditionalInclude - use bmake_malloc() where NULL is not tollerated - use MAKE_ATTR_UNUSED rather that kludges like return(unused ? 0 : 0) - use purge_cached_realpaths() rather than abuse cached_realpath() 2017-04-13 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170413 Merge with NetBSD make, pick up o main.c: when setting .OBJDIR ignore '$' in paths. * job.c: use MALLOC_OPTIONS to set malloc_options. 2017-04-11 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170411 Merge with NetBSD make, pick up o str.c: Str_Match: allow [^a-z] to behave as expected. 2017-03-26 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170326 Merge with NetBSD make, pick up o main.c: purge relative paths from realpath cache when .OBJDIR is changed. 2017-03-11 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170311 Merge with NetBSD make, pick up o main.c: only use -C arg "as is" if it starts with '/'. 2017-03-01 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170301 Merge with NetBSD make, pick up o main.c: use -C arg "as is" rather than getcwd() if they identify the same directory. o parse.c: ensure loadfile buffer is \n terminated in non-mmap case 2017-02-01 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170201 Merge with NetBSD make, pick up o var.c: allow :_=var and avoid use of special context. 2017-01-30 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170130 Merge with NetBSD make, pick up o var.c: add :range and :_ o main.c: partially initialize Dir_* before MainParseArgs() can be called. If -V, skip Main_ExportMAKEFLAGS() 2017-01-14 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20170114 Merge with NetBSD make, pick up o var.c: allow specifying the utc value used by :{gm,local}time 2016-12-12 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20161212 Merge with NetBSD make, pick up o main.c: look for obj.${MACHINE}-${MACHINE_ARCH} too. 2016-12-09 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20161209 Merge with NetBSD make, pick up o main.c: cleanup setting of .OBJDIR o parse.c: avoid coredump from (var)=val 2016-11-26 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20161126 Merge with NetBSD make, pick up o make.c: Make_OODate: report src node name if path not set 2016-09-26 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20160926 Merge with NetBSD make, pick up o support for .DELETE_ON_ERROR: (remove targets that fail) 2016-09-26 Simon J. Gerraty * Makefile MAN: tweak .Dt to match ${PROG} 2016-08-18 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20160818 its a neater number; pick up whitespace fixes to man page. 2016-08-17 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20160817 Merge with NetBSD make, pick up o meta.c: move handling of .MAKE.META.IGNORE_* to meta_ignore() so we can call it before adding entries to missingFiles. Thus we do not track files we have been told to ignore. 2016-08-15 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20160815 Merge with NetBSD make, pick up o meta_oodate: apply .MAKE.META.IGNORE_FILTER (if defined) to pathnames, and skip if the expansion is empty. Useful for dirdeps.mk when checking DIRDEPS_CACHE. 2016-08-12 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20160812 Merge with NetBSD make, pick up o meta.c: remove all missingFiles entries that match a deleted dir. o main.c: set .ERROR_CMD if possible. 2016-06-06 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20160606 Merge with NetBSD make, pick up o dir.c: extend mtimes cache to others via cached_stat() 2016-06-04 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20160604 Merge with NetBSD make, pick up o meta.c: missing filemon data is only relevant if we read a meta file. Also do not return oodate for a missing metafile if gn->path points to .CURDIR 2016-06-02 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20160602 Merge with NetBSD make, pick up o cached_realpath(): avoid hitting filesystem more than necessary. o meta.c: refactor need_meta decision, add knobs for missing meta file and filemon data wrt out-of-datedness. 2016-05-28 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20160528 * boot-strap, make-bootstrap.sh.in: Makefile now uses _MAKE_VERSION 2016-05-12 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20160512 Merge with NetBSD make, pick up o meta.c: ignore paths that match .MAKE.META.IGNORE_PATTERNS this is useful for gcov builds. o propagate errors from filemon(4). 2016-05-09 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20160509 Merge with NetBSD make, pick up o remove use of non-standard types u_int etc. o meta.c: apply realpath() before matching against metaIgnorePaths 2016-04-04 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20160404 Merge with NetBSD make, pick up o allow makefile to set .MAKE.JOBS * Makefile (PROG_NAME): use ${_MAKE_VERSION} 2016-03-15 Simon J. Gerraty * Makefile (_MAKE_VERSION): 20160315 Merge with NetBSD make, pick up o fix handling of archive members 2016-03-13 Simon J. Gerraty * Makefile (_MAKE_VERSION): rename variable to avoid interference with checks for ${MAKE_VERSION} 2016-03-10 Simon J. Gerraty * Makefile (MAKE_VERSION): 20160310 Merge with NetBSD make, pick up o meta.c: treat missing Read file same as Write, incase we Delete it. 2016-03-07 Simon J. Gerraty * Makefile (MAKE_VERSION): 20160307 Merge with NetBSD make, pick up o var.c: fix :ts\nnn to be octal by default. o meta.c: meta_finish() to cleanup memory. 2016-02-26 Simon J. Gerraty * Makefile (MAKE_VERSION): 20160226 Merge with NetBSD make, pick up o meta.c: allow meta file for makeDepend if makefiles want it. 2016-02-19 Simon J. Gerraty * var.c: default .MAKE.SAVE_DOLLARS to FALSE for backwards compatability. * Makefile (MAKE_VERSION): 20160220 Merge with NetBSD make, pick up o var.c: add knob to control handling of '$$' in := 2016-02-18 Simon J. Gerraty * Makefile (MAKE_VERSION): 20160218 Merge with NetBSD make, pick up o var.c: add .export-literal allows us to fix sys.clean-env.mk post the changes to Var_Subst. Var_Subst now takes flags, and does not consume '$$' in := 2016-02-17 Simon J. Gerraty * Makefile (MAKE_VERSION): 20160217 Merge with NetBSD make, pick up o var.c: preserve '$$' in := o parse.c: add .dinclude for handling included makefile like .depend 2015-12-20 Simon J. Gerraty * Makefile (MAKE_VERSION): 20151220 Merge with NetBSD make, pick up o suff.c: re-initialize suffNull when clearing suffixes. 2015-12-01 Simon J. Gerraty * Makefile (MAKE_VERSION): 20151201 Merge with NetBSD make, pick up o cond.c: CondCvtArg: avoid access beyond end of empty buffer. o meta.c: meta_oodate: use lstat(2) for checking link target in case it is a symlink. o var.c: avoid calling brk_string and Var_Export1 with empty strings. 2015-11-26 Simon J. Gerraty * Makefile (MAKE_VERSION): 20151126 Merge with NetBSD make, pick up o parse.c: ParseTrackInput don't access beyond end of old value. 2015-10-22 Simon J. Gerraty * Makefile (MAKE_VERSION): 20151022 * Add support for BSD/OS which lacks inttypes.h and really needs sys/param.h for sys/sysctl.h also 'type' is not a shell builtin. * var.c: eliminate uint32_t and need for inttypes.h * main.c: PrintOnError flush stdout before run .ERROR * parse.c: cope with _SC_PAGESIZE not being defined. 2015-10-20 Simon J. Gerraty * Makefile (MAKE_VERSION): 20151020 Merge with NetBSD make, pick up o var.c: fix uninitialized var 2015-10-12 Simon J. Gerraty * var.c: the conditional expressions used with ':?' can be expensive, if already discarding do not evaluate or expand anything. 2015-10-10 Simon J. Gerraty * Makefile (MAKE_VERSION): 20151010 Merge with NetBSD make, pick up o Add Boolean wantit flag to Var_Subst and Var_Parse when FALSE we know we are discarding the result and can skip operations like Cmd_Exec. 2015-10-09 Simon J. Gerraty * Makefile (MAKE_VERSION): 20151009 Merge with NetBSD make, pick up o var.c: don't check for NULL before free() o meta.c: meta_oodate, do not hard code ignore of makeDependfile 2015-09-10 Simon J. Gerraty * Makefile (MAKE_VERSION): 20150910 Merge with NetBSD make, pick up o main.c: with -w print Enter/Leaving messages for objdir too if necessary. o centralize shell metachar handling * FILES: add metachar.[ch] 2015-06-06 Simon J. Gerraty * Makefile (MAKE_VERSION): 20150606 Merge with NetBSD make, pick up o make.1: document .OBJDIR target 2015-05-05 Simon J. Gerraty * Makefile (MAKE_VERSION): 20150505 Merge with NetBSD make, pick up o cond.c: be strict about lhs of comparison when evaluating .if but less so when called from variable expansion. o unit-tests/cond2.mk: test various error conditions 2015-05-04 Simon J. Gerraty * machine.sh (MACHINE): Add Bitrig patch from joerg@netbsd.org 2015-04-18 Simon J. Gerraty * Makefile (MAKE_VERSION): 20150418 Merge with NetBSD make, pick up o job.c: use memmove() rather than memcpy() * unit-tests/varshell.mk: SunOS cannot handle the TERMINATED_BY_SIGNAL case, so skip it. 2015-04-11 Simon J. Gerraty * Makefile (MAKE_VERSION): 20150411 bump version - only mk/ changes. 2015-04-10 Simon J. Gerraty * Makefile (MAKE_VERSION): 20150410 Merge with NetBSD make, pick up o document different handling of '-' in jobs mode vs compat o fix jobs mode so that '-' only applies to whole job when shell lacks hasErrCtl o meta.c: use separate vars to track lcwd and latestdir (read) per process 2015-04-01 Simon J. Gerraty * Makefile (MAKE_VERSION): 20150401 Merge with NetBSD make, pick up o meta.c: close meta file in child * Makefile: use BINDIR.bmake if set. Same for MANDIR and SHAREDIR Handy for testing release candidates in various environments. 2015-03-26 Simon J. Gerraty * move initialization of savederr to block where it is used to avoid spurious warning from gcc5 2014-11-11 Simon J. Gerraty * Makefile (MAKE_VERSION): 20141111 just a cooler number 2014-11-05 Simon J. Gerraty * Makefile (MAKE_VERSION): 20141105 Merge with NetBSD make, pick up o revert major overhaul of suffix handling and POSIX compliance - too much breakage and impossible to make backwards compatible. o we still have the new unit test structure which is ok. o meta.c ensure "-- filemon" is at start of line. 2014-09-17 Simon J. Gerraty * configure.in: test that result of getconf PATH_MAX is numeric and discard if not. Apparently needed for Hurd. 2014-08-30 Simon J. Gerraty * Makefile (MAKE_VERSION): 20140830 Merge with NetBSD make, pick up o major overhaul of suffix handling o improved POSIX compliance o overhauled unit-tests 2014-06-20 Simon J. Gerraty * Makefile (MAKE_VERSION): 20140620 Merge with NetBSD make, pick up o var.c return varNoError rather than var_Error for ::= modifiers. 2014-05-22 Simon J. Gerraty * Makefile (MAKE_VERSION): 20140522 Merge with NetBSD make, pick up o var.c detect some parse errors. 2014-04-05 Simon J. Gerraty * Fix spelling errors - patch from Pedro Giffuni 2014-02-14 Simon J. Gerraty * Makefile (MAKE_VERSION): 20140214 Merge with NetBSD make, pick up o .INCLUDEFROM* o use Var_Value to get MAKEOBJDIR[PREFIX] o reduced realloc'ign in brk_string. * configure.in: add a check for compiler supporting __func__ 2014-01-03 Simon J. Gerraty * boot-strap: ignore mksrc=none 2014-01-02 Simon J. Gerraty * Makefile (DEFAULT_SYS_PATH?): use just ${prefix}/share/mk 2014-01-01 Simon J. Gerraty * Makefile (MAKE_VERSION): 20140101 * configure.in: set bmake_path_max to min(_SC_PATH_MAX,1024) * Makefile.config: defined BMAKE_PATH_MAX to bmake_path_max * make.h: use BMAKE_PATH_MAX if MAXPATHLEN not defined (needed for Hurd) * configure.in: Add AC_PREREQ and check for sysctl; patch from Andrew Shadura andrewsh at debian.org 2013-10-16 Simon J. Gerraty * Makefile (MAKE_VERSION): 20131010 * lose the const from arg to systcl to avoid problems on older BSDs. 2013-10-01 Simon J. Gerraty * Makefile (MAKE_VERSION): 20131001 Merge with NetBSD make, pick up o main.c: for NATIVE build sysctl to get MACHINE_ARCH from hw.machine_arch if necessary. o meta.c: meta_oodate - need to look at src of Link and target of Move as well. * main.c: check that CTL_HW and HW_MACHINE_ARCH exist. provide __arraycount() if needed. 2013-09-04 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130904 Merge with NetBSD make, pick up o Add VAR_INTERNAL context, so that internal setting of MAKEFILE does not override value set by makefiles. 2013-09-02 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130902 Merge with NetBSD make, pick up o CompatRunCommand: only apply shellErrFlag when errCheck is true 2013-08-28 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130828 Merge with NetBSD make, pick up o Fix VAR :sh = syntax from Will Andrews at freebsd.org o Call Job_SetPrefix() from Job_Init() so makefiles have opportunity to set .MAKE.JOB.PREFIX 2013-07-30 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130730 Merge with NetBSD make, pick up o Allow suppression of --- job -- tokens by setting .MAKE.JOB.PREFIX empty. 2013-07-16 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130716 Merge with NetBSD make, pick up o number of gmake compatibility tweaks -w for gmake style entering/leaving messages if .MAKE.LEVEL > 0 indicate it in progname "make[1]" etc. handle MAKEFLAGS containing only letters. o when overriding a GLOBAL variable on the command line, delete it from GLOBAL context so -V doesn't show the wrong value. 2013-07-06 Simon J. Gerraty * configure.in: We don't need MAKE_LEVEL_SAFE anymore. * Makefile (MAKE_VERSION): 20130706 Merge with NetBSD make, pick up o Shell_Init(): export shellErrFlag if commandShell hasErrCtl is true so that CompatRunCommand() can use it, to ensure consistent behavior with jobs mode. o use MAKE_LEVEL_ENV to define the variable to propagate .MAKE.LEVEL - currently set to MAKELEVEL (same as gmake). o meta.c: use .MAKE.META.IGNORE_PATHS to allow customization of paths to ignore. 2013-06-04 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130604 Merge with NetBSD make, pick up o job.c: JobCreatePipe: do fcntl() after any tweaking of fd's to avoid leaking descriptors. 2013-05-28 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130528 Merge with NetBSD make, pick up o var.c: cleanup some left-overs in VarHash() 2013-05-20 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130520 generate manifest from component FILES rather than have to update FILES when mk/FILES changes. 2013-05-18 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130518 Merge with NetBSD make, pick up o suff.c: don't skip all processsing for .PHONY targets else wildcard srcs do not get expanded. o var.c: expand name of variable to delete if necessary. 2013-03-30 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130330 Merge with NetBSD make, pick up o meta.c: refine the handling of .OODATE in commands. Rather than suppress command comparison for the entire script as though .NOMETA_CMP had been used, only suppress it for the one command line. This allows something like ${.OODATE:M.NOMETA_CMP} to be used to suppress comparison of a command without otherwise affecting it. o make.1: document that 2013-03-22 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130321 yes, not quite right but its a cooler number. Merge with NetBSD make, pick up o parse.c: fix ParseGmakeExport to be portable and add a unit-test. * meta.c: call meta_init() before makefiles are read and if built with filemon support set .MAKE.PATH_FILEMON to _PATH_FILEMON this let's makefiles test for support. Call meta_mode_init() to process .MAKE.MODE. 2013-03-13 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130305 Merge with NetBSD make, pick up o run .STALE: target when a dependency from .depend is missing. o job.c: add Job_RunTarget() for the above and .BEGIN 2013-03-03 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130303 Merge with NetBSD make, pick up o main.c: set .MAKE.OS to utsname.sysname o job.c: more checks for read and poll errors o var.c: lose VarChangeCase() saves 4% time 2013-03-02 Simon J. Gerraty * boot-strap: remove MAKEOBJDIRPREFIX from environment since we want to use MAKEOBJDIR 2013-01-27 Simon J. Gerraty * Merge with NetBSD make, pick up o make.1: more info on how shell commands are handled. o job.c,main.c: detect write errors to job pipes. 2013-01-25 Simon J. Gerraty * Makefile (MAKE_VERSION): 20130123 Merge with NetBSD make, pick up o meta.c: if script uses .OODATE and meta_oodate() decides rebuild is needed, .OODATE will be empty - set it to .ALLSRC. o var.c: in debug output indicate which variabale modifiers apply to. o remove Check_Cwd logic the makefiles have been fixed. 2012-12-12 Simon J. Gerraty * makefile.in: add a simple makefile for folk who insist on ./configure; make; make install it just runs boot-strap * include mk/* to accommodate the above * boot-strap: re-work to accommodate the above mksrc defaults to $Mydir/mk allow op={configure,build,install,clean,all} add options to facilitate install * Makefile.config.in: just the bits set by configure * Makefile: bump version to 20121212 abandon Makefile.in (NetBSD Makefile) leverage mk/* instead * configure.in: ensure srcdir is absolute 2012-11-11 Simon J. Gerraty * Makefile.in (MAKE_VERSION): 20121111 fix generation of bmake.cat1 2012-11-09 Simon J. Gerraty * Makefile.in (MAKE_VERSION): 20121109 Merge with NetBSD make, pick up o make.c: MakeBuildChild: return 0 so search continues if a .ORDER dependency is detected. o unit-tests/order: test the above 2012-11-02 Simon J. Gerraty * Makefile.in (MAKE_VERSION): 20121102 Merge with NetBSD make, pick up o cond.c: allow cond_state[] to grow. In meta mode with a very large tree, we can hit the limit while processing dirdeps. 2012-10-25 Simon J. Gerraty * Makefile.in: we need to use ${srcdir} not ${.CURDIR} 2012-10-10 Simon J. Gerraty * Makefile.in (MAKE_VERSION): 20121010 o protect syntax that only bmake parses correctly. o remove auto setting of FORCE_MACHINE, use configure's --with-force-machine=whatever if that is desired. 2012-10-08 Simon J. Gerraty * Makefile.in: do not lose history from make.1 when generating bmake.1 2012-10-07 Simon J. Gerraty * Makefile.in (MAKE_VERSION): 20121007 Merge with NetBSD make, pick up o compat.c: ignore empty commands - same as jobs mode. o make.1: document meta chars that cause use of shell 2012-09-11 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120911 * bsd.after-import.mk: include Makefile.inc early and allow it to override PROG 2012-08-31 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120831 Merge with NetBSD make, pick up o cast sizeof() to int for comparison o minor make.1 tweak 2012-08-30 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120830 Merge with NetBSD make, pick up o .MAKE.EXPAND_VARIABLES knob can control default behavior of -V o debug flag -dV causes -V to show raw value regardless. 2012-07-05 Simon J. Gerraty * bsd.after-import.mk (after-import): ensure unit-tests/Makefile gets SRCTOP set. 2012-07-04 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120704 Merge with NetBSD make, pick up o Job_ParseShell should call Shell_Init if it has been previously called. * Makefile.in: set USE_META based on configure result. also .PARSEDIR is safer indicator of bmake. 2012-06-26 Simon J. Gerraty * Makefile.in: bump version to 20120626 ensure CPPFLAGS is in CFLAGS * meta.c: avoid nested externs * bsd.after-import.mk: avoid ${.CURDIR}/Makefile as target 2012-06-20 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120620 Merge with NetBSD make, pick up o make_malloc.c: avoid including make_malloc.h again * Makefile.in: avoid bmake only syntax or protect with .if defined(.MAKE.LEVEL) * bsd.after-import.mk: replace .-include with .sinclude ensure? SRCTOP gets a value * configure.in: look for filemon.h in /usr/include/dev/filemon first. 2012-06-19 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120612 Merge with NetBSD make, pick up o use MAKE_ATTR_* rather than those defined by cdefs.h or compiler for greater portability. o unit-tests/forloop: check that .for works as expected wrt number of times and with "quoted strings". 2012-06-06 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120606 Merge with NetBSD make, pick up o compat.c: use kill(2) rather than raise(3). * configure.in: look for sys/dev/filemon * bsd.after-import.mk: add a .-include "Makefile.inc" to Makefile and pass BOOTSTRAP_XTRAS to boot-strap. 2012-06-04 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120604 Merge with NetBSD make, pick up o util.c and var.c share same var for tracking if environ has been reallocated. o util.c provide getenv with setenv. * Add MAKE_LEVEL_SAFE as an alternate means of passing MAKE_LEVEL when the shell actively strips .MAKE.* from the environment. We still refer to the variable always as .MAKE.LEVEL * util.c fix bug in findenv() was finding prefix of name. * compat.c: re-raising SIGINT etc after running .INTERRUPT results in more reliable termination of all activity on many platforms. 2012-06-02 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120602 Merge with NetBSD make, pick up o for.c: handle quoted items in .for list 2012-05-30 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120530 Merge with NetBSD make, pick up o compat.c: ignore empty command. 2012-05-24 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120524 * FILES: add bsd.after-import.mk: A simple means of integrating bmake into a BSD build system. 2012-05-20 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120520 Merge with NetBSD make, pick up o increased limit for nested conditionals. 2012-05-18 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120518 Merge with NetBSD make, pick up o use _exit(2) in signal hanlder o Don't use the [dir] cache when building nodes that might have changed since the last exec. o Avoid nested extern declaration warnings. 2012-04-27 Simon J. Gerraty * meta.c (fgetLine): avoid %z - not portable. * parse.c: Since we moved include of sys/mman.h and def's of MAP_COPY etc. we got dups from a merge. 2012-04-24 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120420 Merge with NetBSD make, pick up o restore duplicate supression in .MAKE.MAKEFILES runtime saving can be significant. o Var_Subst() uses Buf_DestroyCompact() to reduce memory consumption up to 20%. 2012-04-20 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120420 Merge with NetBSD make, pick up o remove duplicate supression in .MAKE.MAKEFILES o improved dir cache behavior o gmake'ish export command 2012-03-25 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20120325 Merge with NetBSD make, pick up o fix parsing of :[#] in conditionals. 2012-02-10 Simon J. Gerraty * Makefile.in: replace use of .Nx in bmake.1 with NetBSD since some systems cannot cope with .Nx 2011-11-14 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20111111 Merge with NetBSD make, pick up o debug output for .PARSEDIR and .PARSEFILE 2011-10-10 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20111010 2011-10-09 Simon J. Gerraty * boot-strap: check for an expected file in the dirs we look for. * make-bootstrap.sh: pass on LDSTATIC 2011-10-01 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20111001 Merge with NetBSD make, pick up o ensure .PREFIX is set for .PHONY and .TARGET set for .PHONY run via .END o __dead used consistently 2011-09-10 Simon J. Gerraty * Makefile.in (MAKE_VERSION): 20110909 is a better number ;-) 2011-09-05 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110905 Merge with NetBSD make, pick up o meta_oodate: ignore makeDependfile 2011-08-28 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110828 Merge with NetBSD make, pick up o silent=yes in .MAKE.MODE causes meta mode to mark targets as SILENT if a .meta file is created 2011-08-18 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110818 Merge with NetBSD make, pick up o in meta mode, if target flagged .META a missing .meta file means target is out-of-date o fixes for gcc 4.5 warnings o simplify job printing code 2011-08-09 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110808 Merge with NetBSD make, pick up o do not touch OP_SPECIAL targets when doing make -t 2011-06-22 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110622 Merge with NetBSD make, pick up o meta_oodate detect corrupted .meta file and declare oodate. * configure.in: add check for setsid 2011-06-07 Simon J. Gerraty * Merge with NetBSD make, pick up o unit-tests/modts now works on MirBSD 2011-06-04 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110606 Merge with NetBSD make, pick up o ApplyModifiers: when we parse a variable which is not the entire modifier string, or not followed by ':', do not consider it as containing modifiers. o loadfile: ensure newline at end of mapped file. 2011-05-05 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110505 Merge with NetBSD make, pick up o .MAKE.META.BAILIWICK - list of prefixes which define the scope of make's control. In meta mode, any generated file within said bailiwick, which is found to be missing, causes current target to be out-of-date. 2011-04-11 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110411 Merge with NetBSD make, pick up o when long modifiers fail to match, check sysV style. - add a test case 2011-04-10 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110410 Merge with NetBSD make, pick up o :hash - cheap 32bit hash of value o :localtime, :gmtime - use value as format string for strftime. 2011-03-30 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110330 mostly because its a cooler version. Merge with NetBSD make, pick up o NetBSD tags for meta.[ch] o job.c call meta_job_finish() after meta_job_error(). o meta_job_error() should call meta_job_finish() to ensure .meta file is closed, and safe to copy - if .ERROR target wants. meta_job_finish() is safe to call repeatedly. 2011-03-29 Simon J. Gerraty * unit-tests/modts: use printf if it is a builtin, to save us from MirBSD * Makefile.in (MAKE_VERSION): bump version to 20110329 Merge with NetBSD make, pick up o fix for use after free() in CondDoExists(). o meta_oodate() report extra commands and return earlier. 2011-03-27 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110327 Merge with NetBSD make, pick up o meta.c, if .MAKE.MODE contains curdirOk=yes allow creating .meta files in .CURDIR * boot-strap (TOOL_DIFF): aparently at least on linux distro formats the output of 'type' differently - so eat any "()" 2011-03-06 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110306 Merge with NetBSD make, pick up o meta.c, only do getcwd() once 2011-03-05 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110305 Merge with NetBSD make, pick up o correct sysV substitution handling of empty lhs and variable o correct exists() check for dir with trailing / o correct handling of modifiers for non-existant variables during evaluation of conditionals. o ensure MAP_FILE is defined. o meta.c use curdir[] now exported by main.c 2011-02-25 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110225 Merge with NetBSD make, pick up o fix for incorrect .PARSEDIR when .OBJDIR is re-computed after makefiles have been read. o fix example of :? modifier in man page. 2011-02-13 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110214 Merge with NetBSD make, pick up o meta.c handle realpath() failing when generating meta file name. * sigcompat.c: convert to ansi so we can use higher warning levels. 2011-02-07 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110207 Merge with NetBSD make, pick up o fix for bug in meta mode. 2011-01-03 Simon J. Gerraty * parse.c: SunOS 5.8 at least does not have MAP_FILE 2011-01-01 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20110101 Merge with NetBSD make, pick up o use mmap(2) if available, for reading makefiles 2010-12-15 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20101215 Merge with NetBSD make, pick up o ensure meta_job_error() does not report a previous .meta file as being culprit. 2010-12-10 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20101210 Merge with NetBSD make, pick up o meta_oodate: track cwd per process, and only consider target out-of-date if missing file is outside make's CWD. Ignore files in /tmp/ etc. o to ensure unit-tests results match, need to control LC_ALL as well as LANG. o fix for parsing bug in var.c 2010-11-26 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20101126 Merge with NetBSD make, pick up o if stale dependency is an IMPSRC, search via .PATH o meta_oodate: if a referenced file is missing, target is out-of-date. o meta_oodate: if a target uses .OODATE in its commands, it (.OODATE) needs to be recomputed. o keep a pointer to youngest child node, rather than just its mtime. 2010-11-02 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20101101 2010-10-16 Simon J. Gerraty * machine.sh: like os.sh, allow for uname -p producing useless drivel 2010-09-13 Simon J. Gerraty * boot-strap: document configure knobs for meta and filemon. * Makefile.in (MAKE_VERSION): bump version to 20100911 Merge with NetBSD make, pick up o meta.c - meta mode * make-bootstrap.sh.in: handle meta.c * configure.in: add knobs for use_meta and filemon_h also, look for dirname, str[e]sep and strlcpy * util.c: add simple err[x] and warn[x] 2010-08-08 Simon J. Gerraty * boot-strap (TOOL_DIFF): set this to ensure tests use the same version of diff that configure tested * Makefile.in (MAKE_VERSION): bump version to 20100808 Merge with NetBSD make, pick up o in jobs mode, when we discover we cannot make something, call PrintOnError before exit. 2010-08-06 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100806 Merge with NetBSD make, pick up o formatting fixes for ignored errors o ensure jobs are cleaned up regardless of where wait() was called. 2010-06-28 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100618 * os.sh (MACHINE_ARCH): watch out for drivel from uname -p 2010-06-16 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100616 Merge with NetBSD make, pick up o man page update o call PrintOnError from JobFinish when we detect an error we are not ignoring. 2010-06-06 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100606 Merge with NetBSD make, pick up o man page update 2010-06-05 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100605 Merge with NetBSD make, pick up o use bmake_signal() which is a wrapper around sigaction() in place of signal() o add .export-env to allow exporting variables to environment without tracking (so no re-export when the internal value is changed). 2010-05-24 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100524 Merge with NetBSD make, pick up o fix for .info et al being greedy. 2010-05-23 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100520 Merge with NetBSD make, pick up o back to using realpath on argv[0] but only if contains '/' and does not start with '/'. 2010-05-10 Simon J. Gerraty * boot-strap: use absolute path for bmake when running tests. * Makefile.in (MAKE_VERSION): bump version to 20100510 Merge with NetBSD make, pick up o revert use of realpath on argv[0] too many corner cases. o print MAKE_PRINT_VAR_ON_ERROR before running .ERROR target. 2010-05-05 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100505 Merge with NetBSD make, pick up o fix for missed SIGCHLD when compiled with SunPRO actually for bmake, defining FORCE_POSIX_SIGNALS would have done the job. 2010-04-30 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100430 Merge with NetBSD make, pick up o fflush stdout before writing to stdout 2010-04-23 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100423 Merge with NetBSD make, pick up o updated unit tests for Haiku (this time for sure). * boot-strap: based on patch from joerg honor --with-default-sys-path better. * boot-strap: remove mention of --with-prefix-sys-path 2010-04-22 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100422 * Merge with NetBSD make, pick up o fix for vfork() on Darwin. o fix for bogus $TMPDIR. o set .MAKE.MODE=compat for -B o set .MAKE.JOBS=max_jobs for -j max_jobs o allow unit-tests to run without any *.mk o unit-tests/modmisc be more conservative in dirs presumed to exist. * boot-strap: ignore /usr/share/mk except on NetBSD. * unit-tests/Makefile.in: set LANG=C when running unit-tests to ensure sort(1) behaves as expected. 2010-04-21 Simon J. Gerraty * boot-strap: add FindHereOrAbove so we can use -m .../mk 2010-04-20 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100420 * Merge with NetBSD make, pick up o fix for variable realpath() behavior. we have to stat(2) the result to be sure. o fix for .export (all) when nested vars use :sh 2010-04-14 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100414 * Merge with NetBSD make, pick up o use realpath to resolve argv[0] (for .MAKE) if needed. o add realpath from libc. o add :tA to resolve variable via realpath(3) if possible. 2010-04-08 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100408 * Merge with NetBSD make, pick up o unit tests for .ERROR, .error o fix for .ERROR to ensure it cannot be default target. 2010-04-06 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100406 * Merge with NetBSD make, pick up o fix for compat mode "Error code" going to debug_file. o fix for .ALLSRC being populated twice. o support for .info, .warning and .error directives o .MAKE.MODE to control make's operational mode o .MAKE.MAKEFILE_PREFERENCE to control the preferred makefile name(s). o .MAKE.DEPENDFILE to control the name of the depend file o .ERROR target - run on failure. 2010-03-18 Simon J. Gerraty * make-bootstrap.sh.in: extract MAKE_VERSION from Makefile * os.sh,arch.c: patch for Haiku from joerg at netbsd 2010-03-17 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100222 * Merge with NetBSD make, pick up o better error msg for .for with mutiple inter vars * boot-strap: o use make-bootstrap.sh from joerg at netbsd to avoid the need for a native make when bootstrapping. o add "" everywhere ;-) o if /usr/share/tmac/andoc.tmac exists install nroff bmake.1 otherwise the pre-formated version. 2010-01-04 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20100102 * Merge with NetBSD make, pick up: o fix for -m .../ 2009-11-18 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20091118 * Merge with NetBSD make, pick up: o .unexport o report lines that start with '.' and should have ':' (catch typo's of .el*if). 2009-10-30 Simon J. Gerraty * configure.in: Ensure that srcdir and mksrc are absolute paths. 2009-10-09 Simon J. Gerraty * Makefile.in (MAKE_VERSION): fix version to 20091007 2009-10-07 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 200910007 * Merge with NetBSD make, pick up: o fix for parsing of :S;...;...; applied to .for loop iterator appearing in a dependency line. 2009-09-09 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20090909 * Merge with NetBSD make, pick up: o fix for -C, .CURDIR and .OBJDIR * boot-strap: o allow share_dir to be set independent of prefix. o select default share_dir better when prefix ends in $HOST_TARGET o if FORCE_BSD_MK etc were set, include them in the suggested install-mk command. 2009-09-08 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20090908 * Merge with NetBSD make, pick up: o .MAKE.LEVEL for recursion tracking o fix for :M scanning \: 2009-09-03 Simon J. Gerraty * configure.in: Don't -D__EXTENSIONS__ if AC_USE_SYSTEM_EXTENSIONS says "no". 2009-08-26 Simon J. Gerraty * Makefile.in (MAKE_VERSION): bump version to 20090826 Simplify MAKE_VERSION to just the bare date. * Merge with NetBSD make, pick up: o -C directory support. o support for SIGINFO o use $TMPDIR for temp files. o child of vfork should be careful about modifying parent's state. 2009-03-26 Simon J. Gerraty * Appy some patches for MiNT from David Brownlee 2009-02-26 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20090222 * Merge with NetBSD make, pick up: o Possible null pointer de-ref in Var_Set. 2009-02-08 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20090204 * Merge with NetBSD make, pick up: o bmake_malloc et al moved to their own .c o Count both () and {} when looking for the end of a :M pattern o Change 'Buffer' so that it is the actual struct, not a pointer to it. o strlist.c - functions for processing extendable arrays of pointers to strings. o ClientData replaced with void *, so const void * can be used. o New debug flag C for DEBUG_CWD 2008-11-11 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20081111 Apply patch from Joerg Sonnenberge to configure.in: o remove some redundant checks o check for emlloc etc only in libutil and require the whole family. util.c: o remove [v]asprintf which is no longer used. 2008-11-04 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20081101 * Merge with NetBSD make, pick up: o util.c: avoid use of putenv() - christos 2008-10-30 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20081030 pick up man page tweaks. 2008-10-29 Simon J. Gerraty * Makefile.in: move processing of LIBOBJS to after is definition! thus we'll have getenv.c in SRCS only if needed. * make.1: add examples of how to use :? * Makefile.in (BMAKE_VERSION): bump version to 20081029 * Merge with NetBSD make, pick up: o fix for .END processing with -j o segfault from Parse_Error when no makefile is open o handle numeric expressions in any variable expansion o debug output now defaults to stderr, -dF to change it - apb o make now uses bmake_malloc etc so that it can build natively on A/UX - wasn't an issue for bmake, but we want to keep in sync. 2008-09-27 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20080808 * Merge with NetBSD make, pick up: o fix for PR/38840: Pierre Pronchery: make crashes while parsing long lines in Makefiles o optimizations for VarQuote by joerg o fix for PR/38756: dominik: make dumps core on invalid makefile 2008-05-15 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20080515 * Merge with NetBSD make, pick up: o fix skip setting vars in VAR_GLOBAL context, to handle cases where VAR_CMD is used for other than command line vars. 2008-05-14 Simon J. Gerraty * boot-strap (make_version): we may need to look in $prefix/share/mk for sys.mk * Makefile.in (BMAKE_VERSION): bump version to 20080514 * Merge with NetBSD make, pick up: o skip setting vars in VAR_GLOBAL context, when already set in VAR_CMD which takes precedence. 2008-03-30 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20080330 * Merge with NetBSD make, pick up: o fix for ?= when LHS contains variable reference. 2008-02-15 Simon J. Gerraty * merge some patches from NetBSD pkgsrc. * makefile.boot.in (BOOTSTRAP_SYS_PATH): Allow better control of the MAKSYSPATH used during bootstrap. * Makefile.in (BMAKE_VERSION): bump version to 20080215 * Merge with NetBSD make, pick up: o warn if non-space chars follow 'empty' in a conditional. 2008-01-18 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20080118 * Merge with NetBSD make, pick up: o consider dependencies read from .depend as optional - dsl o remember when buffer for reading makefile grows - dsl o add -dl (aka LOUD) - David O'Brien 2007-10-22 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20071022 * Merge with NetBSD make, pick up: o Allow .PATH to be used for .include "" * boot-strap: source default settings from .bmake-boot-strap.rc 2007-10-16 Simon J. Gerraty * Makefile.in: fix maninstall on various systems provided that our man.mk is used. For non-BSD systems we install the preformatted page into $MANDIR/cat1 2007-10-15 Simon J. Gerraty * boot-strap: make bmake.1 too, so maninstall works. 2007-10-14 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20071014 * Merge with NetBSD make, pick up: o revamped handling of defshell - configure no longer needs to know the content of the shells array - apb o stop Var_Subst modifying its input - apb o avoid calling ParseTrackInput too often - dsl 2007-10-11 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20071011 * Merge with NetBSD make, pick up: o fix Shell_Init for case that _BASENAME_DEFSHELL is absolute path. * sigcompat.c: some tweaks for HP-UX 11.x based on patch from Tobias Nygren * configure.in: update handling of --with-defshell to match new make behavior. --with-defshell=/usr/xpg4/bin/sh will now do what one might hope - provided the chosen shell behaves enough like sh. 2007-10-08 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20071008 * Merge with NetBSD make, pick up: o .MAKE.JOB.PREFIX - control the token output before jobs - sjg o .export/.MAKE.EXPORTED - export of variables - sjg o .MAKE.MAKEFILES - track all makefiles read - sjg o performance improvements - dsl o revamp parallel job scheduling - dsl 2006-07-28 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20060728 * Merge with NetBSD make, pick up: o extra debug info during variable and cond processing - sjg o shell definition now covers newline - rillig o minor mem leak in PrintOnError - sjg 2006-05-11 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20060511 * Merge with NetBSD make, pick up: o more memory leaks - coverity o possible overflow in ArchFindMember - coverity o extract variable modifier code out of Var_Parse() so it can be called recursively - sjg o unit-tests/moderrs - sjg 2006-04-12 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20060412 * Merge with NetBSD make, pick up: o fixes for some memory leaks - coverity o only read first sys.mk etc when searching sysIncPath - sjg * main.c (ReadMakefile): remove hack for __INTERIX that prevented setting ${MAKEFILE} - OBATA Akio 2006-03-18 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20060318 * Merge with NetBSD make, pick up: o cleanup of job.c to remove remote handling, distcc is more useful and this code was likely bit-rotting - dsl o fix for :P modifier - sjg * boot-strap: set default prefix to something reasonable (for me anyway). 2006-03-01 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20060301 * Merge with NetBSD make, pick up: o make .WAIT apply recursively, document and test case - apb o allow variable modifiers in a variable appear anywhere in modifier list, document and test case - sjg 2006-02-22 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20060222 * Merge with NetBSD make, pick up: o improved job token handling - dsl o SIG_DFL the correct signal before exec - dsl o more debug info during parsing - dsl o allow variable modifiers to be specified via variable - sjg * boot-strap: explain why we died if no mksrc 2005-11-05 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20051105 * configure.in: always set default_sys_path default is ${prefix}/share/mk - remove prefix_sys_path, anyone wanting more than above needs to set it manually. 2005-11-04 Simon J. Gerraty * boot-strap: make this a bit easier for pkgsrc folk. bootstrap still fails on IRIX64 since MACHINE_ARCH gets set to 'mips' while pkgsrc wants 'mipseb' or 'mipsel' 2005-11-02 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20051102 * job.c (JobFinish): fix likely ancient merge lossage fix from Todd Vierling. * boot-strap (srcdir): allow setting mksrc=none 2005-10-31 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20051031 * ranlib.h: skip on OSF too. (NetBSD PR 31864) 2005-10-10 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20051002 fix a silly typo 2005-10-09 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20051001 support for UnixWare and some other systems, based on patches from pkgsrc/bootstrap 2005-09-03 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20050901 * Merge with NetBSD make, pick up: o possible parse error causing us to wander off. 2005-06-06 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20050606 * Merge with NetBSD make, pick up: o :0x modifier for randomizing a list o fixes for a number of -Wuninitialized issues. 2005-05-30 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20050530 * Merge with NetBSD make, pick up: o Handle dependencies for .BEGIN, .END and .INTERRUPT * README: was seriously out of date. 2005-03-22 Simon J. Gerraty * Important to use .MAKE rather than MAKE. 2005-03-15 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20050315 * Merge with NetBSD make, pick up: o don't mistake .elsefoo for .else o use suffix-specific search path correctly o bunch of style nits 2004-05-11 Simon J. Gerraty * boot-strap: o ensure that args to --src and --with-mksrc are resolved before giving them to configure. o add -o "objdir" so that builder can control it, default is $OS as determined by os.sh o add -q to suppress all the install instructions. 2004-05-08 Simon J. Gerraty * Remove __IDSTRING() * Makefile.in (BMAKE_VERSION): bump to 20040508 * Merge with NetBSD make, pick up: o posix fixes - remove '-e' from compat mode - add support for '+' command-line prefix. o fix for handling '--' on command-line. o fix include in lst.lib/lstInt.h to simplify '-I's o we also picked up replacement of MAKE_BOOTSTRAP with !MAKE_NATIVE which is a noop, but possibly confusing. 2004-04-14 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20040414 * Merge with NetBSD make, pick up: o allow quoted strings on lhs of conditionals o issue warning when extra .else is seen o print line numer when errors encountered during parsing from string. 2004-02-20 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20040220 * Merge with NetBSD make, pick up: o fix for old :M parsing bug. o re-jigged unit-tests 2004-02-15 Simon J. Gerraty * Makefile.in (accept test): use ${.MAKE:S,^./,${.CURDIR}/,} so that './bmake -f Makefile test' works. 2004-02-14 Simon J. Gerraty * Makefile.in: (BMAKE_VERSION): bump to 20040214 * Merge with NetBSD make, pick up: o search upwards for *.mk o fix for double free of var substitution buffers o use of getopt replaced with custom code, since the usage (re-scanning) isn't posix compatible. 2004-02-12 Simon J. Gerraty * arch.c: don't include ranlib.h on ELF systems (thanks to Chuck Cranor ). 2004-01-18 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump to 20040118 * boot-strap (while): export vars we assign to on cmdline * unit-test/Makefile.in: ternary is .PHONY 2004-01-08 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20040108 * Merge with NetBSD make, pick up: o fix for ternary modifier 2004-01-06 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20040105 * Merge with NetBSD make, pick up: o fix for cond.c to handle compound expressions better o variable expansion within sysV style replacements 2003-12-22 Simon J. Gerraty * Make portable snprintf safer - output to /dev/null first to check space needed. * Makefile.in (BMAKE_VERSION): bump version to 20031222 * Merge with NetBSD make, pick up: o -dg3 to show input graph when things go wrong. o explicitly look for makefiles in objdir if not found in curdir so that errors in .depend etc will be reported accurarely. o avoid use of -e in shell scripts in jobs mode, use '|| exit $?' instead as it more accurately reflects the expected behavior and is more consistently implemented. o avoid use of asprintf. 2003-09-28 Simon J. Gerraty * util.c: Add asprintf and vasprintf. * Makefile.in (BMAKE_VERSION): bump version to 20030928 * Merge with NetBSD make, pick up: :[] modifier - allows picking words from a variable. :tW modifier - allows treating value as one big word. W flag for :C and :S - allows treating value as one big word. 2003-09-12 Simon J. Gerraty * Merge with NetBSD make pick up -de flag to enable printing failed command. don't skip 1st two dir entries (normally . and ..) since coda does not have them. 2003-09-09 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20030909 * Merge with NetBSD make, pick up: - changes for -V '${VAR}' to print fully expanded value cf. -V VAR - CompatRunCommand now prints the command that failed. - several files got updated 3 clause Berkeley license. 2003-08-02 Simon J. Gerraty * boot-strap: Allow setting configure args on command line. 2003-07-31 Simon J. Gerraty * configure.in: add --with-defshell to allow sh or ksh to be selected as default shell. * Makefile.in: bump version to 20030731 * Merge with NetBSD make Pick up .SHELL spec for ksh and associate man page changes. Also compat mode now uses the same shell specs. 2003-07-29 Simon J. Gerraty * var.c (Var_Parse): ensure delim is initialized. * unit-tests/Makefile.in: use single quotes to avoid problems from some shells. * makefile.boot.in: Run the unit-tests as part of the bootstrap procedure. 2003-07-28 Simon J. Gerraty * unit-tests/Makefile.in: always force complaints from ${TEST_MAKE} to be from 'make'. * configure.in: add check for 'diff -u' also fix some old autoconf'isms * Makefile.in (BMAKE_VERSION): bump version to 20030728. if using GCC add -Wno-cast-qual to CFLAGS for var.o * Merge with NetBSD make Pick up fix for :ts parsing error in some cases. Pick unit-tests. 2003-07-23 Simon J. Gerraty * Makefile.in (BMAKE_VERSION): bump version to 20030723. * var.c (Var_Parse): fix bug in :ts modifier, after const correctness fixes, must pass nstr to VarModify. 2003-07-14 Simon J. Gerraty * Makefile.in: BMAKE_VERSION switch to a date based version. We'll generally use the date of last import from NetBSD. * Merge with NetBSD make Pick up fixes for const-correctness, now passes WARNS=3 on NetBSD. Pick up :ts modifier, allows controlling the separator used between words in variable expansion. 2003-07-11 Simon J. Gerraty * FILES: include boot-strap and os.sh * Makefile.in: only set WARNS if we are NetBSD, the effect on FreeBSD is known to be bad. * makefile.boot.in (bootstrap): make this the default target. * Makefile.in: bump version to 3.1.19 * machine.sh: avoid A-Z with tr as it is bound to lose. 2003-07-10 Simon J. Gerraty * Merge with NetBSD make Pick up fix for PR/19781 - unhelpful error msg on unclosed ${var:foo Plus some doc fixes. 2003-04-27 Simon J. Gerraty * Merge with NetBSD make Pick up fix for PR/1523 - don't count a library as built, if there is no way to build it * Bump version to 3.1.18 2003-03-23 Simon J. Gerraty * Merge with NetBSD make Pick up fix for ParseDoSpecialSrc - we only use it if .WAIT appears in src list. 2003-03-21 Simon J. Gerraty * Merge with NetBSD make (mmm 10th anniversary!) pick up fix for .WAIT in srcs that refer to $@ or $* (PR#20828) pick up -X which tells us to not export VAR=val via setenv if we are already doing so via MAKEFLAGS. This saves valuable env space on systems like Darwin. set MAKE_VERSION to 3.1.17 * parse.c: pix up fix for suffix rules 2003-03-06 Simon J. Gerraty * Merge with NetBSD make. pick up fix for propagating -B via MAKEFLAGS. set MAKE_VERSION to 3.1.16 * Apply some patches from pkgsrc-bootstrap/bmake Originally by Grant Beattie I may have missed some - since they are based on bmake-3.1.12 2002-12-03 Simon J. Gerraty * makefile.boot.in (bmake): update install targets for those that use them, also clear MAKEFLAGS when invoking bmake.boot to avoid havoc from gmake -w. Thanks to Harlan Stenn . * bmake.cat1: update the pre-formatted man page! 2002-11-30 Simon J. Gerraty * Merge with NetBSD make. pick up fix for premature free of pointer used in call to Dir_InitCur(). set MAKE_VERSION to 3.1.15 2002-11-26 Simon J. Gerraty * configure.in: determine suitable value for MKSRC. override using --with-mksrc=PATH. * machine.sh: use `uname -p` for MACHINE_ARCH on modern SunOS systems. configs(8) will use 'sun4' as an alias for 'sparc'. 2002-11-25 Simon J. Gerraty * Merge with NetBSD make. pick up ${.PATH} pick up fix for finding ../cat.c via .PATH when .CURDIR=.. set MAKE_VERSION to 3.1.14 add configure checks for killpg and sys/socket.h 2002-09-16 Simon J. Gerraty * tag bmake-3-1-13 * makefile.boot.in (bmake): use install-mk Also setup ./mk before trying to invoke bmake.boot incase we needed install-mk to create a sys.mk for us. * configure.in: If we need to add -I${srcdir}/missing, make it an absolute path so that it works for lst.lib too. * make.h: always include sys/cdefs.h since we provide one if the host does not. * Makefile.in (install-mk): use MKSRC/install-mk which will do the right thing. use uname -p for ARCH if possible. since install-mk will setup links bsd.prog.mk -> prog.mk if needed, just .include bsd.prog.mk * Merge with NetBSD make (NetBSD-1.6) Code is ansi-C only now. Bug in handling of dotLast is fixed. Can now assign .OBJDIR and make will reset its notions of life. New modifiers :tu :tl for toUpper and toLower. Tue Oct 16 12:18:42 2001 Simon J. Gerraty * Merge with NetBSD make pick up fix for .END failure in compat mode. pick up fix for extra va_end() in ParseVErrorInternal. Thu Oct 11 13:20:06 2001 Simon J. Gerraty * configure.in: for systems that have sys/cdefs.h check if it is compatible. If not, include the one under missing, but tell it to include the native one too - necessary on Linux. * missing/sys/cdefs.h: if NEED_HOST_CDEFS_H is defined, use include_next (for gcc) to get the native sys/cdefs.h Tue Aug 21 02:29:34 2001 Simon J. Gerraty * job.c (JobFinish): Fix an earlier merge bug that resulted in leaking descriptors when using -jN. * job.c (JobPrintCommand): See if "curdir" exists before attempting to chdir(). Doing the chdir directly in make (when in compat mode) fails silently, so let the -jN version do the same. This can happen when building kernels in an object tree and playing clever games to reset .CURDIR. * Merged with NetBSD make pick up .USEBEFORE Tue Jun 26 23:45:11 2001 Simon J. Gerraty * makefile.boot.in: Give bmake.boot a MAKESYSPATH that might work. Tue Jun 12 16:48:57 2001 Simon J. Gerraty * var.c (Var_Set): Add 4th (flags) arg so VarLoopExpand can tell us not to export the iterator variable when using VAR_CMD context. Sun Jun 10 21:55:21 2001 Simon J. Gerraty * job.c (Job_CatchChildren): don't call Job_CatchOutput() here, its the wrong "fix". Sat Jun 9 00:11:24 2001 Simon J. Gerraty * Redesigned export of VAR_CMD's via MAKEFLAGS. We now simply append the variable names to .MAKEOVERRIDES, and handle duplicate suppression and quoting in ExportMAKEFLAGS using: ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@} Apart from fixing quoting bugs in previous version, this allows us to export vars to the environment by simply doing: .MAKEOVERRIDES+= PATH Merged again with NetBSD make, but the above is the only change. * configure.in: added --disable-pwd-override disable $PWD overriding getcwd() --disable-check-make-chdir disable make trying to guess when it should automatically cd ${.CURDIR} * Merge with NetBSD make, changes include: parse.c (ParseDoDependency): Spot that the syntax error is caused by an unresolved cvs/rcs conflict and say so. var.c: most of Var* functions now take a ctxt as 1st arg. now does variable substituion on rhs of sysv style modifiers. * var.c (Var_Set): exporting of command line variables (VAR_CMD) is now done here. We append the name='value' to .MAKEOVERRIDES rather than directly into MAKEFLAGS as this allows a Makefile to use .MAKEOVERRIDES= to disable this behaviour. GNU make uses a very similar mechanism. Note that in adding name='value' to .MAKEOVERRIDES we do the moral equivalent of: .MAKEOVERRIDES:= ${.MAKEOVERRIDES:Nname=*} name='val' Fri Jun 1 14:08:02 2001 Simon J. Gerraty * make-conf.h (USE_IOVEC): make it conditional on HAVE_SYS_UIO_H * Merged with NetBSD make make -dx can now be used to run commands via sh -x better error messages on exec failures. Thu May 31 01:44:54 2001 Simon J. Gerraty * Makefile.in (main.o): depends on ${SRCS} ${MAKEFILE} so that MAKE_VERSION gets updated. Also don't use ?= for MAKE_VERSION, MACHINE etc otherwise they propagate from the previous bmake. * configure.in (machine): allow --with-machine=generic to make configure use machine.sh to set MACHINE. * job.c (JobInterrupt): convert to using WAIT_T and friends. * Makefile.in: mention in bmake.1 that we use autoconf. * make.1: mention MAKE_PRINT_VAR_ON_ERROR. Wed May 30 23:17:18 2001 Simon J. Gerraty * main.c (ReadMakefile): don't set MAKEFILE if reading ".depend" as that rather defeats the usefulness of ${MAKEFILE}. * main.c (MainParseArgs): append command line variable assignments to MAKEFLAGS so that they get propagated to child make's. Apparently this is required POSIX behaviour? Its useful anyway. Tue May 29 02:20:07 2001 Simon J. Gerraty * compat.c (CompatRunCommand): don't use perror() since stdio may cause problems in child of vfork(). * compat.c, main.c: Call PrintOnError() when we are going to bail. This routine prints out the .curdir where we stopped and will also display any vars listed in ${MAKE_PRINT_VAR_ON_ERROR}. * main.c: add ${.newline} to hold a "\n" - sometimes handy in :@ expansion. * var.c: VarLoopExpand: ignore addSpace if a \n is present. * Added RCSid's for the files we've touched. Thu May 24 15:41:37 2001 Simon J. Gerraty * configure.in: Thanks to some clues from mdb@juniper.net, added autoconf magic to control setting of MACHINE, MACHINE_ARCH as well as what ends up in _PATH_DEFSYSPATH. We now have: --with-machine=MACHINE explicitly set MACHINE --with-force-machine=MACHINE set FORCE_MACHINE --with-machine_arch=MACHINE_ARCH explicitly set MACHINE_ARCH --with-default-sys-path=PATH:DIR:LIST use an explicit _PATH_DEFSYSPATH --with-prefix-sys-path=PATH:DIR:LIST prefix _PATH_PREFIX_SYSPATH --with-path-objdirprefix=PATH override _PATH_OBJDIRPREFIX If _PATH_OBJDIRPREFIX is set to "no" we won't define it. * makefile: added a pathetically simple makefile to drive bootstrapping. Running configure by hand is more useful. * Makefile.in: added MAKE_VERSION, and reworked things to be less dependent on NetBSD bsd.*.mk * pathnames.h: allow NO_PATH_OBJDIRPREFIX to stop us defining _PATH_OBJDIRPREFIX for those that don't want a default. construct _PATH_DEFSYSPATH from the info we get from configure. * main.c: allow for no _PATH_OBJDIRPREFIX, set ${MAKE_VERSION} if MAKE_VERSION is defined. * compat.c: when we bail, print out the .CURDIR we were in. Sat May 12 00:34:12 2001 Simon J. Gerraty * Merged with NetBSD make * var.c: fixed a bug in the handling of the modifier :P if the node as found but the path was null, we segfault trying to duplicate it. Mon Mar 5 16:20:33 2001 Simon J. Gerraty * Merged with NetBSD make * make.c: Make_OODate's test for a library out of date was using cmtime where it should have used mtime (my bug). * compat.c: Use perror() to tell us what really went wrong when we cannot exec a command. Fri Dec 15 10:11:08 2000 Simon J. Gerraty * Merged with NetBSD make Sat Jun 10 10:11:08 2000 Simon J. Gerraty * Merged with NetBSD make Thu Jun 1 10:11:08 2000 Simon J. Gerraty * Merged with NetBSD make Tue May 30 10:11:08 2000 Simon J. Gerraty * Merged with NetBSD make Thu Apr 27 00:07:47 2000 Simon J. Gerraty * util.c: don't provide signal() since we use sigcompat.c * Makefile.in: added a build target. * var.c (Var_Parse): added ODE modifiers :U, :D, :L, :P, :@ and :! These allow some quite clever magic. * main.c (main): added support for getenv(MAKESYSPATH). Mon Apr 2 16:25:13 2000 Simon J. Gerraty * Disable $PWD overriding getcwd() if MAKEOBJDIRPREFIX is set. This avoids objdir having a different value depending on how a directory was reached (via command line, or subdir.mk). * If FORCE_MACHINE is defined, ignore getenv("MACHINE"). Mon Apr 2 23:15:31 2000 Simon J. Gerraty * Do a chdir(${.CURDIR}) before invoking ${.MAKE} or ${.MAKE:T} if MAKEOBJDIRPREFIX is set and NOCHECKMAKECHDIR is not. I've been testing this in NetBSD's make for some weeks. * Turn Makefile into Makefile.in and make it useful. Tue Feb 29 22:08:00 2000 Simon J. Gerraty * Imported NetBSD's -current make(1) and resolve conflicts. * Applied autoconf patches from bmake v2 * Imported clean code base from NetBSD-1.0 Index: vendor/NetBSD/bmake/dist/Makefile =================================================================== --- vendor/NetBSD/bmake/dist/Makefile (revision 321401) +++ vendor/NetBSD/bmake/dist/Makefile (revision 321402) @@ -1,225 +1,225 @@ -# $Id: Makefile,v 1.94 2017/07/15 18:22:14 sjg Exp $ +# $Id: Makefile,v 1.95 2017/07/20 19:36:13 sjg Exp $ # Base version on src date -_MAKE_VERSION= 20170711 +_MAKE_VERSION= 20170720 PROG= bmake SRCS= \ arch.c \ buf.c \ compat.c \ cond.c \ dir.c \ for.c \ hash.c \ job.c \ main.c \ make.c \ make_malloc.c \ meta.c \ metachar.c \ parse.c \ str.c \ strlist.c \ suff.c \ targ.c \ trace.c \ util.c \ var.c # from lst.lib/ SRCS+= \ lstAppend.c \ lstAtEnd.c \ lstAtFront.c \ lstClose.c \ lstConcat.c \ lstDatum.c \ lstDeQueue.c \ lstDestroy.c \ lstDupl.c \ lstEnQueue.c \ lstFind.c \ lstFindFrom.c \ lstFirst.c \ lstForEach.c \ lstForEachFrom.c \ lstInit.c \ lstInsert.c \ lstIsAtEnd.c \ lstIsEmpty.c \ lstLast.c \ lstMember.c \ lstNext.c \ lstOpen.c \ lstPrev.c \ lstRemove.c \ lstReplace.c \ lstSucc.c # 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}\"" # meta mode can be useful even without filemon FILEMON_H ?= /usr/include/dev/filemon/filemon.h .if exists(${FILEMON_H}) && ${FILEMON_H:T} == "filemon.h" COPTS.meta.c += -DHAVE_FILEMON_H -I${FILEMON_H:H} .endif .PATH: ${srcdir} .PATH: ${srcdir}/lst.lib .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!= uname -s # are we 4.4BSD ? isBSD44:=${BSD44_LIST:M${OS}} .if ${isBSD44} == "" MANTARGET= cat INSTALL?=${srcdir}/install-sh .if (${MACHINE} == "sun386") # even I don't have one of these anymore :-) CFLAGS+= -DPORTAR .elif (${MACHINE} != "sunos") 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 .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") CLEANFILES+= my.history .if make(${MAN}) || !exists(${srcdir}/${MAN}) my.history: ${MAKEFILE} @(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 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 # make sure that MAKE_VERSION gets updated. main.o: ${SRCS} ${MAKEFILE} # start-delete2 for bsd.after-import.mk .if ${MK_AUTOCONF_MK} == "yes" .include .endif 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 accept test: cd ${.CURDIR}/unit-tests && MAKEFLAGS= ${.MAKE} -r -m / TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET} Index: vendor/NetBSD/bmake/dist/compat.c =================================================================== --- vendor/NetBSD/bmake/dist/compat.c (revision 321401) +++ vendor/NetBSD/bmake/dist/compat.c (revision 321402) @@ -1,765 +1,781 @@ -/* $NetBSD: compat.c,v 1.106 2016/08/26 23:28:39 dholland Exp $ */ +/* $NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg 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. */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: compat.c,v 1.106 2016/08/26 23:28:39 dholland Exp $"; +static char rcsid[] = "$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg Exp $"; #else #include #ifndef lint #if 0 static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: compat.c,v 1.106 2016/08/26 23:28:39 dholland Exp $"); +__RCSID("$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg Exp $"); #endif #endif /* not lint */ #endif /*- * compat.c -- * The routines in this file implement the full-compatibility * mode of PMake. Most of the special functionality of PMake * is available in this mode. Things not supported: * - different shells. * - friendly variable substitution. * * Interface: * Compat_Run Initialize things for this module and recreate * thems as need creatin' */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include "wait.h" #include #include #include #include #include "make.h" #include "hash.h" #include "dir.h" #include "job.h" #include "metachar.h" #include "pathnames.h" static GNode *curTarg = NULL; static GNode *ENDNode; static void CompatInterrupt(int); +static pid_t compatChild; +static int compatSigno; /* * CompatDeleteTarget -- delete a failed, interrupted, or otherwise * duffed target if not inhibited by .PRECIOUS. */ static void CompatDeleteTarget(GNode *gn) { if ((gn != NULL) && !Targ_Precious (gn)) { char *p1; char *file = Var_Value(TARGET, gn, &p1); if (!noExecute && eunlink(file) != -1) { Error("*** %s removed", file); } free(p1); } } /*- *----------------------------------------------------------------------- * CompatInterrupt -- * Interrupt the creation of the current target and remove it if * it ain't precious. * * Results: * None. * * Side Effects: * The target is removed and the process exits. If .INTERRUPT exists, * its commands are run first WITH INTERRUPTS IGNORED.. * * XXX: is .PRECIOUS supposed to inhibit .INTERRUPT? I doubt it, but I've * left the logic alone for now. - dholland 20160826 * *----------------------------------------------------------------------- */ static void CompatInterrupt(int signo) { GNode *gn; CompatDeleteTarget(curTarg); if ((curTarg != NULL) && !Targ_Precious (curTarg)) { /* * Run .INTERRUPT only if hit with interrupt signal */ if (signo == SIGINT) { gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); if (gn != NULL) { Compat_Make(gn, gn); } } } if (signo == SIGQUIT) _exit(signo); - bmake_signal(signo, SIG_DFL); - kill(myPid, signo); + /* + * If there is a child running, pass the signal on + * we will exist after it has exited. + */ + compatSigno = signo; + if (compatChild > 0) { + KILLPG(compatChild, signo); + } else { + bmake_signal(signo, SIG_DFL); + kill(myPid, signo); + } } /*- *----------------------------------------------------------------------- * CompatRunCommand -- * Execute the next command for a target. If the command returns an * error, the node's made field is set to ERROR and creation stops. * * Input: * cmdp Command to execute * gnp Node from which the command came * * Results: * 0 if the command succeeded, 1 if an error occurred. * * Side Effects: * The node's 'made' field may be set to ERROR. * *----------------------------------------------------------------------- */ int CompatRunCommand(void *cmdp, void *gnp) { char *cmdStart; /* Start of expanded command */ char *cp, *bp; Boolean silent, /* Don't print command */ doIt; /* Execute even if -n */ volatile Boolean errCheck; /* Check errors */ WAIT_T reason; /* Reason for child's death */ int status; /* Description of child's death */ pid_t cpid; /* Child actually found */ pid_t retstat; /* Result of wait */ LstNode cmdNode; /* Node where current command is located */ const char ** volatile av; /* Argument vector for thing to exec */ char ** volatile mav;/* Copy of the argument vector for freeing */ int argc; /* Number of arguments in av or 0 if not * dynamically allocated */ Boolean local; /* TRUE if command should be executed * locally */ Boolean useShell; /* TRUE if command should be executed * using a shell */ char * volatile cmd = (char *)cmdp; GNode *gn = (GNode *)gnp; silent = gn->type & OP_SILENT; errCheck = !(gn->type & OP_IGNORE); doIt = FALSE; cmdNode = Lst_Member(gn->commands, cmd); cmdStart = Var_Subst(NULL, cmd, gn, VARF_WANTRES); /* * brk_string will return an argv with a NULL in av[0], thus causing * execvp to choke and die horribly. Besides, how can we execute a null * command? In any case, we warn the user that the command expanded to * nothing (is this the right thing to do?). */ if (*cmdStart == '\0') { free(cmdStart); return(0); } cmd = cmdStart; Lst_Replace(cmdNode, cmdStart); if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { (void)Lst_AtEnd(ENDNode->commands, cmdStart); return(0); } if (strcmp(cmdStart, "...") == 0) { gn->type |= OP_SAVE_CMDS; return(0); } while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) { switch (*cmd) { case '@': silent = DEBUG(LOUD) ? FALSE : TRUE; break; case '-': errCheck = FALSE; break; case '+': doIt = TRUE; if (!shellName) /* we came here from jobs */ Shell_Init(); break; } cmd++; } while (isspace((unsigned char)*cmd)) cmd++; /* * If we did not end up with a command, just skip it. */ if (!*cmd) return (0); #if !defined(MAKE_NATIVE) /* * In a non-native build, the host environment might be weird enough * that it's necessary to go through a shell to get the correct * behaviour. Or perhaps the shell has been replaced with something * that does extra logging, and that should not be bypassed. */ useShell = TRUE; #else /* * Search for meta characters in the command. If there are no meta * characters, there's no need to execute a shell to execute the * command. * * Additionally variable assignments and empty commands * go to the shell. Therefore treat '=' and ':' like shell * meta characters as documented in make(1). */ useShell = needshell(cmd, FALSE); #endif /* * Print the command before echoing if we're not supposed to be quiet for * this one. We also print the command if -n given. */ if (!silent || NoExecute(gn)) { printf("%s\n", cmd); fflush(stdout); } /* * If we're not supposed to execute any commands, this is as far as * we go... */ if (!doIt && NoExecute(gn)) { return (0); } if (DEBUG(JOB)) fprintf(debug_file, "Execute: '%s'\n", cmd); again: if (useShell) { /* * We need to pass the command off to the shell, typically * because the command contains a "meta" character. */ static const char *shargv[5]; int shargc; shargc = 0; shargv[shargc++] = shellPath; /* * The following work for any of the builtin shell specs. */ if (errCheck && shellErrFlag) { shargv[shargc++] = shellErrFlag; } if (DEBUG(SHELL)) shargv[shargc++] = "-xc"; else shargv[shargc++] = "-c"; shargv[shargc++] = cmd; shargv[shargc++] = NULL; av = shargv; argc = 0; bp = NULL; mav = NULL; } else { /* * No meta-characters, so no need to exec a shell. Break the command * into words to form an argument vector we can execute. */ mav = brk_string(cmd, &argc, TRUE, &bp); if (mav == NULL) { useShell = 1; goto again; } av = (void *)mav; } local = TRUE; #ifdef USE_META if (useMeta) { meta_compat_start(); } #endif /* * Fork and execute the single command. If the fork fails, we abort. */ - cpid = vFork(); + compatChild = cpid = vFork(); if (cpid < 0) { Fatal("Could not fork"); } if (cpid == 0) { Var_ExportVars(); #ifdef USE_META if (useMeta) { meta_compat_child(); } #endif if (local) (void)execvp(av[0], (char *const *)UNCONST(av)); else (void)execv(av[0], (char *const *)UNCONST(av)); execError("exec", av[0]); _exit(1); } free(mav); free(bp); Lst_Replace(cmdNode, NULL); #ifdef USE_META if (useMeta) { meta_compat_parent(); } #endif /* * The child is off and running. Now all we can do is wait... */ while (1) { while ((retstat = wait(&reason)) != cpid) { if (retstat > 0) JobReapChild(retstat, reason, FALSE); /* not ours? */ if (retstat == -1 && errno != EINTR) { break; } } if (retstat > -1) { if (WIFSTOPPED(reason)) { status = WSTOPSIG(reason); /* stopped */ } else if (WIFEXITED(reason)) { status = WEXITSTATUS(reason); /* exited */ #if defined(USE_META) && defined(USE_FILEMON_ONCE) if (useMeta) { meta_cmd_finish(NULL); } #endif if (status != 0) { if (DEBUG(ERROR)) { fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", gn->name); for (cp = cmd; *cp; ) { if (isspace((unsigned char)*cp)) { fprintf(debug_file, " "); while (isspace((unsigned char)*cp)) cp++; } else { fprintf(debug_file, "%c", *cp); cp++; } } fprintf(debug_file, "\n"); } printf("*** Error code %d", status); } } else { status = WTERMSIG(reason); /* signaled */ printf("*** Signal %d", status); } if (!WIFEXITED(reason) || (status != 0)) { if (errCheck) { #ifdef USE_META if (useMeta) { meta_job_error(NULL, gn, 0, status); } #endif gn->made = ERROR; if (keepgoing) { /* * Abort the current target, but let others * continue. */ printf(" (continuing)\n"); } else { printf("\n"); } if (deleteOnError) { CompatDeleteTarget(gn); } } else { /* * Continue executing commands for this target. * If we return 0, this will happen... */ printf(" (ignored)\n"); status = 0; } } break; } else { Fatal("error in wait: %d: %s", retstat, strerror(errno)); /*NOTREACHED*/ } } free(cmdStart); - + compatChild = 0; + if (compatSigno) { + bmake_signal(compatSigno, SIG_DFL); + kill(myPid, compatSigno); + } + return (status); } /*- *----------------------------------------------------------------------- * Compat_Make -- * Make a target. * * Input: * gnp The node to make * pgnp Parent to abort if necessary * * Results: * 0 * * Side Effects: * If an error is detected and not being ignored, the process exits. * *----------------------------------------------------------------------- */ int Compat_Make(void *gnp, void *pgnp) { GNode *gn = (GNode *)gnp; GNode *pgn = (GNode *)pgnp; if (!shellName) /* we came here from jobs */ Shell_Init(); if (gn->made == UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) { /* * First mark ourselves to be made, then apply whatever transformations * the suffix module thinks are necessary. Once that's done, we can * descend and make all our children. If any of them has an error * but the -k flag was given, our 'make' field will be set FALSE again. * This is our signal to not attempt to do anything but abort our * parent as well. */ gn->flags |= REMAKE; gn->made = BEINGMADE; if ((gn->type & OP_MADE) == 0) Suff_FindDeps(gn); Lst_ForEach(gn->children, Compat_Make, gn); if ((gn->flags & REMAKE) == 0) { gn->made = ABORTED; pgn->flags &= ~REMAKE; goto cohorts; } if (Lst_Member(gn->iParents, pgn) != NULL) { char *p1; Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); free(p1); } /* * All the children were made ok. Now cmgn->mtime contains the * modification time of the newest child, we need to find out if we * exist and when we were modified last. The criteria for datedness * are defined by the Make_OODate function. */ if (DEBUG(MAKE)) { fprintf(debug_file, "Examining %s...", gn->name); } if (! Make_OODate(gn)) { gn->made = UPTODATE; if (DEBUG(MAKE)) { fprintf(debug_file, "up-to-date.\n"); } goto cohorts; } else if (DEBUG(MAKE)) { fprintf(debug_file, "out-of-date.\n"); } /* * If the user is just seeing if something is out-of-date, exit now * to tell him/her "yes". */ if (queryFlag) { exit(1); } /* * We need to be re-made. We also have to make sure we've got a $? * variable. To be nice, we also define the $> variable using * Make_DoAllVar(). */ Make_DoAllVar(gn); /* * Alter our type to tell if errors should be ignored or things * should not be printed so CompatRunCommand knows what to do. */ if (Targ_Ignore(gn)) { gn->type |= OP_IGNORE; } if (Targ_Silent(gn)) { gn->type |= OP_SILENT; } if (Job_CheckCommands(gn, Fatal)) { /* * Our commands are ok, but we still have to worry about the -t * flag... */ if (!touchFlag || (gn->type & OP_MAKE)) { curTarg = gn; #ifdef USE_META if (useMeta && !NoExecute(gn)) { meta_job_start(NULL, gn); } #endif Lst_ForEach(gn->commands, CompatRunCommand, gn); curTarg = NULL; } else { Job_Touch(gn, gn->type & OP_SILENT); } } else { gn->made = ERROR; } #ifdef USE_META if (useMeta && !NoExecute(gn)) { if (meta_job_finish(NULL) != 0) gn->made = ERROR; } #endif if (gn->made != ERROR) { /* * If the node was made successfully, mark it so, update * its modification time and timestamp all its parents. Note * that for .ZEROTIME targets, the timestamping isn't done. * This is to keep its state from affecting that of its parent. */ gn->made = MADE; pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; if (!(gn->type & OP_EXEC)) { pgn->flags |= CHILDMADE; Make_TimeStamp(pgn, gn); } } else if (keepgoing) { pgn->flags &= ~REMAKE; } else { PrintOnError(gn, "\nStop."); exit(1); } } else if (gn->made == ERROR) { /* * Already had an error when making this beastie. Tell the parent * to abort. */ pgn->flags &= ~REMAKE; } else { if (Lst_Member(gn->iParents, pgn) != NULL) { char *p1; Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); free(p1); } switch(gn->made) { case BEINGMADE: Error("Graph cycles through %s", gn->name); gn->made = ERROR; pgn->flags &= ~REMAKE; break; case MADE: if ((gn->type & OP_EXEC) == 0) { pgn->flags |= CHILDMADE; Make_TimeStamp(pgn, gn); } break; case UPTODATE: if ((gn->type & OP_EXEC) == 0) { Make_TimeStamp(pgn, gn); } break; default: break; } } cohorts: Lst_ForEach(gn->cohorts, Compat_Make, pgnp); return (0); } /*- *----------------------------------------------------------------------- * Compat_Run -- * Initialize this mode and start making. * * Input: * targs List of target nodes to re-create * * Results: * None. * * Side Effects: * Guess what? * *----------------------------------------------------------------------- */ void Compat_Run(Lst targs) { GNode *gn = NULL;/* Current root target */ int errors; /* Number of targets not remade due to errors */ if (!shellName) Shell_Init(); if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) { bmake_signal(SIGINT, CompatInterrupt); } if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) { bmake_signal(SIGTERM, CompatInterrupt); } if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) { bmake_signal(SIGHUP, CompatInterrupt); } if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) { bmake_signal(SIGQUIT, CompatInterrupt); } ENDNode = Targ_FindNode(".END", TARG_CREATE); ENDNode->type = OP_SPECIAL; /* * If the user has defined a .BEGIN target, execute the commands attached * to it. */ if (!queryFlag) { gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); if (gn != NULL) { Compat_Make(gn, gn); if (gn->made == ERROR) { PrintOnError(gn, "\nStop."); exit(1); } } } /* * Expand .USE nodes right now, because they can modify the structure * of the tree. */ Make_ExpandUse(targs); /* * For each entry in the list of targets to create, call Compat_Make on * it to create the thing. Compat_Make will leave the 'made' field of gn * in one of several states: * UPTODATE gn was already up-to-date * MADE gn was recreated successfully * ERROR An error occurred while gn was being created * ABORTED gn was not remade because one of its inferiors * could not be made due to errors. */ errors = 0; while (!Lst_IsEmpty (targs)) { gn = (GNode *)Lst_DeQueue(targs); Compat_Make(gn, gn); if (gn->made == UPTODATE) { printf("`%s' is up to date.\n", gn->name); } else if (gn->made == ABORTED) { printf("`%s' not remade because of errors.\n", gn->name); errors += 1; } } /* * If the user has defined a .END target, run its commands. */ if (errors == 0) { Compat_Make(ENDNode, ENDNode); if (gn->made == ERROR) { PrintOnError(gn, "\nStop."); exit(1); } } } Index: vendor/NetBSD/bmake/dist/job.c =================================================================== --- vendor/NetBSD/bmake/dist/job.c (revision 321401) +++ vendor/NetBSD/bmake/dist/job.c (revision 321402) @@ -1,3095 +1,3090 @@ -/* $NetBSD: job.c,v 1.190 2017/04/16 21:23:43 riastradh Exp $ */ +/* $NetBSD: job.c,v 1.191 2017/07/20 19:29:54 sjg 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. */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: job.c,v 1.190 2017/04/16 21:23:43 riastradh Exp $"; +static char rcsid[] = "$NetBSD: job.c,v 1.191 2017/07/20 19:29:54 sjg Exp $"; #else #include #ifndef lint #if 0 static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: job.c,v 1.190 2017/04/16 21:23:43 riastradh Exp $"); +__RCSID("$NetBSD: job.c,v 1.191 2017/07/20 19:29:54 sjg Exp $"); #endif #endif /* not lint */ #endif /*- * job.c -- * handle the creation etc. of our child processes. * * Interface: * 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_Init Called to intialize this module. in addition, * any commands attached to the .BEGIN target * are executed before this function returns. * Hence, the makefile must have been parsed * before this function is called. * * Job_End Cleanup any memory used. * * Job_ParseShell Given the line following a .SHELL target, parse * the line as a shell specification. Returns * FAILURE if the spec was incorrect. * * 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. It doesn't * handle output or do anything for the jobs, * just kills them. It should only be called in * an emergency, as it were. * * 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 #include #include #include #include "wait.h" #include #include #if !defined(USE_SELECT) && defined(HAVE_POLL_H) #include #else #ifndef USE_SELECT /* no poll.h */ # define USE_SELECT #endif #if defined(HAVE_SYS_SELECT_H) # include #endif #endif #include #include #include #include #if defined(HAVE_SYS_SOCKET_H) # include #endif #include "make.h" #include "hash.h" #include "dir.h" #include "job.h" #include "pathnames.h" #include "trace.h" # define STATIC static /* * error handling variables */ static int errors = 0; /* number of errors reported */ static int aborting = 0; /* why is the make aborting? */ #define ABORT_ERROR 1 /* Because of an error */ #define ABORT_INTERRUPT 2 /* Because it was interrupted */ #define ABORT_WAIT 3 /* Waiting for jobs to finish */ #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; int not_parallel = 0; /* set if .NOT_PARALLEL */ /* * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file * is a char! So when we go above 127 we turn negative! */ #define FILENO(a) ((unsigned) fileno(a)) /* * post-make command processing. The node postCommands is really just the * .END target but we keep it around to avoid having to search for it * all the time. */ static GNode *postCommands = NULL; /* node containing commands to execute when * everything else is done */ static int numCommands; /* The number of commands actually printed * for a target. Should this number be * 0, no shell will be executed. */ /* * Return values from JobStart. */ #define JOB_RUNNING 0 /* Job is running */ #define JOB_ERROR 1 /* Error in starting the job */ #define JOB_FINISHED 2 /* The job is already finished */ /* * 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 prefedined 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, FALSE, "", "", "", 0, FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#', "", "", }, #endif /* DEFSHELL_CUSTOM */ /* * SH description. Echo control is also possible and, under * sun UNIX anyway, one can even control error checking. */ { "sh", FALSE, "", "", "", 0, FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#', #if defined(MAKE_NATIVE) && defined(__NetBSD__) "q", #else "", #endif "", }, /* * KSH description. */ { "ksh", TRUE, "set +v", "set -v", "set +v", 6, FALSE, "echo \"%s\"\n", "%s\n", "{ %s \n} || exit $?\n", "'\n'", '#', "v", "", }, /* * 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", TRUE, "unset verbose", "set verbose", "unset verbose", 10, FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"\n", "", "'\\\n'", '#', "v", "e", }, /* * UNKNOWN. */ { NULL, FALSE, NULL, NULL, NULL, 0, FALSE, NULL, NULL, NULL, NULL, 0, NULL, NULL, } }; static Shell *commandShell = &shells[DEFSHELL_INDEX]; /* this is the shell to * which we pass all * commands in the Makefile. * It is set by the * Job_ParseShell function */ const char *shellPath = NULL, /* full pathname of * executable image */ *shellName = NULL; /* last component of shell */ char *shellErrFlag = NULL; static const char *shellArgv = NULL; /* Custom shell args */ STATIC Job *job_table; /* The structures that describe them */ STATIC Job *job_table_end; /* job_table + maxJobs */ static int wantToken; /* we want a token */ static int lurking_children = 0; static int make_suspended = 0; /* non-zero if 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 **jobfds = NULL; static int nfds = 0; static void watchfd(Job *); static void clearfd(Job *); static int readyfd(Job *); STATIC GNode *lastNode; /* The node for which output was most recently * produced. */ static char *targPrefix = NULL; /* What we print at the start of TARG_FMT */ static Job tokenWaitJob; /* token wait pseudo-job */ static Job childExitJob; /* child exit pseudo-job */ #define CHILD_EXIT "." #define DO_JOB_RESUME "R" #define TARG_FMT "%s %s ---\n" /* Default format */ #define MESSAGE(fp, gn) \ if (maxJobs != 1 && targPrefix && *targPrefix) \ (void)fprintf(fp, TARG_FMT, targPrefix, gn->name) static sigset_t caught_signals; /* Set of signals we handle */ -#if defined(SYSV) -#define KILLPG(pid, sig) kill(-(pid), (sig)) -#else -#define KILLPG(pid, sig) killpg((pid), (sig)) -#endif static void JobChildSig(int); static void JobContinueSig(int); static Job *JobFindPid(int, int, Boolean); static int JobPrintCommand(void *, void *); static int JobSaveCommand(void *, void *); static void JobClose(Job *); static void JobExec(Job *, char **); static void JobMakeArgv(Job *, char **); static int JobStart(GNode *, int); static char *JobOutput(Job *, char *, char *, int); static void JobDoOutput(Job *, Boolean); static Shell *JobMatchShell(const char *); static void JobInterrupt(int, int) MAKE_ATTR_DEAD; static void JobRestartJobs(void); static void JobTokenAdd(void); static void JobSigLock(sigset_t *); static void JobSigUnlock(sigset_t *); static void JobSigReset(void); #if !defined(MALLOC_OPTIONS) # define MALLOC_OPTIONS "A" #endif const char *malloc_options= MALLOC_OPTIONS; static void job_table_dump(const char *where) { Job *job; fprintf(debug_file, "job table @ %s\n", where); for (job = job_table; job < job_table_end; job++) { fprintf(debug_file, "job %d, status %d, flags %d, pid %d\n", (int)(job - job_table), job->job_state, job->flags, job->pid); } } /* * Delete the target of a failed, interrupted, or otherwise * unsuccessful job unless inhibited by .PRECIOUS. */ static void JobDeleteTarget(GNode *gn) { if ((gn->type & (OP_JOIN|OP_PHONY)) == 0 && !Targ_Precious(gn)) { char *file = (gn->path == NULL ? gn->name : gn->path); if (!noExecute && 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)); sigemptyset(omaskp); } } static void JobSigUnlock(sigset_t *omaskp) { (void)sigprocmask(SIG_SETMASK, omaskp, NULL); } static void JobCreatePipe(Job *job, int minfd) { int i, fd, flags; if (pipe(job->jobPipe) == -1) Punt("Cannot create pipe: %s", strerror(errno)); for (i = 0; i < 2; i++) { /* Avoid using low numbered fds */ fd = fcntl(job->jobPipe[i], F_DUPFD, minfd); if (fd != -1) { close(job->jobPipe[i]); job->jobPipe[i] = fd; } } /* Set close-on-exec flag for both */ if (fcntl(job->jobPipe[0], F_SETFD, FD_CLOEXEC) == -1) Punt("Cannot set close-on-exec: %s", strerror(errno)); if (fcntl(job->jobPipe[1], F_SETFD, FD_CLOEXEC) == -1) Punt("Cannot set close-on-exec: %s", strerror(errno)); /* * We mark the input side of the pipe non-blocking; we poll(2) the * pipe when we're waiting for a job token, but we might lose the * race for the token when a new one becomes available, so the read * from the pipe should not block. */ flags = fcntl(job->jobPipe[0], F_GETFL, 0); if (flags == -1) Punt("Cannot get flags: %s", strerror(errno)); flags |= O_NONBLOCK; if (fcntl(job->jobPipe[0], F_SETFL, flags) == -1) Punt("Cannot set flags: %s", strerror(errno)); } /*- *----------------------------------------------------------------------- * JobCondPassSig -- * Pass a signal to a job * * Input: * signop Signal to send it * * Side Effects: * None, except the job may bite it. * *----------------------------------------------------------------------- */ static void JobCondPassSig(int signo) { Job *job; if (DEBUG(JOB)) { (void)fprintf(debug_file, "JobCondPassSig(%d) called.\n", signo); } for (job = job_table; job < job_table_end; job++) { if (job->job_state != JOB_ST_RUNNING) continue; if (DEBUG(JOB)) { (void)fprintf(debug_file, "JobCondPassSig passing signal %d to child %d.\n", signo, job->pid); } KILLPG(job->pid, signo); } } /*- *----------------------------------------------------------------------- * JobChldSig -- * SIGCHLD handler. * * Input: * signo The signal number we've received * * Results: * None. * * Side Effects: * Sends a token on the child exit pipe to wake us up from * select()/poll(). * *----------------------------------------------------------------------- */ static void JobChildSig(int signo MAKE_ATTR_UNUSED) { while (write(childExitJob.outPipe, CHILD_EXIT, 1) == -1 && errno == EAGAIN) continue; } /*- *----------------------------------------------------------------------- * JobContinueSig -- * Resume all stopped jobs. * * Input: * signo The signal number we've received * * Results: * None. * * Side Effects: * Jobs start running again. * *----------------------------------------------------------------------- */ static void JobContinueSig(int signo MAKE_ATTR_UNUSED) { /* * Defer sending to SIGCONT to our stopped children until we return * from the signal handler. */ while (write(childExitJob.outPipe, DO_JOB_RESUME, 1) == -1 && errno == EAGAIN) continue; } /*- *----------------------------------------------------------------------- * JobPassSig -- * Pass a signal on to all jobs, then resend to ourselves. * * Input: * signo The signal number we've received * * Results: * None. * * Side Effects: * We die by the same signal. * *----------------------------------------------------------------------- */ MAKE_ATTR_DEAD static void JobPassSig_int(int signo) { /* Run .INTERRUPT target then exit */ JobInterrupt(TRUE, signo); } MAKE_ATTR_DEAD static void JobPassSig_term(int signo) { /* Dont run .INTERRUPT target then exit */ JobInterrupt(FALSE, signo); } static void JobPassSig_suspend(int signo) { sigset_t nmask, omask; struct sigaction act; /* Suppress job started/continued messages */ make_suspended = 1; /* Pass the signal onto every job */ JobCondPassSig(signo); /* * Send ourselves the signal now we've given the message to everyone else. * Note we block everything else possible while we're getting the signal. * This ensures that all our jobs get continued when we wake up before * we take any other signal. */ sigfillset(&nmask); sigdelset(&nmask, signo); (void)sigprocmask(SIG_SETMASK, &nmask, &omask); act.sa_handler = SIG_DFL; sigemptyset(&act.sa_mask); act.sa_flags = 0; (void)sigaction(signo, &act, NULL); if (DEBUG(JOB)) { (void)fprintf(debug_file, "JobPassSig passing signal %d to self.\n", signo); } (void)kill(getpid(), signo); /* * We've been continued. * * A whole host of signals continue to happen! * SIGCHLD for any processes that actually suspended themselves. * SIGCHLD for any processes that exited while we were alseep. * The SIGCONT that actually caused us to wakeup. * * Since we defer passing the SIGCONT on to our children until * the main processing loop, we can be sure that all the SIGCHLD * events will have happened by then - and that the waitpid() will * collect the child 'suspended' events. * For correct sequencing we just need to ensure we process the * waitpid() before passign on the SIGCONT. * * In any case nothing else is needed here. */ /* Restore handler and signal mask */ act.sa_handler = JobPassSig_suspend; (void)sigaction(signo, &act, NULL); (void)sigprocmask(SIG_SETMASK, &omask, NULL); } /*- *----------------------------------------------------------------------- * JobFindPid -- * Compare the pid of the job with the given pid and return 0 if they * are equal. This function is called from Job_CatchChildren * to find the job descriptor of the finished job. * * Input: * job job to examine * pid process id desired * * Results: * Job with matching pid * * Side Effects: * None *----------------------------------------------------------------------- */ static Job * JobFindPid(int pid, int status, Boolean isJobs) { Job *job; for (job = job_table; job < job_table_end; job++) { if ((job->job_state == status) && job->pid == pid) return job; } if (DEBUG(JOB) && isJobs) job_table_dump("no pid"); return NULL; } /*- *----------------------------------------------------------------------- * JobPrintCommand -- * Put out another command for the given job. If the command starts * with an @ or a - we process it specially. In the former case, * so long as the -s and -n flags weren't given to make, we stick * a shell-specific echoOff command in the script. In the latter, * we ignore errors for the entire job, unless the shell has error * control. * If the command is just "..." we take all future commands for this * job to be commands to be executed once the entire graph has been * made and return non-zero to signal that the end of the commands * was reached. These commands are later attached to the postCommands * node and executed by Job_End when all things are done. * This function is called from JobStart via Lst_ForEach. * * Input: * cmdp command string to print * jobp job for which to print it * * Results: * Always 0, unless the command was "..." * * Side Effects: * If the command begins with a '-' and the shell has no error control, * the JOB_IGNERR flag is set in the job descriptor. * If the command is "..." and we're not ignoring such things, * tailCmds is set to the successor node of the cmd. * numCommands is incremented if the command is actually printed. *----------------------------------------------------------------------- */ static int JobPrintCommand(void *cmdp, void *jobp) { Boolean noSpecials; /* true if we shouldn't worry about * inserting special commands into * the input stream. */ Boolean shutUp = FALSE; /* true if we put a no echo command * into the command file */ Boolean errOff = FALSE; /* true if we turned error checking * off before printing the command * and need to turn it back on */ const char *cmdTemplate; /* Template to use when printing the * command */ char *cmdStart; /* Start of expanded command */ char *escCmd = NULL; /* Command with quotes/backticks escaped */ char *cmd = (char *)cmdp; Job *job = (Job *)jobp; int i, j; noSpecials = NoExecute(job->node); if (strcmp(cmd, "...") == 0) { job->node->type |= OP_SAVE_CMDS; if ((job->flags & JOB_IGNDOTS) == 0) { job->tailCmds = Lst_Succ(Lst_Member(job->node->commands, cmd)); return 1; } return 0; } #define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \ (void)fprintf(debug_file, fmt, arg); \ } \ (void)fprintf(job->cmdFILE, fmt, arg); \ (void)fflush(job->cmdFILE); numCommands += 1; cmdStart = cmd = Var_Subst(NULL, cmd, job->node, VARF_WANTRES); cmdTemplate = "%s\n"; /* * Check for leading @' and -'s to control echoing and error checking. */ while (*cmd == '@' || *cmd == '-' || (*cmd == '+')) { switch (*cmd) { case '@': shutUp = DEBUG(LOUD) ? FALSE : TRUE; break; case '-': errOff = TRUE; break; case '+': if (noSpecials) { /* * We're not actually executing anything... * but this one needs to be - use compat mode just for it. */ CompatRunCommand(cmdp, job->node); free(cmdStart); return 0; } break; } cmd++; } while (isspace((unsigned char) *cmd)) cmd++; /* * If the shell doesn't have error control the alternate echo'ing will * be done (to avoid showing additional error checking code) * and this will need the characters '$ ` \ "' escaped */ if (!commandShell->hasErrCtl) { /* Worst that could happen is every char needs escaping. */ escCmd = bmake_malloc((strlen(cmd) * 2) + 1); for (i = 0, j= 0; cmd[i] != '\0'; i++, j++) { if (cmd[i] == '$' || cmd[i] == '`' || cmd[i] == '\\' || cmd[i] == '"') escCmd[j++] = '\\'; escCmd[j] = cmd[i]; } escCmd[j] = 0; } if (shutUp) { if (!(job->flags & JOB_SILENT) && !noSpecials && commandShell->hasEchoCtl) { DBPRINTF("%s\n", commandShell->echoOff); } else { if (commandShell->hasErrCtl) shutUp = FALSE; } } if (errOff) { if (!noSpecials) { if (commandShell->hasErrCtl) { /* * we don't want the error-control commands showing * up either, so we turn off echoing while executing * them. We could put another field in the shell * structure to tell JobDoOutput to look for this * string too, but why make it any more complex than * it already is? */ if (!(job->flags & JOB_SILENT) && !shutUp && commandShell->hasEchoCtl) { DBPRINTF("%s\n", commandShell->echoOff); DBPRINTF("%s\n", commandShell->ignErr); DBPRINTF("%s\n", commandShell->echoOn); } else { DBPRINTF("%s\n", commandShell->ignErr); } } else if (commandShell->ignErr && (*commandShell->ignErr != '\0')) { /* * The shell has no error control, so we need to be * weird to get it to ignore any errors from the command. * If echoing is turned on, we turn it off and use the * errCheck template to echo the command. Leave echoing * off so the user doesn't see the weirdness we go through * to ignore errors. Set cmdTemplate to use the weirdness * instead of the simple "%s\n" template. */ job->flags |= JOB_IGNERR; if (!(job->flags & JOB_SILENT) && !shutUp) { if (commandShell->hasEchoCtl) { DBPRINTF("%s\n", commandShell->echoOff); } DBPRINTF(commandShell->errCheck, escCmd); shutUp = TRUE; } else { if (!shutUp) { DBPRINTF(commandShell->errCheck, escCmd); } } cmdTemplate = commandShell->ignErr; /* * The error ignoration (hee hee) is already taken care * of by the ignErr template, so pretend error checking * is still on. */ errOff = FALSE; } else { errOff = FALSE; } } else { errOff = FALSE; } } else { /* * If errors are being checked and the shell doesn't have error control * but does supply an errOut template, then setup commands to run * through it. */ if (!commandShell->hasErrCtl && commandShell->errOut && (*commandShell->errOut != '\0')) { if (!(job->flags & JOB_SILENT) && !shutUp) { if (commandShell->hasEchoCtl) { DBPRINTF("%s\n", commandShell->echoOff); } DBPRINTF(commandShell->errCheck, escCmd); shutUp = TRUE; } /* If it's a comment line or blank, treat as an ignored error */ if ((escCmd[0] == commandShell->commentChar) || (escCmd[0] == 0)) cmdTemplate = commandShell->ignErr; else cmdTemplate = commandShell->errOut; errOff = FALSE; } } if (DEBUG(SHELL) && strcmp(shellName, "sh") == 0 && (job->flags & JOB_TRACED) == 0) { DBPRINTF("set -%s\n", "x"); job->flags |= JOB_TRACED; } DBPRINTF(cmdTemplate, cmd); free(cmdStart); free(escCmd); if (errOff) { /* * If echoing is already off, there's no point in issuing the * echoOff command. Otherwise we issue it and pretend it was on * for the whole command... */ if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){ DBPRINTF("%s\n", commandShell->echoOff); shutUp = TRUE; } DBPRINTF("%s\n", commandShell->errCheck); } if (shutUp && commandShell->hasEchoCtl) { DBPRINTF("%s\n", commandShell->echoOn); } return 0; } /*- *----------------------------------------------------------------------- * JobSaveCommand -- * Save a command to be executed when everything else is done. * Callback function for JobFinish... * * Results: * Always returns 0 * * Side Effects: * The command is tacked onto the end of postCommands's commands list. * *----------------------------------------------------------------------- */ static int JobSaveCommand(void *cmd, void *gn) { cmd = Var_Subst(NULL, (char *)cmd, (GNode *)gn, VARF_WANTRES); (void)Lst_AtEnd(postCommands->commands, cmd); return(0); } /*- *----------------------------------------------------------------------- * JobClose -- * Called to close both input and output pipes when a job is finished. * * Results: * Nada * * Side Effects: * The file descriptors associated with the job are closed. * *----------------------------------------------------------------------- */ static void JobClose(Job *job) { clearfd(job); (void)close(job->outPipe); job->outPipe = -1; JobDoOutput(job, TRUE); (void)close(job->inPipe); job->inPipe = -1; } /*- *----------------------------------------------------------------------- * JobFinish -- * Do final processing for the given job including updating * parents and starting new jobs as available/necessary. Note * that we pay no attention to the JOB_IGNERR flag here. * This is because when we're called because of a noexecute flag * or something, jstat.w_status is 0 and when called from * Job_CatchChildren, the status is zeroed if it s/b ignored. * * Input: * job job to finish * status sub-why job went away * * Results: * None * * Side Effects: * Final commands for the job are placed on postCommands. * * If we got an error and are aborting (aborting == ABORT_ERROR) and * the job list is now empty, we are done for the day. * If we recognized an error (errors !=0), we set the aborting flag * to ABORT_ERROR so no more jobs will be started. *----------------------------------------------------------------------- */ /*ARGSUSED*/ static void JobFinish (Job *job, WAIT_T status) { Boolean done, return_job_token; if (DEBUG(JOB)) { fprintf(debug_file, "Jobfinish: %d [%s], status %d\n", job->pid, job->node->name, status); } if ((WIFEXITED(status) && (((WEXITSTATUS(status) != 0) && !(job->flags & JOB_IGNERR)))) || WIFSIGNALED(status)) { /* * If it exited non-zero and either we're doing things our * way or we're not ignoring errors, the job is finished. * Similarly, if the shell died because of a signal * the job is also finished. In these * cases, finish out the job's output before printing the exit * status... */ JobClose(job); if (job->cmdFILE != NULL && job->cmdFILE != stdout) { (void)fclose(job->cmdFILE); job->cmdFILE = NULL; } done = TRUE; } else if (WIFEXITED(status)) { /* * Deal with ignored errors in -B mode. We need to print a message * telling of the ignored error as well as setting status.w_status * to 0 so the next command gets run. To do this, we set done to be * TRUE if in -B mode and the job exited non-zero. */ done = WEXITSTATUS(status) != 0; /* * Old comment said: "Note we don't * want to close down any of the streams until we know we're at the * end." * But we do. Otherwise when are we going to print the rest of the * stuff? */ JobClose(job); } else { /* * No need to close things down or anything. */ done = FALSE; } if (done) { if (WIFEXITED(status)) { if (DEBUG(JOB)) { (void)fprintf(debug_file, "Process %d [%s] exited.\n", job->pid, job->node->name); } if (WEXITSTATUS(status) != 0) { if (job->node != lastNode) { MESSAGE(stdout, job->node); lastNode = job->node; } #ifdef USE_META if (useMeta) { meta_job_error(job, job->node, job->flags, WEXITSTATUS(status)); } #endif (void)printf("*** [%s] Error code %d%s\n", job->node->name, WEXITSTATUS(status), (job->flags & JOB_IGNERR) ? " (ignored)" : ""); if (job->flags & JOB_IGNERR) { WAIT_STATUS(status) = 0; } else { if (deleteOnError) { JobDeleteTarget(job->node); } PrintOnError(job->node, NULL); } } else if (DEBUG(JOB)) { if (job->node != lastNode) { MESSAGE(stdout, job->node); lastNode = job->node; } (void)printf("*** [%s] Completed successfully\n", job->node->name); } } else { if (job->node != lastNode) { MESSAGE(stdout, job->node); lastNode = job->node; } (void)printf("*** [%s] Signal %d\n", job->node->name, WTERMSIG(status)); if (deleteOnError) { JobDeleteTarget(job->node); } } (void)fflush(stdout); } #ifdef USE_META if (useMeta) { int x; if ((x = meta_job_finish(job)) != 0 && status == 0) { status = x; } } #endif return_job_token = FALSE; Trace_Log(JOBEND, job); if (!(job->flags & JOB_SPECIAL)) { if ((WAIT_STATUS(status) != 0) || (aborting == ABORT_ERROR) || (aborting == ABORT_INTERRUPT)) return_job_token = TRUE; } if ((aborting != ABORT_ERROR) && (aborting != ABORT_INTERRUPT) && (WAIT_STATUS(status) == 0)) { /* * As long as we aren't aborting and the job didn't return a non-zero * status that we shouldn't ignore, we call Make_Update to update * the parents. In addition, any saved commands for the node are placed * on the .END target. */ if (job->tailCmds != NULL) { Lst_ForEachFrom(job->node->commands, job->tailCmds, JobSaveCommand, job->node); } job->node->made = MADE; if (!(job->flags & JOB_SPECIAL)) return_job_token = TRUE; Make_Update(job->node); job->job_state = JOB_ST_FREE; } else if (WAIT_STATUS(status)) { errors += 1; job->job_state = JOB_ST_FREE; } /* * Set aborting if any error. */ if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) { /* * If we found any errors in this batch of children and the -k flag * wasn't given, we set the aborting flag so no more jobs get * started. */ aborting = ABORT_ERROR; } if (return_job_token) Job_TokenReturn(); if (aborting == ABORT_ERROR && jobTokensRunning == 0) { /* * If we are aborting and the job table is now empty, we finish. */ Finish(errors); } } /*- *----------------------------------------------------------------------- * Job_Touch -- * Touch the given target. Called by JobStart when the -t flag was * given * * Input: * gn the node of the file to touch * silent TRUE if should not print message * * Results: * None * * Side Effects: * The data modification of the file is changed. In addition, if the * file did not exist, it is created. *----------------------------------------------------------------------- */ void Job_Touch(GNode *gn, Boolean silent) { int streamID; /* ID of stream opened to do the touch */ struct utimbuf times; /* Times for utime() call */ if (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC|OP_OPTIONAL| OP_SPECIAL|OP_PHONY)) { /* * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets * and, as such, shouldn't really be created. */ return; } if (!silent || NoExecute(gn)) { (void)fprintf(stdout, "touch %s\n", gn->name); (void)fflush(stdout); } if (NoExecute(gn)) { return; } if (gn->type & OP_ARCHV) { Arch_Touch(gn); } else if (gn->type & OP_LIB) { Arch_TouchLib(gn); } else { char *file = gn->path ? gn->path : gn->name; times.actime = times.modtime = now; if (utime(file, ×) < 0){ streamID = open(file, O_RDWR | O_CREAT, 0666); if (streamID >= 0) { char c; /* * Read and write a byte to the file to change the * modification time, then close the file. */ if (read(streamID, &c, 1) == 1) { (void)lseek(streamID, (off_t)0, SEEK_SET); while (write(streamID, &c, 1) == -1 && errno == EAGAIN) continue; } (void)close(streamID); } else { (void)fprintf(stdout, "*** couldn't touch %s: %s", file, strerror(errno)); (void)fflush(stdout); } } } } /*- *----------------------------------------------------------------------- * Job_CheckCommands -- * Make sure the given node has all the commands it needs. * * Input: * gn The target whose commands need verifying * abortProc Function to abort with message * * Results: * TRUE if the commands list is/was ok. * * Side Effects: * The node will have commands from the .DEFAULT rule added to it * if it needs them. *----------------------------------------------------------------------- */ Boolean Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...)) { if (OP_NOP(gn->type) && Lst_IsEmpty(gn->commands) && ((gn->type & OP_LIB) == 0 || Lst_IsEmpty(gn->children))) { /* * No commands. Look for .DEFAULT rule from which we might infer * commands */ if ((DEFAULT != NULL) && !Lst_IsEmpty(DEFAULT->commands) && (gn->type & OP_SPECIAL) == 0) { char *p1; /* * Make only looks for a .DEFAULT if the node was never the * target of an operator, so that's what we do too. If * a .DEFAULT was given, we substitute its commands for gn's * commands and set the IMPSRC variable to be the target's name * The DEFAULT node acts like a transformation rule, in that * gn also inherits any attributes or sources attached to * .DEFAULT itself. */ Make_HandleUse(DEFAULT, gn); Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn, 0); free(p1); } else if (Dir_MTime(gn, 0) == 0 && (gn->type & OP_SPECIAL) == 0) { /* * The node wasn't the target of an operator we have no .DEFAULT * rule to go on and the target doesn't already exist. There's * nothing more we can do for this branch. If the -k flag wasn't * given, we stop in our tracks, otherwise we just don't update * this node's parents so they never get examined. */ static const char msg[] = ": don't know how to make"; if (gn->flags & FROM_DEPEND) { if (!Job_RunTarget(".STALE", gn->fname)) fprintf(stdout, "%s: %s, %d: ignoring stale %s for %s\n", progname, gn->fname, gn->lineno, makeDependfile, gn->name); return TRUE; } if (gn->type & OP_OPTIONAL) { (void)fprintf(stdout, "%s%s %s (ignored)\n", progname, msg, gn->name); (void)fflush(stdout); } else if (keepgoing) { (void)fprintf(stdout, "%s%s %s (continuing)\n", progname, msg, gn->name); (void)fflush(stdout); return FALSE; } else { (*abortProc)("%s%s %s. Stop", progname, msg, gn->name); return FALSE; } } } return TRUE; } /*- *----------------------------------------------------------------------- * JobExec -- * Execute the shell for the given job. Called from JobStart * * Input: * job Job to execute * * Results: * None. * * Side Effects: * A shell is executed, outputs is altered and the Job structure added * to the job table. * *----------------------------------------------------------------------- */ static void JobExec(Job *job, char **argv) { int cpid; /* ID of new child */ sigset_t mask; job->flags &= ~JOB_TRACED; if (DEBUG(JOB)) { int i; (void)fprintf(debug_file, "Running %s %sly\n", job->node->name, "local"); (void)fprintf(debug_file, "\tCommand: "); for (i = 0; argv[i] != NULL; i++) { (void)fprintf(debug_file, "%s ", argv[i]); } (void)fprintf(debug_file, "\n"); } /* * Some jobs produce no output and it's disconcerting to have * no feedback of their running (since they produce no output, the * banner with their name in it never appears). This is an attempt to * provide that feedback, even if nothing follows it. */ if ((lastNode != job->node) && !(job->flags & JOB_SILENT)) { MESSAGE(stdout, job->node); lastNode = job->node; } /* No interruptions until this job is on the `jobs' list */ JobSigLock(&mask); /* Pre-emptively mark job running, pid still zero though */ job->job_state = JOB_ST_RUNNING; cpid = vFork(); if (cpid == -1) Punt("Cannot vfork: %s", strerror(errno)); if (cpid == 0) { /* Child */ sigset_t tmask; #ifdef USE_META if (useMeta) { meta_job_child(job); } #endif /* * Reset all signal handlers; this is necessary because we also * need to unblock signals before we exec(2). */ JobSigReset(); /* Now unblock signals */ sigemptyset(&tmask); JobSigUnlock(&tmask); /* * Must duplicate the input stream down to the child's input and * reset it to the beginning (again). Since the stream was marked * close-on-exec, we must clear that bit in the new input. */ if (dup2(FILENO(job->cmdFILE), 0) == -1) { execError("dup2", "job->cmdFILE"); _exit(1); } if (fcntl(0, F_SETFD, 0) == -1) { execError("fcntl clear close-on-exec", "stdin"); _exit(1); } if (lseek(0, (off_t)0, SEEK_SET) == -1) { execError("lseek to 0", "stdin"); _exit(1); } if (job->node->type & (OP_MAKE | OP_SUBMAKE)) { /* * Pass job token pipe to submakes. */ if (fcntl(tokenWaitJob.inPipe, F_SETFD, 0) == -1) { execError("clear close-on-exec", "tokenWaitJob.inPipe"); _exit(1); } if (fcntl(tokenWaitJob.outPipe, F_SETFD, 0) == -1) { execError("clear close-on-exec", "tokenWaitJob.outPipe"); _exit(1); } } /* * Set up the child's output to be routed through the pipe * we've created for it. */ if (dup2(job->outPipe, 1) == -1) { execError("dup2", "job->outPipe"); _exit(1); } /* * The output channels are marked close on exec. This bit was * duplicated by the dup2(on some systems), so we have to clear * it before routing the shell's error output to the same place as * its standard output. */ if (fcntl(1, F_SETFD, 0) == -1) { execError("clear close-on-exec", "stdout"); _exit(1); } if (dup2(1, 2) == -1) { execError("dup2", "1, 2"); _exit(1); } /* * We want to switch the child into a different process family so * we can kill it and all its descendants in one fell swoop, * by killing its process family, but not commit suicide. */ #if defined(HAVE_SETPGID) (void)setpgid(0, getpid()); #else #if defined(HAVE_SETSID) /* XXX: dsl - I'm sure this should be setpgrp()... */ (void)setsid(); #else (void)setpgrp(0, getpid()); #endif #endif Var_ExportVars(); (void)execv(shellPath, argv); execError("exec", shellPath); _exit(1); } /* Parent, continuing after the child exec */ job->pid = cpid; Trace_Log(JOBSTART, job); /* * Set the current position in the buffer to the beginning * and mark another stream to watch in the outputs mask */ job->curPos = 0; watchfd(job); if (job->cmdFILE != NULL && job->cmdFILE != stdout) { (void)fclose(job->cmdFILE); job->cmdFILE = NULL; } /* * Now the job is actually running, add it to the table. */ if (DEBUG(JOB)) { fprintf(debug_file, "JobExec(%s): pid %d added to jobs table\n", job->node->name, job->pid); job_table_dump("job started"); } JobSigUnlock(&mask); } /*- *----------------------------------------------------------------------- * JobMakeArgv -- * Create the argv needed to execute the shell for a given job. * * * Results: * * Side Effects: * *----------------------------------------------------------------------- */ static void JobMakeArgv(Job *job, char **argv) { int argc; static char args[10]; /* For merged arguments */ argv[0] = UNCONST(shellName); argc = 1; if ((commandShell->exit && (*commandShell->exit != '-')) || (commandShell->echo && (*commandShell->echo != '-'))) { /* * At least one of the flags doesn't have a minus before it, so * merge them together. Have to do this because the *(&(@*#*&#$# * Bourne shell thinks its second argument is a file to source. * Grrrr. Note the ten-character limitation on the combined arguments. */ (void)snprintf(args, sizeof(args), "-%s%s", ((job->flags & JOB_IGNERR) ? "" : (commandShell->exit ? commandShell->exit : "")), ((job->flags & JOB_SILENT) ? "" : (commandShell->echo ? commandShell->echo : ""))); if (args[1]) { argv[argc] = args; argc++; } } else { if (!(job->flags & JOB_IGNERR) && commandShell->exit) { argv[argc] = UNCONST(commandShell->exit); argc++; } if (!(job->flags & JOB_SILENT) && commandShell->echo) { argv[argc] = UNCONST(commandShell->echo); argc++; } } argv[argc] = NULL; } /*- *----------------------------------------------------------------------- * JobStart -- * Start a target-creation process going for the target described * by the graph node gn. * * Input: * gn target to create * flags flags for the job to override normal ones. * e.g. JOB_SPECIAL or JOB_IGNDOTS * previous The previous Job structure for this node, if any. * * Results: * JOB_ERROR if there was an error in the commands, JOB_FINISHED * if there isn't actually anything left to do for the job and * JOB_RUNNING if the job has been started. * * Side Effects: * A new Job node is created and added to the list of running * jobs. PMake is forked and a child shell created. * * NB: I'm fairly sure that this code is never called with JOB_SPECIAL set * JOB_IGNDOTS is never set (dsl) * Also the return value is ignored by everyone. *----------------------------------------------------------------------- */ static int JobStart(GNode *gn, int flags) { Job *job; /* new job descriptor */ char *argv[10]; /* Argument vector to shell */ Boolean cmdsOK; /* true if the nodes commands were all right */ Boolean noExec; /* Set true if we decide not to run the job */ int tfd; /* File descriptor to the temp file */ for (job = job_table; job < job_table_end; job++) { if (job->job_state == JOB_ST_FREE) break; } if (job >= job_table_end) Punt("JobStart no job slots vacant"); memset(job, 0, sizeof *job); job->job_state = JOB_ST_SETUP; if (gn->type & OP_SPECIAL) flags |= JOB_SPECIAL; job->node = gn; job->tailCmds = NULL; /* * Set the initial value of the flags for this job based on the global * ones and the node's attributes... Any flags supplied by the caller * are also added to the field. */ job->flags = 0; if (Targ_Ignore(gn)) { job->flags |= JOB_IGNERR; } if (Targ_Silent(gn)) { job->flags |= JOB_SILENT; } job->flags |= flags; /* * Check the commands now so any attributes from .DEFAULT have a chance * to migrate to the node */ cmdsOK = Job_CheckCommands(gn, Error); job->inPollfd = NULL; /* * If the -n flag wasn't given, we open up OUR (not the child's) * temporary file to stuff commands in it. The thing is rd/wr so we don't * need to reopen it to feed it to the shell. If the -n flag *was* given, * we just set the file to be stdout. Cute, huh? */ if (((gn->type & OP_MAKE) && !(noRecursiveExecute)) || (!noExecute && !touchFlag)) { /* * tfile is the name of a file into which all shell commands are * put. It is removed before the child shell is executed, unless * DEBUG(SCRIPT) is set. */ char *tfile; sigset_t mask; /* * We're serious here, but if the commands were bogus, we're * also dead... */ if (!cmdsOK) { PrintOnError(gn, NULL); /* provide some clue */ DieHorribly(); } JobSigLock(&mask); tfd = mkTempFile(TMPPAT, &tfile); if (!DEBUG(SCRIPT)) (void)eunlink(tfile); JobSigUnlock(&mask); job->cmdFILE = fdopen(tfd, "w+"); if (job->cmdFILE == NULL) { Punt("Could not fdopen %s", tfile); } (void)fcntl(FILENO(job->cmdFILE), F_SETFD, FD_CLOEXEC); /* * Send the commands to the command file, flush all its buffers then * rewind and remove the thing. */ noExec = FALSE; #ifdef USE_META if (useMeta) { meta_job_start(job, gn); if (Targ_Silent(gn)) { /* might have changed */ job->flags |= JOB_SILENT; } } #endif /* * We can do all the commands at once. hooray for sanity */ numCommands = 0; Lst_ForEach(gn->commands, JobPrintCommand, job); /* * If we didn't print out any commands to the shell script, * there's not much point in executing the shell, is there? */ if (numCommands == 0) { noExec = TRUE; } free(tfile); } else if (NoExecute(gn)) { /* * Not executing anything -- just print all the commands to stdout * in one fell swoop. This will still set up job->tailCmds correctly. */ if (lastNode != gn) { MESSAGE(stdout, gn); lastNode = gn; } job->cmdFILE = stdout; /* * Only print the commands if they're ok, but don't die if they're * not -- just let the user know they're bad and keep going. It * doesn't do any harm in this case and may do some good. */ if (cmdsOK) { Lst_ForEach(gn->commands, JobPrintCommand, job); } /* * Don't execute the shell, thank you. */ noExec = TRUE; } else { /* * Just touch the target and note that no shell should be executed. * Set cmdFILE to stdout to make life easier. Check the commands, too, * but don't die if they're no good -- it does no harm to keep working * up the graph. */ job->cmdFILE = stdout; Job_Touch(gn, job->flags&JOB_SILENT); noExec = TRUE; } /* Just in case it isn't already... */ (void)fflush(job->cmdFILE); /* * If we're not supposed to execute a shell, don't. */ if (noExec) { if (!(job->flags & JOB_SPECIAL)) Job_TokenReturn(); /* * Unlink and close the command file if we opened one */ if (job->cmdFILE != stdout) { if (job->cmdFILE != NULL) { (void)fclose(job->cmdFILE); job->cmdFILE = NULL; } } /* * We only want to work our way up the graph if we aren't here because * the commands for the job were no good. */ if (cmdsOK && aborting == 0) { if (job->tailCmds != NULL) { Lst_ForEachFrom(job->node->commands, job->tailCmds, JobSaveCommand, job->node); } job->node->made = MADE; Make_Update(job->node); } job->job_state = JOB_ST_FREE; return cmdsOK ? JOB_FINISHED : JOB_ERROR; } /* * Set up the control arguments to the shell. This is based on the flags * set earlier for this job. */ JobMakeArgv(job, argv); /* Create the pipe by which we'll get the shell's output. */ JobCreatePipe(job, 3); JobExec(job, argv); return(JOB_RUNNING); } static char * JobOutput(Job *job, char *cp, char *endp, int msg) { char *ecp; if (commandShell->noPrint) { ecp = Str_FindSubstring(cp, commandShell->noPrint); while (ecp != NULL) { if (cp != ecp) { *ecp = '\0'; if (!beSilent && msg && job->node != lastNode) { MESSAGE(stdout, job->node); lastNode = job->node; } /* * The only way there wouldn't be a newline after * this line is if it were the last in the buffer. * however, since the non-printable comes after it, * there must be a newline, so we don't print one. */ (void)fprintf(stdout, "%s", cp); (void)fflush(stdout); } cp = ecp + commandShell->noPLen; if (cp != endp) { /* * Still more to print, look again after skipping * the whitespace following the non-printable * command.... */ cp++; while (*cp == ' ' || *cp == '\t' || *cp == '\n') { cp++; } ecp = Str_FindSubstring(cp, commandShell->noPrint); } else { return cp; } } } return cp; } /*- *----------------------------------------------------------------------- * JobDoOutput -- * This function is called at different times depending on * whether the user has specified that output is to be collected * via pipes or temporary files. In the former case, we are called * whenever there is something to read on the pipe. We collect more * output from the given job and store it in the job's outBuf. If * this makes up a line, we print it tagged by the job's identifier, * as necessary. * If output has been collected in a temporary file, we open the * file and read it line by line, transfering it to our own * output channel until the file is empty. At which point we * remove the temporary file. * In both cases, however, we keep our figurative eye out for the * 'noPrint' line for the shell from which the output came. If * we recognize a line, we don't print it. If the command is not * alone on the line (the character after it is not \0 or \n), we * do print whatever follows it. * * Input: * job the job whose output needs printing * finish TRUE if this is the last time we'll be called * for this job * * Results: * None * * Side Effects: * curPos may be shifted as may the contents of outBuf. *----------------------------------------------------------------------- */ STATIC void JobDoOutput(Job *job, Boolean finish) { Boolean gotNL = FALSE; /* true if got a newline */ Boolean fbuf; /* true if our buffer filled up */ int nr; /* number of bytes read */ int i; /* auxiliary index into outBuf */ int max; /* limit for i (end of current data) */ int nRead; /* (Temporary) number of bytes read */ /* * Read as many bytes as will fit in the buffer. */ end_loop: gotNL = FALSE; fbuf = FALSE; nRead = read(job->inPipe, &job->outBuf[job->curPos], JOB_BUFSIZE - job->curPos); if (nRead < 0) { if (errno == EAGAIN) return; if (DEBUG(JOB)) { perror("JobDoOutput(piperead)"); } nr = 0; } else { nr = nRead; } /* * If we hit the end-of-file (the job is dead), we must flush its * remaining output, so pretend we read a newline if there's any * output remaining in the buffer. * Also clear the 'finish' flag so we stop looping. */ if ((nr == 0) && (job->curPos != 0)) { job->outBuf[job->curPos] = '\n'; nr = 1; finish = FALSE; } else if (nr == 0) { finish = FALSE; } /* * Look for the last newline in the bytes we just got. If there is * one, break out of the loop with 'i' as its index and gotNL set * TRUE. */ max = job->curPos + nr; for (i = job->curPos + nr - 1; i >= job->curPos; i--) { if (job->outBuf[i] == '\n') { gotNL = TRUE; break; } else if (job->outBuf[i] == '\0') { /* * Why? */ job->outBuf[i] = ' '; } } if (!gotNL) { job->curPos += nr; if (job->curPos == JOB_BUFSIZE) { /* * If we've run out of buffer space, we have no choice * but to print the stuff. sigh. */ fbuf = TRUE; i = job->curPos; } } if (gotNL || fbuf) { /* * Need to send the output to the screen. Null terminate it * first, overwriting the newline character if there was one. * So long as the line isn't one we should filter (according * to the shell description), we print the line, preceded * by a target banner if this target isn't the same as the * one for which we last printed something. * The rest of the data in the buffer are then shifted down * to the start of the buffer and curPos is set accordingly. */ job->outBuf[i] = '\0'; if (i >= job->curPos) { char *cp; cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE); /* * There's still more in that thar buffer. This time, though, * we know there's no newline at the end, so we add one of * our own free will. */ if (*cp != '\0') { if (!beSilent && job->node != lastNode) { MESSAGE(stdout, job->node); lastNode = job->node; } #ifdef USE_META if (useMeta) { meta_job_output(job, cp, gotNL ? "\n" : ""); } #endif (void)fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); (void)fflush(stdout); } } /* * max is the last offset still in the buffer. Move any remaining * characters to the start of the buffer and update the end marker * curPos. */ if (i < max) { (void)memmove(job->outBuf, &job->outBuf[i + 1], max - (i + 1)); job->curPos = max - (i + 1); } else { assert(i == max); job->curPos = 0; } } if (finish) { /* * If the finish flag is true, we must loop until we hit * end-of-file on the pipe. This is guaranteed to happen * eventually since the other end of the pipe is now closed * (we closed it explicitly and the child has exited). When * we do get an EOF, finish will be set FALSE and we'll fall * through and out. */ goto end_loop; } } static void JobRun(GNode *targ) { #ifdef notyet /* * Unfortunately it is too complicated to run .BEGIN, .END, * and .INTERRUPT job in the parallel job module. This has * the nice side effect that it avoids a lot of other problems. */ Lst lst = Lst_Init(FALSE); Lst_AtEnd(lst, targ); (void)Make_Run(lst); Lst_Destroy(lst, NULL); JobStart(targ, JOB_SPECIAL); while (jobTokensRunning) { Job_CatchOutput(); } #else Compat_Make(targ, targ); if (targ->made == ERROR) { PrintOnError(targ, "\n\nStop."); exit(1); } #endif } /*- *----------------------------------------------------------------------- * Job_CatchChildren -- * Handle the exit of a child. Called from Make_Make. * * Input: * block TRUE if should block on the wait * * Results: * none. * * Side Effects: * The job descriptor is removed from the list of children. * * Notes: * We do waits, blocking or not, according to the wisdom of our * caller, until there are no more children to report. For each * job, call JobFinish to finish things off. * *----------------------------------------------------------------------- */ void Job_CatchChildren(void) { int pid; /* pid of dead child */ WAIT_T status; /* Exit/termination status */ /* * Don't even bother if we know there's no one around. */ if (jobTokensRunning == 0) return; while ((pid = waitpid((pid_t) -1, &status, WNOHANG | WUNTRACED)) > 0) { if (DEBUG(JOB)) { (void)fprintf(debug_file, "Process %d exited/stopped status %x.\n", pid, WAIT_STATUS(status)); } JobReapChild(pid, status, TRUE); } } /* * It is possible that wait[pid]() was called from elsewhere, * this lets us reap jobs regardless. */ void JobReapChild(pid_t pid, WAIT_T status, Boolean isJobs) { Job *job; /* job descriptor for dead child */ /* * Don't even bother if we know there's no one around. */ if (jobTokensRunning == 0) return; job = JobFindPid(pid, JOB_ST_RUNNING, isJobs); if (job == NULL) { if (isJobs) { if (!lurking_children) Error("Child (%d) status %x not in table?", pid, status); } return; /* not ours */ } if (WIFSTOPPED(status)) { if (DEBUG(JOB)) { (void)fprintf(debug_file, "Process %d (%s) stopped.\n", job->pid, job->node->name); } if (!make_suspended) { switch (WSTOPSIG(status)) { case SIGTSTP: (void)printf("*** [%s] Suspended\n", job->node->name); break; case SIGSTOP: (void)printf("*** [%s] Stopped\n", job->node->name); break; default: (void)printf("*** [%s] Stopped -- signal %d\n", job->node->name, WSTOPSIG(status)); } job->job_suspended = 1; } (void)fflush(stdout); return; } job->job_state = JOB_ST_FINISHED; job->exit_status = WAIT_STATUS(status); JobFinish(job, status); } /*- *----------------------------------------------------------------------- * Job_CatchOutput -- * Catch the output from our children, if we're using * pipes do so. Otherwise just block time until we get a * signal(most likely a SIGCHLD) since there's no point in * just spinning when there's nothing to do and the reaping * of a child can wait for a while. * * Results: * None * * Side Effects: * Output is read from pipes if we're piping. * ----------------------------------------------------------------------- */ void Job_CatchOutput(void) { int nready; Job *job; int i; (void)fflush(stdout); /* The first fd in the list is the job token pipe */ do { nready = poll(fds + 1 - wantToken, nfds - 1 + wantToken, POLL_MSEC); } while (nready < 0 && errno == EINTR); if (nready < 0) Punt("poll: %s", strerror(errno)); if (nready > 0 && readyfd(&childExitJob)) { char token = 0; ssize_t count; count = read(childExitJob.inPipe, &token, 1); switch (count) { case 0: Punt("unexpected eof on token pipe"); case -1: Punt("token pipe read: %s", strerror(errno)); case 1: if (token == DO_JOB_RESUME[0]) /* Complete relay requested from our SIGCONT handler */ JobRestartJobs(); break; default: abort(); } --nready; } Job_CatchChildren(); if (nready == 0) return; for (i = 2; i < nfds; i++) { if (!fds[i].revents) continue; job = jobfds[i]; if (job->job_state == JOB_ST_RUNNING) JobDoOutput(job, FALSE); if (--nready == 0) return; } } /*- *----------------------------------------------------------------------- * Job_Make -- * Start the creation of a target. Basically a front-end for * JobStart used by the Make module. * * Results: * None. * * Side Effects: * Another job is started. * *----------------------------------------------------------------------- */ void Job_Make(GNode *gn) { (void)JobStart(gn, 0); } void Shell_Init(void) { if (shellPath == NULL) { /* * We are using the default shell, which may be an absolute * path if DEFSHELL_CUSTOM is defined. */ shellName = commandShell->name; #ifdef DEFSHELL_CUSTOM if (*shellName == '/') { shellPath = shellName; shellName = strrchr(shellPath, '/'); shellName++; } else #endif shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); } if (commandShell->exit == NULL) { commandShell->exit = ""; } if (commandShell->echo == NULL) { commandShell->echo = ""; } if (commandShell->hasErrCtl && *commandShell->exit) { if (shellErrFlag && strcmp(commandShell->exit, &shellErrFlag[1]) != 0) { free(shellErrFlag); shellErrFlag = NULL; } if (!shellErrFlag) { int n = strlen(commandShell->exit) + 2; shellErrFlag = bmake_malloc(n); if (shellErrFlag) { snprintf(shellErrFlag, n, "-%s", commandShell->exit); } } } else if (shellErrFlag) { free(shellErrFlag); shellErrFlag = NULL; } } /*- * Returns the string literal that is used in the current command shell * to produce a newline character. */ const char * Shell_GetNewline(void) { return commandShell->newline; } void Job_SetPrefix(void) { if (targPrefix) { free(targPrefix); } else if (!Var_Exists(MAKE_JOB_PREFIX, VAR_GLOBAL)) { Var_Set(MAKE_JOB_PREFIX, "---", VAR_GLOBAL, 0); } targPrefix = Var_Subst(NULL, "${" MAKE_JOB_PREFIX "}", VAR_GLOBAL, VARF_WANTRES); } /*- *----------------------------------------------------------------------- * Job_Init -- * Initialize the process module * * Input: * * Results: * none * * Side Effects: * lists and counters are initialized *----------------------------------------------------------------------- */ void Job_Init(void) { Job_SetPrefix(); /* Allocate space for all the job info */ job_table = bmake_malloc(maxJobs * sizeof *job_table); memset(job_table, 0, maxJobs * sizeof *job_table); job_table_end = job_table + maxJobs; wantToken = 0; aborting = 0; errors = 0; lastNode = NULL; /* * There is a non-zero chance that we already have children. * eg after 'make -f- < 0) continue; if (rval == 0) lurking_children = 1; break; } Shell_Init(); JobCreatePipe(&childExitJob, 3); /* We can only need to wait for tokens, children and output from each job */ fds = bmake_malloc(sizeof (*fds) * (2 + maxJobs)); jobfds = bmake_malloc(sizeof (*jobfds) * (2 + maxJobs)); /* These are permanent entries and take slots 0 and 1 */ watchfd(&tokenWaitJob); watchfd(&childExitJob); sigemptyset(&caught_signals); /* * Install a SIGCHLD handler. */ (void)bmake_signal(SIGCHLD, JobChildSig); sigaddset(&caught_signals, SIGCHLD); #define ADDSIG(s,h) \ if (bmake_signal(s, SIG_IGN) != SIG_IGN) { \ sigaddset(&caught_signals, s); \ (void)bmake_signal(s, h); \ } /* * Catch the four signals that POSIX specifies if they aren't ignored. * JobPassSig will take care of calling JobInterrupt if appropriate. */ ADDSIG(SIGINT, JobPassSig_int) ADDSIG(SIGHUP, JobPassSig_term) ADDSIG(SIGTERM, JobPassSig_term) ADDSIG(SIGQUIT, JobPassSig_term) /* * There are additional signals that need to be caught and passed if * either the export system wants to be told directly of signals or if * we're giving each job its own process group (since then it won't get * signals from the terminal driver as we own the terminal) */ ADDSIG(SIGTSTP, JobPassSig_suspend) ADDSIG(SIGTTOU, JobPassSig_suspend) ADDSIG(SIGTTIN, JobPassSig_suspend) ADDSIG(SIGWINCH, JobCondPassSig) ADDSIG(SIGCONT, JobContinueSig) #undef ADDSIG (void)Job_RunTarget(".BEGIN", NULL); postCommands = Targ_FindNode(".END", TARG_CREATE); } static void JobSigReset(void) { #define DELSIG(s) \ if (sigismember(&caught_signals, s)) { \ (void)bmake_signal(s, SIG_DFL); \ } DELSIG(SIGINT) DELSIG(SIGHUP) DELSIG(SIGQUIT) DELSIG(SIGTERM) DELSIG(SIGTSTP) DELSIG(SIGTTOU) DELSIG(SIGTTIN) DELSIG(SIGWINCH) DELSIG(SIGCONT) #undef DELSIG (void)bmake_signal(SIGCHLD, SIG_DFL); } /*- *----------------------------------------------------------------------- * JobMatchShell -- * Find a shell in 'shells' given its name. * * Results: * A pointer to the Shell structure. * * Side Effects: * None. * *----------------------------------------------------------------------- */ static Shell * JobMatchShell(const char *name) { Shell *sh; for (sh = shells; sh->name != NULL; sh++) { if (strcmp(name, sh->name) == 0) return (sh); } return NULL; } /*- *----------------------------------------------------------------------- * Job_ParseShell -- * Parse a shell specification and set up commandShell, shellPath * and shellName appropriately. * * Input: * line The shell spec * * Results: * FAILURE if the specification was incorrect. * * Side Effects: * commandShell points to a Shell structure (either predefined or * created from the shell spec), shellPath is the full path of the * shell described by commandShell, while shellName is just the * final component of shellPath. * * Notes: * A shell specification consists of a .SHELL target, with dependency * operator, followed by a series of blank-separated words. Double * quotes can be used to use blanks in words. A backslash escapes * anything (most notably a double-quote and a space) and * provides the functionality it does in C. Each word consists of * keyword and value separated by an equal sign. There should be no * unnecessary spaces in the word. The keywords are as follows: * name Name of shell. * path Location of shell. * quiet Command to turn off echoing. * echo Command to turn echoing on * filter Result of turning off echoing that shouldn't be * printed. * echoFlag Flag to turn echoing on at the start * errFlag Flag to turn error checking on at the start * hasErrCtl True if shell has error checking control * newline String literal to represent a newline char * check Command to turn on error checking if hasErrCtl * is TRUE or template of command to echo a command * for which error checking is off if hasErrCtl is * FALSE. * ignore Command to turn off error checking if hasErrCtl * is TRUE or template of command to execute a * command so as to ignore any errors it returns if * hasErrCtl is FALSE. * *----------------------------------------------------------------------- */ ReturnStatus Job_ParseShell(char *line) { char **words; char **argv; int argc; char *path; Shell newShell; Boolean fullSpec = FALSE; Shell *sh; while (isspace((unsigned char)*line)) { line++; } free(UNCONST(shellArgv)); memset(&newShell, 0, sizeof(newShell)); /* * Parse the specification by keyword */ words = brk_string(line, &argc, TRUE, &path); if (words == NULL) { Error("Unterminated quoted string [%s]", line); return FAILURE; } shellArgv = path; for (path = NULL, argv = words; argc != 0; argc--, argv++) { if (strncmp(*argv, "path=", 5) == 0) { path = &argv[0][5]; } else if (strncmp(*argv, "name=", 5) == 0) { newShell.name = &argv[0][5]; } else { if (strncmp(*argv, "quiet=", 6) == 0) { newShell.echoOff = &argv[0][6]; } else if (strncmp(*argv, "echo=", 5) == 0) { newShell.echoOn = &argv[0][5]; } else if (strncmp(*argv, "filter=", 7) == 0) { newShell.noPrint = &argv[0][7]; newShell.noPLen = strlen(newShell.noPrint); } else if (strncmp(*argv, "echoFlag=", 9) == 0) { newShell.echo = &argv[0][9]; } else if (strncmp(*argv, "errFlag=", 8) == 0) { newShell.exit = &argv[0][8]; } else if (strncmp(*argv, "hasErrCtl=", 10) == 0) { char c = argv[0][10]; newShell.hasErrCtl = !((c != 'Y') && (c != 'y') && (c != 'T') && (c != 't')); } else if (strncmp(*argv, "newline=", 8) == 0) { newShell.newline = &argv[0][8]; } else if (strncmp(*argv, "check=", 6) == 0) { newShell.errCheck = &argv[0][6]; } else if (strncmp(*argv, "ignore=", 7) == 0) { newShell.ignErr = &argv[0][7]; } else if (strncmp(*argv, "errout=", 7) == 0) { newShell.errOut = &argv[0][7]; } else if (strncmp(*argv, "comment=", 8) == 0) { newShell.commentChar = argv[0][8]; } else { Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", *argv); free(words); return(FAILURE); } fullSpec = TRUE; } } if (path == NULL) { /* * If no path was given, the user wants one of the pre-defined shells, * yes? So we find the one s/he wants with the help of JobMatchShell * and set things up the right way. shellPath will be set up by * Shell_Init. */ if (newShell.name == NULL) { Parse_Error(PARSE_FATAL, "Neither path nor name specified"); free(words); return(FAILURE); } else { if ((sh = JobMatchShell(newShell.name)) == NULL) { Parse_Error(PARSE_WARNING, "%s: No matching shell", newShell.name); free(words); return(FAILURE); } commandShell = sh; shellName = newShell.name; if (shellPath) { /* Shell_Init has already been called! Do it again. */ free(UNCONST(shellPath)); shellPath = NULL; Shell_Init(); } } } else { /* * The user provided a path. If s/he gave nothing else (fullSpec is * FALSE), try and find a matching shell in the ones we know of. * Else we just take the specification at its word and copy it * to a new location. In either case, we need to record the * path the user gave for the shell. */ shellPath = path; path = strrchr(path, '/'); if (path == NULL) { path = UNCONST(shellPath); } else { path += 1; } if (newShell.name != NULL) { shellName = newShell.name; } else { shellName = path; } if (!fullSpec) { if ((sh = JobMatchShell(shellName)) == NULL) { Parse_Error(PARSE_WARNING, "%s: No matching shell", shellName); free(words); return(FAILURE); } commandShell = sh; } else { commandShell = bmake_malloc(sizeof(Shell)); *commandShell = newShell; } /* this will take care of shellErrFlag */ Shell_Init(); } if (commandShell->echoOn && commandShell->echoOff) { commandShell->hasEchoCtl = TRUE; } if (!commandShell->hasErrCtl) { if (commandShell->errCheck == NULL) { commandShell->errCheck = ""; } if (commandShell->ignErr == NULL) { commandShell->ignErr = "%s\n"; } } /* * Do not free up the words themselves, since they might be in use by the * shell specification. */ free(words); return SUCCESS; } /*- *----------------------------------------------------------------------- * JobInterrupt -- * Handle the receipt of an interrupt. * * Input: * runINTERRUPT Non-zero if commands for the .INTERRUPT target * should be executed * signo signal received * * Results: * None * * Side Effects: * All children are killed. Another job will be started if the * .INTERRUPT target was given. *----------------------------------------------------------------------- */ static void JobInterrupt(int runINTERRUPT, int signo) { Job *job; /* job descriptor in that element */ GNode *interrupt; /* the node describing the .INTERRUPT target */ sigset_t mask; GNode *gn; aborting = ABORT_INTERRUPT; JobSigLock(&mask); for (job = job_table; job < job_table_end; job++) { if (job->job_state != JOB_ST_RUNNING) continue; gn = job->node; JobDeleteTarget(gn); if (job->pid) { if (DEBUG(JOB)) { (void)fprintf(debug_file, "JobInterrupt passing signal %d to child %d.\n", signo, job->pid); } KILLPG(job->pid, signo); } } JobSigUnlock(&mask); if (runINTERRUPT && !touchFlag) { interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); if (interrupt != NULL) { ignoreErrors = FALSE; JobRun(interrupt); } } Trace_Log(MAKEINTR, 0); exit(signo); } /* *----------------------------------------------------------------------- * Job_Finish -- * Do final processing such as the running of the commands * attached to the .END target. * * Results: * Number of errors reported. * * Side Effects: * None. *----------------------------------------------------------------------- */ int Job_Finish(void) { if (postCommands != NULL && (!Lst_IsEmpty(postCommands->commands) || !Lst_IsEmpty(postCommands->children))) { if (errors) { Error("Errors reported so .END ignored"); } else { JobRun(postCommands); } } return(errors); } /*- *----------------------------------------------------------------------- * Job_End -- * Cleanup any memory used by the jobs module * * Results: * None. * * Side Effects: * Memory is freed *----------------------------------------------------------------------- */ void Job_End(void) { #ifdef CLEANUP free(shellArgv); #endif } /*- *----------------------------------------------------------------------- * Job_Wait -- * Waits for all running jobs to finish and returns. Sets 'aborting' * to ABORT_WAIT to prevent other jobs from starting. * * Results: * None. * * Side Effects: * Currently running jobs finish. * *----------------------------------------------------------------------- */ void Job_Wait(void) { aborting = ABORT_WAIT; while (jobTokensRunning != 0) { Job_CatchOutput(); } aborting = 0; } /*- *----------------------------------------------------------------------- * Job_AbortAll -- * Abort all currently running jobs without handling output or anything. * This function is to be called only in the event of a major * error. Most definitely NOT to be called from JobInterrupt. * * Results: * None * * Side Effects: * All children are killed, not just the firstborn *----------------------------------------------------------------------- */ void Job_AbortAll(void) { Job *job; /* the job descriptor in that element */ WAIT_T foo; aborting = ABORT_ERROR; if (jobTokensRunning) { for (job = job_table; job < job_table_end; job++) { if (job->job_state != JOB_ST_RUNNING) continue; /* * kill the child process with increasingly drastic signals to make * darn sure it's dead. */ KILLPG(job->pid, SIGINT); KILLPG(job->pid, SIGKILL); } } /* * Catch as many children as want to report in at first, then give up */ while (waitpid((pid_t) -1, &foo, WNOHANG) > 0) continue; } /*- *----------------------------------------------------------------------- * JobRestartJobs -- * Tries to restart stopped jobs if there are slots available. * Called in process context in response to a SIGCONT. * * Results: * None. * * Side Effects: * Resumes jobs. * *----------------------------------------------------------------------- */ static void JobRestartJobs(void) { Job *job; for (job = job_table; job < job_table_end; job++) { if (job->job_state == JOB_ST_RUNNING && (make_suspended || job->job_suspended)) { if (DEBUG(JOB)) { (void)fprintf(debug_file, "Restarting stopped job pid %d.\n", job->pid); } if (job->job_suspended) { (void)printf("*** [%s] Continued\n", job->node->name); (void)fflush(stdout); } job->job_suspended = 0; if (KILLPG(job->pid, SIGCONT) != 0 && DEBUG(JOB)) { fprintf(debug_file, "Failed to send SIGCONT to %d\n", job->pid); } } if (job->job_state == JOB_ST_FINISHED) /* Job exit deferred after calling waitpid() in a signal handler */ JobFinish(job, job->exit_status); } make_suspended = 0; } static void watchfd(Job *job) { if (job->inPollfd != NULL) Punt("Watching watched job"); fds[nfds].fd = job->inPipe; fds[nfds].events = POLLIN; jobfds[nfds] = job; job->inPollfd = &fds[nfds]; nfds++; } static void clearfd(Job *job) { int i; if (job->inPollfd == NULL) Punt("Unwatching unwatched job"); i = job->inPollfd - fds; nfds--; /* * Move last job in table into hole made by dead job. */ if (nfds != i) { fds[i] = fds[nfds]; jobfds[i] = jobfds[nfds]; jobfds[i]->inPollfd = &fds[i]; } job->inPollfd = NULL; } static int readyfd(Job *job) { if (job->inPollfd == NULL) Punt("Polling unwatched job"); return (job->inPollfd->revents & POLLIN) != 0; } /*- *----------------------------------------------------------------------- * JobTokenAdd -- * Put a token into the job pipe so that some make process can start * another job. * * Side Effects: * Allows more build jobs to be spawned somewhere. * *----------------------------------------------------------------------- */ static void JobTokenAdd(void) { char tok = JOB_TOKENS[aborting], tok1; /* If we are depositing an error token flush everything else */ while (tok != '+' && read(tokenWaitJob.inPipe, &tok1, 1) == 1) continue; if (DEBUG(JOB)) fprintf(debug_file, "(%d) aborting %d, deposit token %c\n", getpid(), aborting, JOB_TOKENS[aborting]); while (write(tokenWaitJob.outPipe, &tok, 1) == -1 && errno == EAGAIN) continue; } /*- *----------------------------------------------------------------------- * Job_ServerStartTokenAdd -- * Prep the job token pipe in the root make process. * *----------------------------------------------------------------------- */ void Job_ServerStart(int max_tokens, int jp_0, int jp_1) { int i; char jobarg[64]; if (jp_0 >= 0 && jp_1 >= 0) { /* Pipe passed in from parent */ tokenWaitJob.inPipe = jp_0; tokenWaitJob.outPipe = jp_1; (void)fcntl(jp_0, F_SETFD, FD_CLOEXEC); (void)fcntl(jp_1, F_SETFD, FD_CLOEXEC); return; } JobCreatePipe(&tokenWaitJob, 15); snprintf(jobarg, sizeof(jobarg), "%d,%d", tokenWaitJob.inPipe, tokenWaitJob.outPipe); Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); Var_Append(MAKEFLAGS, jobarg, VAR_GLOBAL); /* * Preload the job pipe with one token per job, save the one * "extra" token for the primary job. * * XXX should clip maxJobs against PIPE_BUF -- if max_tokens is * larger than the write buffer size of the pipe, we will * deadlock here. */ for (i = 1; i < max_tokens; i++) JobTokenAdd(); } /*- *----------------------------------------------------------------------- * Job_TokenReturn -- * Return a withdrawn token to the pool. * *----------------------------------------------------------------------- */ void Job_TokenReturn(void) { jobTokensRunning--; if (jobTokensRunning < 0) Punt("token botch"); if (jobTokensRunning || JOB_TOKENS[aborting] != '+') JobTokenAdd(); } /*- *----------------------------------------------------------------------- * Job_TokenWithdraw -- * Attempt to withdraw a token from the pool. * * Results: * Returns TRUE if a token was withdrawn, and FALSE if the pool * is currently empty. * * Side Effects: * If pool is empty, set wantToken so that we wake up * when a token is released. * *----------------------------------------------------------------------- */ Boolean Job_TokenWithdraw(void) { char tok, tok1; int count; wantToken = 0; if (DEBUG(JOB)) fprintf(debug_file, "Job_TokenWithdraw(%d): aborting %d, running %d\n", getpid(), aborting, jobTokensRunning); if (aborting || (jobTokensRunning >= maxJobs)) return FALSE; count = read(tokenWaitJob.inPipe, &tok, 1); if (count == 0) Fatal("eof on job pipe!"); if (count < 0 && jobTokensRunning != 0) { if (errno != EAGAIN) { Fatal("job pipe read: %s", strerror(errno)); } if (DEBUG(JOB)) fprintf(debug_file, "(%d) blocked for token\n", getpid()); wantToken = 1; return FALSE; } if (count == 1 && tok != '+') { /* make being abvorted - remove any other job tokens */ if (DEBUG(JOB)) fprintf(debug_file, "(%d) aborted by token %c\n", getpid(), tok); while (read(tokenWaitJob.inPipe, &tok1, 1) == 1) continue; /* And put the stopper back */ while (write(tokenWaitJob.outPipe, &tok, 1) == -1 && errno == EAGAIN) continue; Fatal("A failure has been detected in another branch of the parallel make"); } if (count == 1 && jobTokensRunning == 0) /* We didn't want the token really */ while (write(tokenWaitJob.outPipe, &tok, 1) == -1 && errno == EAGAIN) continue; jobTokensRunning++; if (DEBUG(JOB)) fprintf(debug_file, "(%d) withdrew token\n", getpid()); return TRUE; } /*- *----------------------------------------------------------------------- * Job_RunTarget -- * Run the named target if found. If a filename is specified, then * set that to the sources. * * Results: * None * * Side Effects: * exits if the target fails. * *----------------------------------------------------------------------- */ Boolean Job_RunTarget(const char *target, const char *fname) { GNode *gn = Targ_FindNode(target, TARG_NOCREATE); if (gn == NULL) return FALSE; if (fname) Var_Set(ALLSRC, fname, gn, 0); JobRun(gn); if (gn->made == ERROR) { PrintOnError(gn, "\n\nStop."); exit(1); } return TRUE; } #ifdef USE_SELECT int emul_poll(struct pollfd *fd, int nfd, int timeout) { fd_set rfds, wfds; int i, maxfd, nselect, npoll; struct timeval tv, *tvp; long usecs; FD_ZERO(&rfds); FD_ZERO(&wfds); maxfd = -1; for (i = 0; i < nfd; i++) { fd[i].revents = 0; if (fd[i].events & POLLIN) FD_SET(fd[i].fd, &rfds); if (fd[i].events & POLLOUT) FD_SET(fd[i].fd, &wfds); if (fd[i].fd > maxfd) maxfd = fd[i].fd; } if (maxfd >= FD_SETSIZE) { Punt("Ran out of fd_set slots; " "recompile with a larger FD_SETSIZE."); } if (timeout < 0) { tvp = NULL; } else { usecs = timeout * 1000; tv.tv_sec = usecs / 1000000; tv.tv_usec = usecs % 1000000; tvp = &tv; } nselect = select(maxfd + 1, &rfds, &wfds, 0, tvp); if (nselect <= 0) return nselect; npoll = 0; for (i = 0; i < nfd; i++) { if (FD_ISSET(fd[i].fd, &rfds)) fd[i].revents |= POLLIN; if (FD_ISSET(fd[i].fd, &wfds)) fd[i].revents |= POLLOUT; if (fd[i].revents) npoll++; } return npoll; } #endif /* USE_SELECT */ Index: vendor/NetBSD/bmake/dist/make.h =================================================================== --- vendor/NetBSD/bmake/dist/make.h (revision 321401) +++ vendor/NetBSD/bmake/dist/make.h (revision 321402) @@ -1,546 +1,552 @@ -/* $NetBSD: make.h,v 1.102 2016/12/07 15:00:46 christos Exp $ */ +/* $NetBSD: make.h,v 1.103 2017/07/20 19:29:54 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 * 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. * * from: @(#)make.h 8.3 (Berkeley) 6/13/95 */ /* * 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. * * from: @(#)make.h 8.3 (Berkeley) 6/13/95 */ /*- * make.h -- * The global definitions for pmake */ #ifndef _MAKE_H_ #define _MAKE_H_ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #ifdef HAVE_STRING_H #include #else #include #endif #include #include #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif #if defined(__GNUC__) #define MAKE_GNUC_PREREQ(x, y) \ ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \ (__GNUC__ > (x))) #else /* defined(__GNUC__) */ #define MAKE_GNUC_PREREQ(x, y) 0 #endif /* defined(__GNUC__) */ #if MAKE_GNUC_PREREQ(2, 7) #define MAKE_ATTR_UNUSED __attribute__((__unused__)) #else #define MAKE_ATTR_UNUSED /* delete */ #endif #if MAKE_GNUC_PREREQ(2, 5) #define MAKE_ATTR_DEAD __attribute__((__noreturn__)) #elif defined(__GNUC__) #define MAKE_ATTR_DEAD __volatile #else #define MAKE_ATTR_DEAD /* delete */ #endif #if MAKE_GNUC_PREREQ(2, 7) #define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) \ __attribute__((__format__ (__printf__, fmtarg, firstvararg))) #else #define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) /* delete */ #endif #include "sprite.h" #include "lst.h" #include "hash.h" #include "make-conf.h" #include "buf.h" #include "make_malloc.h" /* * some vendors don't have this --sjg */ #if defined(S_IFDIR) && !defined(S_ISDIR) # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif #if defined(sun) && (defined(__svr4__) || defined(__SVR4)) #define POSIX_SIGNALS #endif /*- * The structure for an individual graph node. Each node has several * pieces of data associated with it. * 1) the name of the target it describes * 2) the location of the target file in the file system. * 3) the type of operator used to define its sources (qv. parse.c) * 4) whether it is involved in this invocation of make * 5) whether the target has been remade * 6) whether any of its children has been remade * 7) the number of its children that are, as yet, unmade * 8) its modification time * 9) the modification time of its youngest child (qv. make.c) * 10) a list of nodes for which this is a source (parents) * 11) a list of nodes on which this depends (children) * 12) a list of nodes that depend on this, as gleaned from the * transformation rules (iParents) * 13) a list of ancestor nodes, which includes parents, iParents, * and recursive parents of parents * 14) a list of nodes of the same name created by the :: operator * 15) a list of nodes that must be made (if they're made) before * this node can be, but that do not enter into the datedness of * this node. * 16) a list of nodes that must be made (if they're made) before * this node or any child of this node can be, but that do not * enter into the datedness of this node. * 17) a list of nodes that must be made (if they're made) after * this node is, but that do not depend on this node, in the * normal sense. * 18) a Lst of ``local'' variables that are specific to this target * and this target only (qv. var.c [$@ $< $?, etc.]) * 19) a Lst of strings that are commands to be given to a shell * to create this target. */ typedef struct GNode { char *name; /* The target's name */ char *uname; /* The unexpanded name of a .USE node */ char *path; /* The full pathname of the file */ int type; /* Its type (see the OP flags, below) */ int flags; #define REMAKE 0x1 /* this target needs to be (re)made */ #define CHILDMADE 0x2 /* children of this target were made */ #define FORCE 0x4 /* children don't exist, and we pretend made */ #define DONE_WAIT 0x8 /* Set by Make_ProcessWait() */ #define DONE_ORDER 0x10 /* Build requested by .ORDER processing */ #define FROM_DEPEND 0x20 /* Node created from .depend */ #define DONE_ALLSRC 0x40 /* We do it once only */ #define CYCLE 0x1000 /* Used by MakePrintStatus */ #define DONECYCLE 0x2000 /* Used by MakePrintStatus */ #define INTERNAL 0x4000 /* Internal use only */ enum enum_made { UNMADE, DEFERRED, REQUESTED, BEINGMADE, MADE, UPTODATE, ERROR, ABORTED } made; /* Set to reflect the state of processing * on this node: * UNMADE - Not examined yet * DEFERRED - Examined once (building child) * REQUESTED - on toBeMade list * BEINGMADE - Target is already being made. * Indicates a cycle in the graph. * MADE - Was out-of-date and has been made * UPTODATE - Was already up-to-date * ERROR - An error occurred while it was being * made (used only in compat mode) * ABORTED - The target was aborted due to * an error making an inferior (compat). */ int unmade; /* The number of unmade children */ time_t mtime; /* Its modification time */ struct GNode *cmgn; /* The youngest child */ Lst iParents; /* Links to parents for which this is an * implied source, if any */ Lst cohorts; /* Other nodes for the :: operator */ Lst parents; /* Nodes that depend on this one */ Lst children; /* Nodes on which this one depends */ Lst order_pred; /* .ORDER nodes we need made */ Lst order_succ; /* .ORDER nodes who need us */ char cohort_num[8]; /* #n for this cohort */ int unmade_cohorts;/* # of unmade instances on the cohorts list */ struct GNode *centurion; /* Pointer to the first instance of a :: node; only set when on a cohorts list */ unsigned int checked; /* Last time we tried to makle this node */ Hash_Table context; /* The local variables */ Lst commands; /* Creation commands */ struct _Suff *suffix; /* Suffix for the node (determined by * Suff_FindDeps and opaque to everyone * but the Suff module) */ const char *fname; /* filename where the GNode got defined */ int lineno; /* line number where the GNode got defined */ } GNode; /* * The OP_ constants are used when parsing a dependency line as a way of * communicating to other parts of the program the way in which a target * should be made. These constants are bitwise-OR'ed together and * placed in the 'type' field of each node. Any node that has * a 'type' field which satisfies the OP_NOP function was never never on * the lefthand side of an operator, though it may have been on the * righthand side... */ #define OP_DEPENDS 0x00000001 /* Execution of commands depends on * kids (:) */ #define OP_FORCE 0x00000002 /* Always execute commands (!) */ #define OP_DOUBLEDEP 0x00000004 /* Execution of commands depends on kids * per line (::) */ #define OP_OPMASK (OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP) #define OP_OPTIONAL 0x00000008 /* Don't care if the target doesn't * exist and can't be created */ #define OP_USE 0x00000010 /* Use associated commands for parents */ #define OP_EXEC 0x00000020 /* Target is never out of date, but always * execute commands anyway. Its time * doesn't matter, so it has none...sort * of */ #define OP_IGNORE 0x00000040 /* Ignore errors when creating the node */ #define OP_PRECIOUS 0x00000080 /* Don't remove the target when * interrupted */ #define OP_SILENT 0x00000100 /* Don't echo commands when executed */ #define OP_MAKE 0x00000200 /* Target is a recursive make so its * commands should always be executed when * it is out of date, regardless of the * state of the -n or -t flags */ #define OP_JOIN 0x00000400 /* Target is out-of-date only if any of its * children was out-of-date */ #define OP_MADE 0x00000800 /* Assume the children of the node have * been already made */ #define OP_SPECIAL 0x00001000 /* Special .BEGIN, .END, .INTERRUPT */ #define OP_USEBEFORE 0x00002000 /* Like .USE, only prepend commands */ #define OP_INVISIBLE 0x00004000 /* The node is invisible to its parents. * I.e. it doesn't show up in the parents's * local variables. */ #define OP_NOTMAIN 0x00008000 /* The node is exempt from normal 'main * target' processing in parse.c */ #define OP_PHONY 0x00010000 /* Not a file target; run always */ #define OP_NOPATH 0x00020000 /* Don't search for file in the path */ #define OP_WAIT 0x00040000 /* .WAIT phony node */ #define OP_NOMETA 0x00080000 /* .NOMETA do not create a .meta file */ #define OP_META 0x00100000 /* .META we _do_ want a .meta file */ #define OP_NOMETA_CMP 0x00200000 /* Do not compare commands in .meta file */ #define OP_SUBMAKE 0x00400000 /* Possibly a submake node */ /* Attributes applied by PMake */ #define OP_TRANSFORM 0x80000000 /* The node is a transformation rule */ #define OP_MEMBER 0x40000000 /* Target is a member of an archive */ #define OP_LIB 0x20000000 /* Target is a library */ #define OP_ARCHV 0x10000000 /* Target is an archive construct */ #define OP_HAS_COMMANDS 0x08000000 /* Target has all the commands it should. * Used when parsing to catch multiple * commands for a target */ #define OP_SAVE_CMDS 0x04000000 /* Saving commands on .END (Compat) */ #define OP_DEPS_FOUND 0x02000000 /* Already processed by Suff_FindDeps */ #define OP_MARK 0x01000000 /* Node found while expanding .ALLSRC */ #define NoExecute(gn) ((gn->type & OP_MAKE) ? noRecursiveExecute : noExecute) /* * OP_NOP will return TRUE if the node with the given type was not the * object of a dependency operator */ #define OP_NOP(t) (((t) & OP_OPMASK) == 0x00000000) #define OP_NOTARGET (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM) /* * The TARG_ constants are used when calling the Targ_FindNode and * Targ_FindList functions in targ.c. They simply tell the functions what to * do if the desired node(s) is (are) not found. If the TARG_CREATE constant * is given, a new, empty node will be created for the target, placed in the * table of all targets and its address returned. If TARG_NOCREATE is given, * a NULL pointer will be returned. */ #define TARG_NOCREATE 0x00 /* don't create it */ #define TARG_CREATE 0x01 /* create node if not found */ #define TARG_NOHASH 0x02 /* don't look in/add to hash table */ /* * These constants are all used by the Str_Concat function to decide how the * final string should look. If STR_ADDSPACE is given, a space will be * placed between the two strings. If STR_ADDSLASH is given, a '/' will * be used instead of a space. If neither is given, no intervening characters * will be placed between the two strings in the final output. If the * STR_DOFREE bit is set, the two input strings will be freed before * Str_Concat returns. */ #define STR_ADDSPACE 0x01 /* add a space when Str_Concat'ing */ #define STR_ADDSLASH 0x02 /* add a slash when Str_Concat'ing */ /* * Error levels for parsing. PARSE_FATAL means the process cannot continue * once the makefile has been parsed. PARSE_WARNING means it can. Passed * as the first argument to Parse_Error. */ #define PARSE_WARNING 2 #define PARSE_FATAL 1 /* * Values returned by Cond_Eval. */ #define COND_PARSE 0 /* Parse the next lines */ #define COND_SKIP 1 /* Skip the next lines */ #define COND_INVALID 2 /* Not a conditional statement */ /* * Definitions for the "local" variables. Used only for clarity. */ #define TARGET "@" /* Target of dependency */ #define OODATE "?" /* All out-of-date sources */ #define ALLSRC ">" /* All sources */ #define IMPSRC "<" /* Source implied by transformation */ #define PREFIX "*" /* Common prefix */ #define ARCHIVE "!" /* Archive in "archive(member)" syntax */ #define MEMBER "%" /* Member in "archive(member)" syntax */ #define FTARGET "@F" /* file part of TARGET */ #define DTARGET "@D" /* directory part of TARGET */ #define FIMPSRC " b) ? a : b) #endif /* At least GNU/Hurd systems lack hardcoded MAXPATHLEN/PATH_MAX */ #ifdef HAVE_LIMITS_H #include #endif #ifndef MAXPATHLEN #define MAXPATHLEN BMAKE_PATH_MAX #endif #ifndef PATH_MAX #define PATH_MAX MAXPATHLEN +#endif + +#if defined(SYSV) +#define KILLPG(pid, sig) kill(-(pid), (sig)) +#else +#define KILLPG(pid, sig) killpg((pid), (sig)) #endif #endif /* _MAKE_H_ */ Index: vendor/NetBSD/bmake/dist/nonints.h =================================================================== --- vendor/NetBSD/bmake/dist/nonints.h (revision 321401) +++ vendor/NetBSD/bmake/dist/nonints.h (revision 321402) @@ -1,200 +1,205 @@ /* $NetBSD: nonints.h,v 1.74 2016/09/05 00:40:29 sevan Exp $ */ /*- * Copyright (c) 1988, 1989, 1990, 1993 * 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. * * from: @(#)nonints.h 8.3 (Berkeley) 3/19/94 */ /*- * 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. * * from: @(#)nonints.h 8.3 (Berkeley) 3/19/94 */ /* arch.c */ ReturnStatus Arch_ParseArchive(char **, Lst, GNode *); void Arch_Touch(GNode *); void Arch_TouchLib(GNode *); time_t Arch_MTime(GNode *); time_t Arch_MemMTime(GNode *); void Arch_FindLib(GNode *, Lst); Boolean Arch_LibOODate(GNode *); void Arch_Init(void); void Arch_End(void); int Arch_IsLib(GNode *); /* compat.c */ int CompatRunCommand(void *, void *); void Compat_Run(Lst); int Compat_Make(void *, void *); /* cond.c */ struct If; int Cond_EvalExpression(const struct If *, char *, Boolean *, int, Boolean); int Cond_Eval(char *); void Cond_restore_depth(unsigned int); unsigned int Cond_save_depth(void); /* for.c */ int For_Eval(char *); int For_Accum(char *); void For_Run(int); /* job.c */ #ifdef WAIT_T void JobReapChild(pid_t, WAIT_T, Boolean); #endif /* main.c */ void Main_ParseArgLine(const char *); void MakeMode(const char *); char *Cmd_Exec(const char *, const char **); void Error(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2); void Fatal(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2) MAKE_ATTR_DEAD; void Punt(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2) MAKE_ATTR_DEAD; void DieHorribly(void) MAKE_ATTR_DEAD; int PrintAddr(void *, void *); void Finish(int) MAKE_ATTR_DEAD; int eunlink(const char *); void execError(const char *, const char *); char *getTmpdir(void); Boolean s2Boolean(const char *, Boolean); Boolean getBoolean(const char *, Boolean); char *cached_realpath(const char *, char *); /* parse.c */ void Parse_Error(int, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3); Boolean Parse_AnyExport(void); Boolean Parse_IsVar(char *); void Parse_DoVar(char *, GNode *); void Parse_AddIncludeDir(char *); void Parse_File(const char *, int); void Parse_Init(void); void Parse_End(void); void Parse_SetInput(const char *, int, int, char *(*)(void *, size_t *), void *); Lst Parse_MainName(void); /* str.c */ char *str_concat(const char *, const char *, int); char **brk_string(const char *, int *, Boolean, char **); char *Str_FindSubstring(const char *, const char *); int Str_Match(const char *, const char *); char *Str_SYSVMatch(const char *, const char *, int *len); void Str_SYSVSubst(Buffer *, char *, char *, int); +#ifndef HAVE_STRLCPY +/* strlcpy.c */ +size_t strlcpy(char *, const char *, size_t); +#endif + /* suff.c */ void Suff_ClearSuffixes(void); Boolean Suff_IsTransform(char *); GNode *Suff_AddTransform(char *); int Suff_EndTransform(void *, void *); void Suff_AddSuffix(char *, GNode **); Lst Suff_GetPath(char *); void Suff_DoPaths(void); void Suff_AddInclude(char *); void Suff_AddLib(char *); void Suff_FindDeps(GNode *); Lst Suff_FindPath(GNode *); void Suff_SetNull(char *); void Suff_Init(void); void Suff_End(void); void Suff_PrintAll(void); /* targ.c */ void Targ_Init(void); void Targ_End(void); Lst Targ_List(void); GNode *Targ_NewGN(const char *); GNode *Targ_FindNode(const char *, int); Lst Targ_FindList(Lst, int); Boolean Targ_Ignore(GNode *); Boolean Targ_Silent(GNode *); Boolean Targ_Precious(GNode *); void Targ_SetMain(GNode *); int Targ_PrintCmd(void *, void *); int Targ_PrintNode(void *, void *); char *Targ_FmtTime(time_t); void Targ_PrintType(int); void Targ_PrintGraph(int); void Targ_Propagate(void); void Targ_Propagate_Wait(void); /* var.c */ void Var_Delete(const char *, GNode *); void Var_Set(const char *, const char *, GNode *, int); void Var_Append(const char *, const char *, GNode *); Boolean Var_Exists(const char *, GNode *); char *Var_Value(const char *, GNode *, char **); char *Var_Parse(const char *, GNode *, int, int *, void **); char *Var_Subst(const char *, const char *, GNode *, int); char *Var_GetTail(const char *); char *Var_GetHead(const char *); void Var_Init(void); void Var_End(void); void Var_Dump(GNode *); void Var_ExportVars(void); void Var_Export(char *, int); void Var_UnExport(char *); /* util.c */ void (*bmake_signal(int, void (*)(int)))(int);