]> Zhao Yanbai Git Server - minix.git/commitdiff
Import NetBSD make
authorThomas Veerman <thomas@minix3.org>
Wed, 6 Jun 2012 14:24:31 +0000 (14:24 +0000)
committerThomas Veerman <thomas@minix3.org>
Mon, 18 Jun 2012 10:54:48 +0000 (10:54 +0000)
100 files changed:
commands/Makefile
commands/make/Makefile [deleted file]
commands/make/unit-tests/export-all [deleted file]
commands/make/unit-tests/modts [deleted file]
usr.bin/Makefile
usr.bin/make/Makefile [moved from commands/make/Makefile.netbsd with 59% similarity]
usr.bin/make/Makefile.bak [new file with mode: 0644]
usr.bin/make/Makefile.boot [moved from commands/make/Makefile.boot with 84% similarity]
usr.bin/make/PSD.doc/Makefile [moved from commands/make/PSD.doc/Makefile with 100% similarity]
usr.bin/make/PSD.doc/tutorial.ms [moved from commands/make/PSD.doc/tutorial.ms with 99% similarity]
usr.bin/make/arch.c [moved from commands/make/arch.c with 98% similarity]
usr.bin/make/buf.c [moved from commands/make/buf.c with 100% similarity]
usr.bin/make/buf.h [moved from commands/make/buf.h with 100% similarity]
usr.bin/make/compat.c [moved from commands/make/compat.c with 94% similarity]
usr.bin/make/cond.c [moved from commands/make/cond.c with 98% similarity]
usr.bin/make/config.h [moved from commands/make/config.h with 97% similarity]
usr.bin/make/dir.c [moved from commands/make/dir.c with 97% similarity]
usr.bin/make/dir.h [moved from commands/make/dir.h with 97% similarity]
usr.bin/make/for.c [moved from commands/make/for.c with 97% similarity]
usr.bin/make/hash.c [moved from commands/make/hash.c with 100% similarity]
usr.bin/make/hash.h [moved from commands/make/hash.h with 100% similarity]
usr.bin/make/job.c [moved from commands/make/job.c with 96% similarity]
usr.bin/make/job.h [moved from commands/make/job.h with 98% similarity]
usr.bin/make/lst.h [moved from commands/make/lst.h with 100% similarity]
usr.bin/make/lst.lib/Makefile [moved from commands/make/lst.lib/Makefile with 100% similarity]
usr.bin/make/lst.lib/lstAppend.c [moved from commands/make/lst.lib/lstAppend.c with 100% similarity]
usr.bin/make/lst.lib/lstAtEnd.c [moved from commands/make/lst.lib/lstAtEnd.c with 100% similarity]
usr.bin/make/lst.lib/lstAtFront.c [moved from commands/make/lst.lib/lstAtFront.c with 100% similarity]
usr.bin/make/lst.lib/lstClose.c [moved from commands/make/lst.lib/lstClose.c with 100% similarity]
usr.bin/make/lst.lib/lstConcat.c [moved from commands/make/lst.lib/lstConcat.c with 100% similarity]
usr.bin/make/lst.lib/lstDatum.c [moved from commands/make/lst.lib/lstDatum.c with 100% similarity]
usr.bin/make/lst.lib/lstDeQueue.c [moved from commands/make/lst.lib/lstDeQueue.c with 100% similarity]
usr.bin/make/lst.lib/lstDestroy.c [moved from commands/make/lst.lib/lstDestroy.c with 100% similarity]
usr.bin/make/lst.lib/lstDupl.c [moved from commands/make/lst.lib/lstDupl.c with 100% similarity]
usr.bin/make/lst.lib/lstEnQueue.c [moved from commands/make/lst.lib/lstEnQueue.c with 100% similarity]
usr.bin/make/lst.lib/lstFind.c [moved from commands/make/lst.lib/lstFind.c with 100% similarity]
usr.bin/make/lst.lib/lstFindFrom.c [moved from commands/make/lst.lib/lstFindFrom.c with 100% similarity]
usr.bin/make/lst.lib/lstFirst.c [moved from commands/make/lst.lib/lstFirst.c with 100% similarity]
usr.bin/make/lst.lib/lstForEach.c [moved from commands/make/lst.lib/lstForEach.c with 100% similarity]
usr.bin/make/lst.lib/lstForEachFrom.c [moved from commands/make/lst.lib/lstForEachFrom.c with 100% similarity]
usr.bin/make/lst.lib/lstInit.c [moved from commands/make/lst.lib/lstInit.c with 100% similarity]
usr.bin/make/lst.lib/lstInsert.c [moved from commands/make/lst.lib/lstInsert.c with 100% similarity]
usr.bin/make/lst.lib/lstInt.h [moved from commands/make/lst.lib/lstInt.h with 100% similarity]
usr.bin/make/lst.lib/lstIsAtEnd.c [moved from commands/make/lst.lib/lstIsAtEnd.c with 100% similarity]
usr.bin/make/lst.lib/lstIsEmpty.c [moved from commands/make/lst.lib/lstIsEmpty.c with 100% similarity]
usr.bin/make/lst.lib/lstLast.c [moved from commands/make/lst.lib/lstLast.c with 100% similarity]
usr.bin/make/lst.lib/lstMember.c [moved from commands/make/lst.lib/lstMember.c with 100% similarity]
usr.bin/make/lst.lib/lstNext.c [moved from commands/make/lst.lib/lstNext.c with 100% similarity]
usr.bin/make/lst.lib/lstOpen.c [moved from commands/make/lst.lib/lstOpen.c with 100% similarity]
usr.bin/make/lst.lib/lstPrev.c [moved from commands/make/lst.lib/lstPrev.c with 100% similarity]
usr.bin/make/lst.lib/lstRemove.c [moved from commands/make/lst.lib/lstRemove.c with 100% similarity]
usr.bin/make/lst.lib/lstReplace.c [moved from commands/make/lst.lib/lstReplace.c with 100% similarity]
usr.bin/make/lst.lib/lstSucc.c [moved from commands/make/lst.lib/lstSucc.c with 100% similarity]
usr.bin/make/main.c [moved from commands/make/main.c with 98% similarity]
usr.bin/make/make.1 [moved from commands/make/make.1 with 91% similarity]
usr.bin/make/make.c [moved from commands/make/make.c with 97% similarity]
usr.bin/make/make.h [moved from commands/make/make.h with 97% similarity]
usr.bin/make/make_malloc.c [moved from commands/make/make_malloc.c with 92% similarity]
usr.bin/make/make_malloc.h [moved from commands/make/make_malloc.h with 100% similarity]
usr.bin/make/meta.c [new file with mode: 0644]
usr.bin/make/meta.h [new file with mode: 0644]
usr.bin/make/nonints.h [moved from commands/make/nonints.h with 96% similarity]
usr.bin/make/parse.c [moved from commands/make/parse.c with 87% similarity]
usr.bin/make/pathnames.h [moved from commands/make/pathnames.h with 100% similarity]
usr.bin/make/sprite.h [moved from commands/make/sprite.h with 100% similarity]
usr.bin/make/str.c [moved from commands/make/str.c with 97% similarity]
usr.bin/make/strlist.c [moved from commands/make/strlist.c with 100% similarity]
usr.bin/make/strlist.h [moved from commands/make/strlist.h with 100% similarity]
usr.bin/make/suff.c [moved from commands/make/suff.c with 99% similarity]
usr.bin/make/targ.c [moved from commands/make/targ.c with 98% similarity]
usr.bin/make/trace.c [moved from commands/make/trace.c with 94% similarity]
usr.bin/make/trace.h [moved from commands/make/trace.h with 100% similarity]
usr.bin/make/unit-tests/Makefile [moved from commands/make/unit-tests/Makefile with 83% similarity]
usr.bin/make/unit-tests/comment [moved from commands/make/unit-tests/comment with 100% similarity]
usr.bin/make/unit-tests/cond1 [moved from commands/make/unit-tests/cond1 with 92% similarity]
usr.bin/make/unit-tests/doterror [new file with mode: 0644]
usr.bin/make/unit-tests/dotwait [moved from commands/make/unit-tests/dotwait with 100% similarity]
usr.bin/make/unit-tests/error [new file with mode: 0644]
usr.bin/make/unit-tests/export [moved from commands/make/unit-tests/export with 100% similarity]
usr.bin/make/unit-tests/export-all [new file with mode: 0644]
usr.bin/make/unit-tests/forsubst [moved from commands/make/unit-tests/forsubst with 100% similarity]
usr.bin/make/unit-tests/hash [new file with mode: 0644]
usr.bin/make/unit-tests/misc [new file with mode: 0644]
usr.bin/make/unit-tests/moderrs [moved from commands/make/unit-tests/moderrs with 100% similarity]
usr.bin/make/unit-tests/modmatch [moved from commands/make/unit-tests/modmatch with 100% similarity]
usr.bin/make/unit-tests/modmisc [moved from commands/make/unit-tests/modmisc with 74% similarity]
usr.bin/make/unit-tests/modorder [moved from commands/make/unit-tests/modorder with 100% similarity]
usr.bin/make/unit-tests/modts [new file with mode: 0644]
usr.bin/make/unit-tests/modword [moved from commands/make/unit-tests/modword with 100% similarity]
usr.bin/make/unit-tests/phony-end [new file with mode: 0644]
usr.bin/make/unit-tests/posix [moved from commands/make/unit-tests/posix with 100% similarity]
usr.bin/make/unit-tests/qequals [moved from commands/make/unit-tests/qequals with 100% similarity]
usr.bin/make/unit-tests/sysv [new file with mode: 0644]
usr.bin/make/unit-tests/ternary [moved from commands/make/unit-tests/ternary with 100% similarity]
usr.bin/make/unit-tests/test.exp [moved from commands/make/unit-tests/test.exp with 89% similarity]
usr.bin/make/unit-tests/unexport [moved from commands/make/unit-tests/unexport with 100% similarity]
usr.bin/make/unit-tests/unexport-env [moved from commands/make/unit-tests/unexport-env with 100% similarity]
usr.bin/make/unit-tests/varcmd [moved from commands/make/unit-tests/varcmd with 100% similarity]
usr.bin/make/util.c [moved from commands/make/util.c with 97% similarity]
usr.bin/make/var.c [moved from commands/make/var.c with 96% similarity]

index 5e80f2179c416c6547bad639bb7fea57c160def3..a52473970e73f1e684fbdebd9be7091a20dfc196 100644 (file)
@@ -16,7 +16,7 @@ SUBDIR=       add_route arp ash at \
        hostaddr id ifconfig ifdef install \
        intr ipcrm ipcs irdpd isoread join kill last \
        less loadkeys loadramdisk logger look lp \
-       lpd ls lspci mail make  MAKEDEV \
+       lpd ls lspci mail MAKEDEV \
        mdb  mesg mined mkfifo mkfs.mfs mknod \
        mkproto mount mt netconf nice acknm nohup \
        nonamed od paste patch pax \
diff --git a/commands/make/Makefile b/commands/make/Makefile
deleted file mode 100644 (file)
index bc7fd63..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#      $NetBSD: Makefile,v 1.50 2010/04/22 19:15:23 sjg Exp $
-#      @(#)Makefile    5.2 (Berkeley) 12/28/90
-
-PROG=  make
-SRCS=  arch.c buf.c compat.c cond.c dir.c for.c hash.c job.c main.c \
-       make.c parse.c str.c suff.c targ.c trace.c var.c util.c
-SRCS+=  strlist.c
-SRCS+=  make_malloc.c
-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 lstRemove.c lstReplace.c lstSucc.c
-SRCS+= lstPrev.c
-
-
-# For MINIX
-CPPFLAGS+=     -DHAVE_SETENV -DHAVE_STRERROR -DHAVE_STRDUP \
-               -DHAVE_STRFTIME -DHAVE_VSNPRINTF -DUSE_SELECT
-MACHINE=${ARCH}
-MACHINE_ARCH=${ARCH}
-CPPFLAGS+= -DTARGET_MACHINE=\"${MACHINE}\" \
-       -DTARGET_MACHINE_ARCH=\"${MACHINE_ARCH}\" \
-       -DMAKE_MACHINE=\"${MACHINE}\" \
-       -DMAKE_MACHINE_ARCH=\"${MACHINE_ARCH}\"
-
-
- .PATH:        ${.CURDIR}/lst.lib
-
-# .if make(obj) || make(clean)
-# SUBDIR+= unit-tests
-# .endif
-
-.include <bsd.prog.mk>
-.include <bsd.subdir.mk>
-
-# A simple unit-test driver to help catch regressions
-accept test:
-       cd ${.CURDIR}/unit-tests && ${.MAKE} -r -m / TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET}
diff --git a/commands/make/unit-tests/export-all b/commands/make/unit-tests/export-all
deleted file mode 100644 (file)
index 0542937..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# $Id: export-all,v 1.1 2007/10/05 15:27:46 sjg Exp $
-
-UT_OK=good
-UT_F=fine
-
-.export
-
-.include "export"
-
-UT_TEST=export-all
-UT_ALL=even this gets exported
diff --git a/commands/make/unit-tests/modts b/commands/make/unit-tests/modts
deleted file mode 100644 (file)
index d0efd6d..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-
-LIST= one two three
-LIST+= four five six
-
-FU_mod-ts = a / b / cool
-
-AAA= a a a
-B.aaa= Baaa
-
-all:   mod-ts
-
-mod-ts:
-       @echo 'LIST="${LIST}"'
-       @echo 'LIST:ts,="${LIST:ts,}"'
-       @echo 'LIST:ts/:tu="${LIST:ts/:tu}"'
-       @echo 'LIST:ts::tu="${LIST:ts::tu}"'
-       @echo 'LIST:ts:tu="${LIST:ts:tu}"'
-       @echo 'LIST:tu:ts/="${LIST:tu:ts/}"'
-       @echo 'LIST:ts:="${LIST:ts:}"'
-       @echo 'LIST:ts="${LIST:ts}"'
-       @echo 'LIST:ts:S/two/2/="${LIST:ts:S/two/2/}"'
-       @echo 'LIST:S/two/2/:ts="${LIST:S/two/2/:ts}"'
-       @echo 'LIST:ts/:S/two/2/="${LIST:ts/:S/two/2/}"'
-       @echo "Pretend the '/' in '/n' etc. below are back-slashes."
-       @echo 'LIST:ts/n="${LIST:ts\n}"'
-       @echo 'LIST:ts/t="${LIST:ts\t}"'
-       @echo 'LIST:ts/012:tu="${LIST:ts\012:tu}"'
-       @echo 'LIST:tx="${LIST:tx}"'
-       @echo 'LIST:ts/x:tu="${LIST:ts\x:tu}"'
-       @echo 'FU_$@="${FU_${@:ts}:ts}"'
-       @echo 'FU_$@:ts:T="${FU_${@:ts}:ts:T}" == cool?'
-       @echo 'B.$${AAA:ts}="${B.${AAA:ts}}" == Baaa?'
index d608224d50e15a5eee60359fd5e4f4f7d1f821a6..468adfc79611b4969857c480dd5b3e6a922ab07b 100644 (file)
@@ -3,7 +3,7 @@
 .include <bsd.own.mk>
 
 # NetBSD imports
-SUBDIR= login indent m4 stat tic sed mkdep uniq seq du man \
+SUBDIR= login indent m4 make stat tic sed mkdep uniq seq du man \
        apropos chpass newgrp passwd bzip2 bzip2recover gzip su genassym \
        ldd/elf32 .WAIT ldd
 
similarity index 59%
rename from commands/make/Makefile.netbsd
rename to usr.bin/make/Makefile
index acbe83aa7c800159bf73b9f835ad13a3b96f780a..bcfd975e85842e49bbde6d44df31659bbca7fa78 100644 (file)
@@ -1,4 +1,4 @@
-#      $NetBSD: Makefile,v 1.50 2010/04/22 19:15:23 sjg Exp $
+#      $NetBSD: Makefile,v 1.55 2011/08/14 13:06:09 christos Exp $
 #      @(#)Makefile    5.2 (Berkeley) 12/28/90
 
 PROG=  make
@@ -13,10 +13,28 @@ SRCS+=      lstAppend.c lstAtEnd.c lstAtFront.c lstClose.c lstConcat.c \
        lstMember.c lstNext.c lstOpen.c lstRemove.c lstReplace.c lstSucc.c
 SRCS += lstPrev.c
 
-.PATH: ${.CURDIR}/lst.lib
-.if make(install)
-SUBDIR=        PSD.doc
+# let people experiment for a bit
+USE_META ?= no
+.if ${USE_META:tl} != "no"
+SRCS+= meta.c
+CPPFLAGS+= -DUSE_META
+FILEMON_H ?= ${.CURDIR:H:H}/sys/dev/filemon/filemon.h
+.if exists(${FILEMON_H}) && ${FILEMON_H:T} == "filemon.h"
+COPTS.meta.c += -DHAVE_FILEMON_H -I${FILEMON_H:H}
+.endif
 .endif
+
+# For MINIX
+CPPFLAGS+=     -DHAVE_SETENV -DHAVE_STRERROR -DHAVE_STRDUP \
+               -DHAVE_STRFTIME -DHAVE_VSNPRINTF -DUSE_SELECT
+
+CPPFLAGS+= -DMAKE_MACHINE=\"${MACHINE}\" -DMAKE_MACHINE_ARCH=\"${MACHINE_ARCH}\"
+
+
+.PATH: ${.CURDIR}/lst.lib
+#.if make(install)
+#SUBDIR=       PSD.doc
+#.endif
 .if make(obj) || make(clean)
 SUBDIR+= unit-tests
 .endif
@@ -24,10 +42,13 @@ SUBDIR+= unit-tests
 .include <bsd.prog.mk>
 .include <bsd.subdir.mk>
 
+.ifdef TOOLDIR
 CPPFLAGS+= -DMAKE_NATIVE
-COPTS.var.c+= -Wno-cast-qual
+COPTS.var.c += -Wno-cast-qual
+COPTS.job.c += -Wno-format-nonliteral
+COPTS.parse.c += -Wno-format-nonliteral
+COPTS.var.c += -Wno-format-nonliteral
 
-.ifdef TOOLDIR
 # this is a native netbsd build, 
 # use libutil rather than the local emalloc etc.
 CPPFLAGS+= -DUSE_EMALLOC
diff --git a/usr.bin/make/Makefile.bak b/usr.bin/make/Makefile.bak
new file mode 100644 (file)
index 0000000..fe2f613
--- /dev/null
@@ -0,0 +1,71 @@
+#      $NetBSD: Makefile,v 1.55 2011/08/14 13:06:09 christos Exp $
+#      @(#)Makefile    5.2 (Berkeley) 12/28/90
+
+PROG=  make
+SRCS=  arch.c buf.c compat.c cond.c dir.c for.c hash.c job.c main.c \
+       make.c parse.c str.c suff.c targ.c trace.c var.c util.c 
+SRCS+=  strlist.c
+SRCS+=  make_malloc.c
+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 lstRemove.c lstReplace.c lstSucc.c
+SRCS += lstPrev.c
+
+# let people experiment for a bit
+USE_META ?= no
+.if ${USE_META:tl} != "no"
+SRCS+= meta.c
+CPPFLAGS+= -DUSE_META
+FILEMON_H ?= ${.CURDIR:H:H}/sys/dev/filemon/filemon.h
+.if exists(${FILEMON_H}) && ${FILEMON_H:T} == "filemon.h"
+COPTS.meta.c += -DHAVE_FILEMON_H -I${FILEMON_H:H}
+.endif
+.endif
+
+# For MINIX
+CPPFLAGS+=     -DHAVE_SETENV -DHAVE_STRERROR -DHAVE_STRDUP \
+               -DHAVE_STRFTIME -DHAVE_VSNPRINTF -DUSE_SELECT
+
+# Gross hack, but we assume i386 everywhere
+.if ${MACHINE_ARCH} == "i686"
+MACHINE_ARCH=i386
+.endif
+.if $(MACHINE) == "i686"
+MACHINE=i386
+.endif
+CPPFLAGS+= -DTARGET_MACHINE=\"${MACHINE}\" \
+               -DTARGET_MACHINE_ARCH=\"${MACHINE_ARCH}\" \
+               -DMAKE_MACHINE=\"${MACHINE}\" \
+               -DMAKE_MACHINE_ARCH=\"${MACHINE_ARCH}\"
+
+
+.PATH: ${.CURDIR}/lst.lib
+.if make(install)
+SUBDIR=        PSD.doc
+.endif
+.if make(obj) || make(clean)
+SUBDIR+= unit-tests
+.endif
+
+.include <bsd.prog.mk>
+.include <bsd.subdir.mk>
+
+.ifdef TOOLDIR
+CPPFLAGS+= -DMAKE_NATIVE
+COPTS.var.c += -Wno-cast-qual
+COPTS.job.c += -Wno-format-nonliteral
+COPTS.parse.c += -Wno-format-nonliteral
+COPTS.var.c += -Wno-format-nonliteral
+
+# this is a native netbsd build, 
+# use libutil rather than the local emalloc etc.
+CPPFLAGS+= -DUSE_EMALLOC
+LDADD+=-lutil
+DPADD+=${LIBUTIL}
+.endif
+
+# A simple unit-test driver to help catch regressions
+accept test:
+       cd ${.CURDIR}/unit-tests && ${.MAKE} -r -m / TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET}
similarity index 84%
rename from commands/make/Makefile.boot
rename to usr.bin/make/Makefile.boot
index f6c2bb0717853e1b21b3d4ab157a91e24391cb9f..953dba6a664c747a7153acfd5226baf87891d19a 100644 (file)
@@ -1,4 +1,4 @@
-#      $NetBSD: Makefile.boot,v 1.19 2009/01/24 11:59:39 dsl Exp $
+#      $NetBSD: Makefile.boot,v 1.20 2011/03/26 21:42:12 dholland Exp $
 #
 # a very simple makefile...
 #
@@ -6,9 +6,7 @@
 #
 # modify MACHINE and MACHINE_ARCH as appropriate for your target architecture
 #
-#CC=gcc -O -g
-CC=cc
-CFLAGS=-g -Wall -DHAVE_SETENV -DHAVE_STRERROR -DHAVE_STRDUP -DHAVE_STRFTIME -DHAVE_VSNPRINTF -DUSE_SELECT -D_POSIX_SOURCE
+CC=gcc -O -g
 
 .c.o:
        ${CC} ${CFLAGS} -c $< -o $@
@@ -18,7 +16,7 @@ MACHINE_ARCH=i386
 # tested on HP-UX 10.20
 #MAKE_MACHINE=hp700
 #MAKE_MACHINE_ARCH=hppa
-CFLAGS+= -DTARGET_MACHINE=\"${MACHINE}\" \
+CFLAGS= -DTARGET_MACHINE=\"${MACHINE}\" \
        -DTARGET_MACHINE_ARCH=\"${MACHINE_ARCH}\" \
        -DMAKE_MACHINE=\"${MACHINE}\"
 LIBS=
similarity index 99%
rename from commands/make/PSD.doc/tutorial.ms
rename to usr.bin/make/PSD.doc/tutorial.ms
index 9802e4b40238bdbf33ac8371283913a66018d81c..c1a6444d48c684e46fb275fe66b707b145a60697 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $NetBSD: tutorial.ms,v 1.10 2004/06/27 19:12:33 uwe Exp $
+.\"    $NetBSD: tutorial.ms,v 1.11 2011/08/18 15:19:30 sjg Exp $
 .\" Copyright (c) 1988, 1989, 1993
 .\"    The Regents of the University of California.  All rights reserved.
 .\"
 .nr g4 \\n(.s
 .sp -1
 .\" .st cf
-\D's -1u'\D't 5u'
+\D't 5u'
 .sp -1
-\h'50u'\D'l 71u 0u'\D'l 50u 50u'\D'l 0u 71u'\D'l -50u 50u'\D'l -71u 0u'\D'l -50u -50u'\D'l 0u -71u'\D'l 50u -50u'
+\h'50u'
 .sp -1
 \D't 3u'
 .sp -1
 .sp 7u
-\h'53u'\D'p 14 68u 0u 46u 46u 0u 68u -46u 46u -68u 0u -47u -46u 0u -68u 47u -46u'
+\h'53u'
+\d\D'p -0.19i 0.0i 0.0i -0.13i 0.30i 0.0i 0.0i 0.13i'
 .sp -1
 .ft R
 .ps 6
 \h'85u'\v'0.85n'\h\a-\w\a\\*(g9\au/2u\a\&\\*(g9
 .sp |\\n(g8u
 .sp 166u
-\D't 3u'\D's -1u'
+\D't 3u'
 .br
 .po
 .rt 
similarity index 98%
rename from commands/make/arch.c
rename to usr.bin/make/arch.c
index 263a4470dfce359617aedb63425cd241907514d7..650aaec7ea98bb55a8e2384aa18bf44b1855bc37 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: arch.c,v 1.59 2009/01/23 21:58:27 dsl Exp $    */
+/*     $NetBSD: arch.c,v 1.62 2010/11/27 16:00:09 christos Exp $       */
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: arch.c,v 1.59 2009/01/23 21:58:27 dsl Exp $";
+static char rcsid[] = "$NetBSD: arch.c,v 1.62 2010/11/27 16:00:09 christos Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)arch.c     8.2 (Berkeley) 1/2/94";
 #else
-__RCSID("$NetBSD: arch.c,v 1.59 2009/01/23 21:58:27 dsl Exp $");
+__RCSID("$NetBSD: arch.c,v 1.62 2010/11/27 16:00:09 christos Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -1212,7 +1212,7 @@ Arch_FindLib(GNode *gn, Lst path)
  *     A library will be considered out-of-date for any of these reasons,
  *     given that it is a target on a dependency line somewhere:
  *         Its modification time is less than that of one of its
- *               sources (gn->mtime < gn->cmtime).
+ *               sources (gn->mtime < gn->cmgn->mtime).
  *         Its modification time is greater than the time at which the
  *               make began (i.e. it's been modified in the course
  *               of the make, probably by archiving).
@@ -1245,8 +1245,9 @@ Arch_LibOODate(GNode *gn)
        oodate = TRUE;
     } else if (OP_NOP(gn->type) && Lst_IsEmpty(gn->children)) {
        oodate = FALSE;
-    } else if ((!Lst_IsEmpty(gn->children) && gn->cmtime == 0) ||
-              (gn->mtime > now) || (gn->mtime < gn->cmtime)) {
+    } else if ((!Lst_IsEmpty(gn->children) && gn->cmgn == NULL) ||
+              (gn->mtime > now) ||
+              (gn->cmgn != NULL && gn->mtime < gn->cmgn->mtime)) {
        oodate = TRUE;
     } else {
 #ifdef RANLIBMAG
@@ -1261,7 +1262,7 @@ Arch_LibOODate(GNode *gn)
            if (DEBUG(ARCH) || DEBUG(MAKE)) {
                fprintf(debug_file, "%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC));
            }
-           oodate = (gn->cmtime > modTimeTOC);
+           oodate = (gn->cmgn == NULL || gn->cmgn->mtime > modTimeTOC);
        } else {
            /*
             * A library w/o a table of contents is out-of-date
similarity index 100%
rename from commands/make/buf.c
rename to usr.bin/make/buf.c
similarity index 100%
rename from commands/make/buf.h
rename to usr.bin/make/buf.h
similarity index 94%
rename from commands/make/compat.c
rename to usr.bin/make/compat.c
index 054cfd75e9b60e7cdc161c623c4eb0908d63d3de..099ba39c8d394240768a8c6d0a897c1585348fd2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: compat.c,v 1.79 2010/06/03 15:40:15 sjg Exp $  */
+/*     $NetBSD: compat.c,v 1.84 2011/09/16 15:38:03 joerg Exp $        */
 
 /*
  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: compat.c,v 1.79 2010/06/03 15:40:15 sjg Exp $";
+static char rcsid[] = "$NetBSD: compat.c,v 1.84 2011/09/16 15:38:03 joerg Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)compat.c   8.2 (Berkeley) 3/19/94";
 #else
-__RCSID("$NetBSD: compat.c,v 1.79 2010/06/03 15:40:15 sjg Exp $");
+__RCSID("$NetBSD: compat.c,v 1.84 2011/09/16 15:38:03 joerg Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -121,7 +121,7 @@ static char             meta[256];
 
 static GNode       *curTarg = NULL;
 static GNode       *ENDNode;
-static void CompatInterrupt(int);
+static void CompatInterrupt(int) __dead;
 
 static void
 Compat_Init(void)
@@ -347,11 +347,17 @@ again:
                useShell = 1;
                goto again;
        }
-       av = (const char **)mav;
+       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.
      */
@@ -362,6 +368,11 @@ again:
     if (cpid == 0) {
        Check_Cwd(av);
        Var_ExportVars();
+#ifdef USE_META
+       if (useMeta) {
+           meta_compat_child();
+       }
+#endif
        if (local)
            (void)execvp(av[0], (char *const *)UNCONST(av));
        else
@@ -375,12 +386,20 @@ again:
        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;
            }
@@ -391,6 +410,11 @@ again:
                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: ",
@@ -417,6 +441,11 @@ again:
 
            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) {
                        /*
@@ -498,10 +527,10 @@ Compat_Make(void *gnp, void *pgnp)
        }
 
        /*
-        * All the children were made ok. Now cmtime 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.
+        * 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);
@@ -549,6 +578,11 @@ Compat_Make(void *gnp, void *pgnp)
             */
            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 {
@@ -557,6 +591,11 @@ Compat_Make(void *gnp, void *pgnp)
        } else {
            gn->made = ERROR;
        }
+#ifdef USE_META
+       if (useMeta && !NoExecute(gn)) {
+           meta_job_finish(NULL);
+       }
+#endif
 
        if (gn->made != ERROR) {
            /*
similarity index 98%
rename from commands/make/cond.c
rename to usr.bin/make/cond.c
index 3292f19ebbb301e77534de04df55ca79f743f73a..24db629c0694224f402fd948e2646ed90a5909b8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: cond.c,v 1.60 2009/11/06 19:44:06 dsl Exp $    */
+/*     $NetBSD: cond.c,v 1.62 2011/03/29 17:19:22 sjg Exp $    */
 
 /*
  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: cond.c,v 1.60 2009/11/06 19:44:06 dsl Exp $";
+static char rcsid[] = "$NetBSD: cond.c,v 1.62 2011/03/29 17:19:22 sjg Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)cond.c     8.2 (Berkeley) 1/2/94";
 #else
-__RCSID("$NetBSD: cond.c,v 1.60 2009/11/06 19:44:06 dsl Exp $");
+__RCSID("$NetBSD: cond.c,v 1.62 2011/03/29 17:19:22 sjg Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -327,7 +327,7 @@ CondGetArg(char **linePtr, char **argPtr, const char *func)
  *-----------------------------------------------------------------------
  */
 static Boolean
-CondDoDefined(int argLen, const char *arg)
+CondDoDefined(int argLen __unused, const char *arg)
 {
     char    *p1;
     Boolean result;
@@ -376,7 +376,7 @@ CondStrMatch(const void *string, const void *pattern)
  *-----------------------------------------------------------------------
  */
 static Boolean
-CondDoMake(int argLen, const char *arg)
+CondDoMake(int argLen __unused, const char *arg)
 {
     return Lst_Find(create, arg, CondStrMatch) != NULL;
 }
@@ -395,22 +395,22 @@ CondDoMake(int argLen, const char *arg)
  *-----------------------------------------------------------------------
  */
 static Boolean
-CondDoExists(int argLen, const char *arg)
+CondDoExists(int argLen __unused, const char *arg)
 {
     Boolean result;
     char    *path;
 
     path = Dir_FindFile(arg, dirSearchPath);
+    if (DEBUG(COND)) {
+       fprintf(debug_file, "exists(%s) result is \"%s\"\n",
+              arg, path ? path : "");
+    }    
     if (path != NULL) {
        result = TRUE;
        free(path);
     } else {
        result = FALSE;
     }
-    if (DEBUG(COND)) {
-       fprintf(debug_file, "exists(%s) result is \"%s\"\n",
-              arg, path ? path : "");
-    }    
     return (result);
 }
 \f
@@ -428,7 +428,7 @@ CondDoExists(int argLen, const char *arg)
  *-----------------------------------------------------------------------
  */
 static Boolean
-CondDoTarget(int argLen, const char *arg)
+CondDoTarget(int argLen __unused, const char *arg)
 {
     GNode   *gn;
 
@@ -452,7 +452,7 @@ CondDoTarget(int argLen, const char *arg)
  *-----------------------------------------------------------------------
  */
 static Boolean
-CondDoCommands(int argLen, const char *arg)
+CondDoCommands(int argLen __unused, const char *arg)
 {
     GNode   *gn;
 
@@ -790,7 +790,7 @@ done:
 }
 
 static int
-get_mpt_arg(char **linePtr, char **argPtr, const char *func)
+get_mpt_arg(char **linePtr, char **argPtr, const char *func __unused)
 {
     /*
      * Use Var_Parse to parse the spec in parens and return
@@ -831,7 +831,7 @@ get_mpt_arg(char **linePtr, char **argPtr, const char *func)
 }
 
 static Boolean
-CondDoEmpty(int arglen, const char *arg)
+CondDoEmpty(int arglen, const char *arg __unused)
 {
     return arglen == 1;
 }
similarity index 97%
rename from commands/make/config.h
rename to usr.bin/make/config.h
index 7ff999572641bc6d7a9083990693e8f619f27aaf..06af09c2d85aeb6f831154da4a25e6f22d43a304 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: config.h,v 1.20 2007/10/14 20:22:53 apb Exp $  */
+/*     $NetBSD: config.h,v 1.21 2012/03/31 00:12:24 christos Exp $     */
 
 /*
  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
 #define SYSVINCLUDE
 #define SYSVVARSUB
 
+/*
+ * GMAKEEXPORT
+ *     Recognize gmake like variable export directives [export <VAR>=<VALUE>]
+ */
+#define GMAKEEXPORT
+
 /*
  * SUNSHCMD
  *     Recognize SunOS and Solaris:
similarity index 97%
rename from commands/make/dir.c
rename to usr.bin/make/dir.c
index 7863d490c0ef0cb3c5b7655bb72e63dd14807992..6560f30d05bd09ed936ea77ad8c2a07acaac360e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: dir.c,v 1.61 2009/01/24 10:59:09 dsl Exp $     */
+/*     $NetBSD: dir.c,v 1.64 2012/04/07 18:29:08 christos Exp $        */
 
 /*
  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: dir.c,v 1.61 2009/01/24 10:59:09 dsl Exp $";
+static char rcsid[] = "$NetBSD: dir.c,v 1.64 2012/04/07 18:29:08 christos Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)dir.c      8.2 (Berkeley) 1/2/94";
 #else
-__RCSID("$NetBSD: dir.c,v 1.61 2009/01/24 10:59:09 dsl Exp $");
+__RCSID("$NetBSD: dir.c,v 1.64 2012/04/07 18:29:08 christos Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -1061,6 +1061,7 @@ Dir_FindFile(const char *name, Lst path)
     Boolean      hasSlash;             /* true if 'name' contains a / */
     struct stat          stb;                  /* Buffer for stat, if necessary */
     Hash_Entry   *entry;               /* Entry for mtimes table */
+    const char   *trailing_dot = ".";
 
     /*
      * Find the final component of the name and note whether it has a
@@ -1165,6 +1166,11 @@ Dir_FindFile(const char *name, Lst path)
        return NULL;
     }
 
+    if (*cp == '\0') {
+       /* we were given a trailing "/" */
+       cp = trailing_dot;
+    }
+
     if (name[0] != '/') {
        Boolean checkedDot = FALSE;
 
@@ -1272,6 +1278,10 @@ Dir_FindFile(const char *name, Lst path)
      * b/c we added it here. This is not good...
      */
 #ifdef notdef
+    if (cp == traling_dot) {
+       cp = strrchr(name, '/');
+       cp += 1;
+    }
     cp[-1] = '\0';
     (void)Dir_AddDir(path, name);
     cp[-1] = '/';
@@ -1418,7 +1428,7 @@ Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen) {
  *-----------------------------------------------------------------------
  */
 int
-Dir_MTime(GNode *gn)
+Dir_MTime(GNode *gn, Boolean recheck)
 {
     char          *fullName;  /* the full pathname of name */
     struct stat          stb;        /* buffer for finding the mod time */
@@ -1434,6 +1444,31 @@ Dir_MTime(GNode *gn)
            fullName = NULL;
        else {
            fullName = Dir_FindFile(gn->name, Suff_FindPath(gn));
+           if (fullName == NULL && gn->flags & FROM_DEPEND &&
+               !Lst_IsEmpty(gn->iParents)) {
+               char *cp;
+
+               cp = strrchr(gn->name, '/');
+               if (cp) {
+                   /*
+                    * This is an implied source, and it may have moved,
+                    * see if we can find it via the current .PATH
+                    */
+                   cp++;
+                       
+                   fullName = Dir_FindFile(cp, Suff_FindPath(gn));
+                   if (fullName) {
+                       /*
+                        * Put the found file in gn->path
+                        * so that we give that to the compiler.
+                        */
+                       gn->path = bmake_strdup(fullName);
+                       fprintf(stdout,
+                               "%s: ignoring stale %s for %s, found %s\n",
+                               progname, makeDependfile, gn->name, fullName);
+                   }
+               }
+           }
            if (DEBUG(DIR))
                fprintf(debug_file, "Found '%s' as '%s'\n",
                        gn->name, fullName ? fullName : "(not found)" );
@@ -1446,19 +1481,16 @@ Dir_MTime(GNode *gn)
        fullName = bmake_strdup(gn->name);
     }
 
-    entry = Hash_FindEntry(&mtimes, fullName);
+    if (!recheck)
+       entry = Hash_FindEntry(&mtimes, fullName);
+    else
+       entry = NULL;
     if (entry != NULL) {
-       /*
-        * Only do this once -- the second time folks are checking to
-        * see if the file was actually updated, so we need to actually go
-        * to the file system.
-        */
        if (DEBUG(DIR)) {
            fprintf(debug_file, "Using cached time %s for %s\n",
                    Targ_FmtTime(Hash_GetTimeValue(entry)), fullName);
        }
        stb.st_mtime = Hash_GetTimeValue(entry);
-       Hash_DeleteEntry(&mtimes, entry);
     } else if (stat(fullName, &stb) < 0) {
        if (gn->type & OP_MEMBER) {
            if (fullName != gn->path)
@@ -1467,12 +1499,16 @@ Dir_MTime(GNode *gn)
        } else {
            stb.st_mtime = 0;
        }
-    } else if (stb.st_mtime == 0) {
-       /*
-        * 0 handled specially by the code, if the time is really 0, return
-        * something else instead
-        */
-       stb.st_mtime = 1;
+    } else {
+       if (stb.st_mtime == 0) {
+               /*
+                * 0 handled specially by the code, if the time is really 0,
+                * return something else instead
+                */
+               stb.st_mtime = 1;
+       }
+       entry = Hash_CreateEntry(&mtimes, fullName, NULL);
+       Hash_SetTimeValue(entry, stb.st_mtime);
     }
        
     if (fullName && gn->path == NULL) {
similarity index 97%
rename from commands/make/dir.h
rename to usr.bin/make/dir.h
index d758371ca1a2baf128f4f0c7d59d7f6693ce6a47..aa004504a5bccef808d21352431e039aaf25b78d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: dir.h,v 1.14 2009/01/23 21:26:30 dsl Exp $     */
+/*     $NetBSD: dir.h,v 1.15 2012/04/07 18:29:08 christos Exp $        */
 
 /*
  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -95,7 +95,7 @@ Boolean Dir_HasWildcards(char *);
 void Dir_Expand(const char *, Lst, Lst);
 char *Dir_FindFile(const char *, Lst);
 int Dir_FindHereOrAbove(char *, char *, char *, int);
-int Dir_MTime(GNode *);
+int Dir_MTime(GNode *, Boolean);
 Path *Dir_AddDir(Lst, const char *);
 char *Dir_MakeFlags(const char *, Lst);
 void Dir_ClearPath(Lst);
similarity index 97%
rename from commands/make/for.c
rename to usr.bin/make/for.c
index 4a320a38a8f1e4f67295fa14329fbdd53788fa72..fd4f2b7329622ead4ebd84481b564885385a0fab 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: for.c,v 1.47 2010/02/06 20:37:13 dholland Exp $        */
+/*     $NetBSD: for.c,v 1.48 2010/12/25 04:57:07 dholland Exp $        */
 
 /*
  * Copyright (c) 1992, The Regents of the University of California.
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: for.c,v 1.47 2010/02/06 20:37:13 dholland Exp $";
+static char rcsid[] = "$NetBSD: for.c,v 1.48 2010/12/25 04:57:07 dholland Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)for.c      8.1 (Berkeley) 6/6/93";
 #else
-__RCSID("$NetBSD: for.c,v 1.47 2010/02/06 20:37:13 dholland Exp $");
+__RCSID("$NetBSD: for.c,v 1.48 2010/12/25 04:57:07 dholland Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -366,7 +366,7 @@ for_substitute(Buffer *cmds, strlist_t *items, unsigned int item_no, char ech)
 }
 
 static char *
-For_Iterate(void *v_arg)
+For_Iterate(void *v_arg, size_t *ret_len)
 {
     For *arg = v_arg;
     int i, len;
@@ -451,6 +451,7 @@ For_Iterate(void *v_arg)
     arg->sub_next += strlist_num(&arg->vars);
 
     arg->parse_buf = cp;
+    *ret_len = strlen(cp);
     return cp;
 }
 
similarity index 100%
rename from commands/make/hash.c
rename to usr.bin/make/hash.c
similarity index 100%
rename from commands/make/hash.h
rename to usr.bin/make/hash.h
similarity index 96%
rename from commands/make/job.c
rename to usr.bin/make/job.c
index aeda9da9344fc7f8f084f9dcc4c765ac3bc05f0c..1e8eefb14705593046a9355f64eb79f30c6e0e15 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: job.c,v 1.151 2010/06/17 03:36:05 sjg Exp $    */
+/*     $NetBSD: job.c,v 1.161 2012/04/07 18:29:08 christos Exp $       */
 
 /*
  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: job.c,v 1.151 2010/06/17 03:36:05 sjg Exp $";
+static char rcsid[] = "$NetBSD: job.c,v 1.161 2012/04/07 18:29:08 christos Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)job.c      8.2 (Berkeley) 3/19/94";
 #else
-__RCSID("$NetBSD: job.c,v 1.151 2010/06/17 03:36:05 sjg Exp $");
+__RCSID("$NetBSD: job.c,v 1.161 2012/04/07 18:29:08 christos Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -321,10 +321,7 @@ static int readyfd(Job *);
 
 STATIC GNode           *lastNode;      /* The node for which output was most recently
                                 * produced. */
-STATIC const char *targFmt;    /* Format string to use to head output from a
-                                * job when it's not the most-recent job heard
-                                * from */
-static char *targPrefix = NULL; /* What we print at the start of targFmt */
+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 */
@@ -333,10 +330,11 @@ static Job childExitJob;  /* child exit pseudo-job */
 
 #define TARG_FMT  "%s %s ---\n" /* Default format */
 #define MESSAGE(fp, gn) \
-       (void)fprintf(fp, targFmt, targPrefix, gn->name)
+       if (maxJobs != 1) \
+           (void)fprintf(fp, TARG_FMT, targPrefix, gn->name)
 
 static sigset_t caught_signals;        /* Set of signals we handle */
-#if defined(SYSV) || defined(__minix)
+#if defined(SYSV)
 #define KILLPG(pid, sig)       kill(-(pid), (sig))
 #else
 #define KILLPG(pid, sig)       killpg((pid), (sig))
@@ -344,7 +342,7 @@ static sigset_t caught_signals;     /* Set of signals we handle */
 
 static void JobChildSig(int);
 static void JobContinueSig(int);
-static Job *JobFindPid(int, int);
+static Job *JobFindPid(int, int, Boolean);
 static int JobPrintCommand(void *, void *);
 static int JobSaveCommand(void *, void *);
 static void JobClose(Job *);
@@ -354,7 +352,7 @@ 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);
+static void JobInterrupt(int, int) __dead;
 static void JobRestartJobs(void);
 static void JobTokenAdd(void);
 static void JobSigLock(sigset_t *);
@@ -525,14 +523,14 @@ JobContinueSig(int signo __unused)
  *
  *-----------------------------------------------------------------------
  */
-static void
+__dead static void
 JobPassSig_int(int signo)
 {
     /* Run .INTERRUPT target then exit */
     JobInterrupt(TRUE, signo);
 }
 
-static void
+__dead static void
 JobPassSig_term(int signo)
 {
     /* Dont run .INTERRUPT target then exit */
@@ -616,7 +614,7 @@ JobPassSig_suspend(int signo)
  *-----------------------------------------------------------------------
  */
 static Job *
-JobFindPid(int pid, int status)
+JobFindPid(int pid, int status, Boolean isJobs)
 {
     Job *job;
 
@@ -624,7 +622,7 @@ JobFindPid(int pid, int status)
        if ((job->job_state == status) && job->pid == pid)
            return job;
     }
-    if (DEBUG(JOB))
+    if (DEBUG(JOB) && isJobs)
        job_table_dump("no pid");
     return NULL;
 }
@@ -713,6 +711,7 @@ JobPrintCommand(void *cmdp, void *jobp)
            shutUp = DEBUG(LOUD) ? FALSE : TRUE;
            break;
        case '-':
+           job->flags |= JOB_IGNERR;
            errOff = TRUE;
            break;
        case '+':
@@ -761,7 +760,7 @@ JobPrintCommand(void *cmdp, void *jobp)
     }
 
     if (errOff) {
-       if ( !(job->flags & JOB_IGNERR) && !noSpecials) {
+       if (!noSpecials) {
            if (commandShell->hasErrCtl) {
                /*
                 * we don't want the error-control commands showing
@@ -1016,10 +1015,15 @@ JobFinish(Job *job, int status)
                    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)" : "");
+                              (job->flags & JOB_IGNERR) ? " (ignored)" : "");
                if (job->flags & JOB_IGNERR) {
                    status = 0;
                } else {
@@ -1044,6 +1048,12 @@ JobFinish(Job *job, int status)
        (void)fflush(stdout);
     }
 
+#ifdef USE_META
+    if (useMeta) {
+       meta_job_finish(job);
+    }
+#endif
+    
     return_job_token = FALSE;
 
     Trace_Log(JOBEND, job);
@@ -1123,7 +1133,8 @@ 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_PHONY)) {
+    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.
@@ -1215,7 +1226,7 @@ Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...))
            Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn, 0);
            if (p1)
                free(p1);
-       } else if (Dir_MTime(gn) == 0 && (gn->type & OP_SPECIAL) == 0) {
+       } 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
@@ -1232,11 +1243,11 @@ Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...))
            }
 
            if (gn->type & OP_OPTIONAL) {
-               (void)fprintf(stdout, "%s%s %s(ignored)\n", progname,
+               (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,
+               (void)fprintf(stdout, "%s%s %s (continuing)\n", progname,
                    msg, gn->name);
                (void)fflush(stdout);
                return FALSE;
@@ -1310,6 +1321,11 @@ JobExec(Job *job, char **argv)
        /* 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).
@@ -1552,6 +1568,7 @@ JobStart(GNode *gn, int flags)
         * also dead...
         */
        if (!cmdsOK) {
+           PrintOnError(gn, NULL);     /* provide some clue */
            DieHorribly();
        }
 
@@ -1572,6 +1589,14 @@ JobStart(GNode *gn, int flags)
         */
        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
         */
@@ -1844,6 +1869,11 @@ end_loop:
                    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);
            }
@@ -1926,7 +1956,6 @@ void
 Job_CatchChildren(void)
 {
     int          pid;          /* pid of dead child */
-    Job                  *job;         /* job descriptor for dead child */
     int                  status;       /* Exit/termination status */
 
     /*
@@ -1940,41 +1969,60 @@ Job_CatchChildren(void)
            (void)fprintf(debug_file, "Process %d exited/stopped status %x.\n", pid,
              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, int 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);
-       if (job == NULL) {
+    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);
-           continue;
        }
-       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;
+       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));
            }
-           (void)fflush(stdout);
-           continue;
+           job->job_suspended = 1;
        }
+       (void)fflush(stdout);
+       return;
+    }
 
-       job->job_state = JOB_ST_FINISHED;
-       job->exit_status = status;
+    job->job_state = JOB_ST_FINISHED;
+    job->exit_status = status;
 
-       JobFinish(job, status);
-    }
+    JobFinish(job, status);
 }
 
 /*-
@@ -2131,16 +2179,6 @@ Job_Init(void)
 
     lastNode =   NULL;
 
-    if (maxJobs == 1) {
-       /*
-        * If only one job can run at a time, there's no need for a banner,
-        * is there?
-        */
-       targFmt = "";
-    } else {
-       targFmt = TARG_FMT;
-    }
-
     /*
      * There is a non-zero chance that we already have children.
      * eg after 'make -f- <<EOF'
similarity index 98%
rename from commands/make/job.h
rename to usr.bin/make/job.h
index 326aa3e5c7bc9598c3145aa8253976be2954639d..560b70bf7326f5fac0db5aabf8693dfdba0c3cf6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: job.h,v 1.39 2009/04/11 09:41:18 apb Exp $     */
+/*     $NetBSD: job.h,v 1.40 2010/09/13 15:36:57 sjg Exp $     */
 
 /*
  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -135,6 +135,11 @@ emul_poll(struct pollfd *fd, int nfd, int timeout);
  */
 struct pollfd;
 
+
+#ifdef USE_META
+# include "meta.h"
+#endif
+
 #define JOB_BUFSIZE    1024
 typedef struct Job {
     int        pid;        /* The child's process ID */
@@ -165,6 +170,10 @@ typedef struct Job {
                                /* Buffer for storing the output of the
                                 * job, line by line */
     int        curPos; /* Current position in op_outBuf */
+
+#ifdef USE_META
+    struct BuildMon    bm;
+#endif
 } Job;
 
 #define inPipe jobPipe[0]
similarity index 100%
rename from commands/make/lst.h
rename to usr.bin/make/lst.h
similarity index 98%
rename from commands/make/main.c
rename to usr.bin/make/main.c
index 169778c10c4fa29fbf761f6daaa603a1930ba4ed..71f6de72e9999f3275ac43467501f69a0ce3a67c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: main.c,v 1.188 2010/06/03 15:40:16 sjg Exp $   */
+/*     $NetBSD: main.c,v 1.198 2011/09/16 15:38:04 joerg Exp $ */
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -69,7 +69,7 @@
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: main.c,v 1.188 2010/06/03 15:40:16 sjg Exp $";
+static char rcsid[] = "$NetBSD: main.c,v 1.198 2011/09/16 15:38:04 joerg Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
@@ -81,7 +81,7 @@ __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\
 #if 0
 static char sccsid[] = "@(#)main.c     8.3 (Berkeley) 3/19/94";
 #else
-__RCSID("$NetBSD: main.c,v 1.188 2010/06/03 15:40:16 sjg Exp $");
+__RCSID("$NetBSD: main.c,v 1.198 2011/09/16 15:38:04 joerg Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -178,11 +178,11 @@ static const char *       tracefile;
 static char *          Check_Cwd_av(int, char **, int);
 static void            MainParseArgs(int, char **);
 static int             ReadMakefile(const void *, const void *);
-static void            usage(void);
+static void            usage(void) __dead;
 
 static Boolean         ignorePWD;      /* if we use -C, PWD is meaningless */
-static char curdir[MAXPATHLEN + 1];    /* startup directory */
 static char objdir[MAXPATHLEN + 1];    /* where we chdir'ed to */
+char curdir[MAXPATHLEN + 1];           /* Startup directory */
 char *progname;                                /* the program name */
 char *makeDependfile;
 pid_t myPid;
@@ -242,6 +242,9 @@ parse_debug_options(const char *argvalue)
                case 'l':
                        debug |= DEBUG_LOUD;
                        break;
+               case 'M':
+                       debug |= DEBUG_META;
+                       break;
                case 'm':
                        debug |= DEBUG_MAKE;
                        break;
@@ -684,7 +687,7 @@ ReadAllMakefiles(const void *p, const void *q)
        return (ReadMakefile(p, q) == 0);
 }
 
-static int
+int
 str2Lst_Append(Lst lp, char *str, const char *sep)
 {
     char *cp;
@@ -703,7 +706,7 @@ str2Lst_Append(Lst lp, char *str, const char *sep)
 #ifdef SIGINFO
 /*ARGSUSED*/
 static void
-siginfo(int signo)
+siginfo(int signo __unused)
 {
        char dir[MAXPATHLEN];
        char str[2 * MAXPATHLEN];
@@ -732,6 +735,10 @@ MakeMode(const char *mode)
            compatMake = TRUE;
            forceJobs = FALSE;
        }
+#if USE_META
+       if (strstr(mode, "meta"))
+           meta_init(mode);
+#endif
     }
     if (mp)
        free(mp);
@@ -762,7 +769,7 @@ main(int argc, char **argv)
        struct stat sb, sa;
        char *p1, *path, *pwd;
        char mdpath[MAXPATHLEN];
-       char *machine = getenv("MACHINE");
+       const char *machine = getenv("MACHINE");
        const char *machine_arch = getenv("MACHINE_ARCH");
        char *syspath = getenv("MAKESYSPATH");
        Lst sysMkPath;                  /* Path of sys.mk */
@@ -957,7 +964,8 @@ main(int argc, char **argv)
         * We take care of PWD for the automounter below...
         */
        if (getcwd(curdir, MAXPATHLEN) == NULL) {
-               (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno));
+               (void)fprintf(stderr, "%s: getcwd: %s.\n",
+                   progname, strerror(errno));
                exit(2);
        }
 
@@ -1300,7 +1308,7 @@ ReadMakefile(const void *p, const void *q __unused)
        char *name, *path = bmake_malloc(len);
 
        if (!strcmp(fname, "-")) {
-               Parse_File("(stdin)", dup(fileno(stdin)));
+               Parse_File(NULL /*stdin*/, -1);
                Var_Set("MAKEFILE", "", VAR_GLOBAL, 0);
        } else {
                /* if we've chdir'd, rebuild the path name */
@@ -1641,9 +1649,10 @@ Cmd_Exec(const char *cmd, const char **errnum)
        /*
         * Wait for the process to exit.
         */
-       while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0))
+       while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) {
+           JobReapChild(pid, status, FALSE);
            continue;
-
+       }
        cc = Buf_Size(&buf);
        res = Buf_Destroy(&buf, FALSE);
 
@@ -1958,20 +1967,10 @@ Main_ExportMAKEFLAGS(Boolean first)
     }
 }
 
-/*
- * Create and open a temp file using "pattern".
- * If "fnamep" is provided set it to a copy of the filename created.
- * Otherwise unlink the file once open.
- */
-int
-mkTempFile(const char *pattern, char **fnamep)
+char *
+getTmpdir(void)
 {
     static char *tmpdir = NULL;
-    char tfile[MAXPATHLEN];
-    int fd;
-    
-    if (!pattern)
-       pattern = TMPPAT;
 
     if (!tmpdir) {
        struct stat st;
@@ -1986,6 +1985,25 @@ mkTempFile(const char *pattern, char **fnamep)
            tmpdir = bmake_strdup(_PATH_TMP);
        }
     }
+    return tmpdir;
+}
+
+/*
+ * Create and open a temp file using "pattern".
+ * If "fnamep" is provided set it to a copy of the filename created.
+ * Otherwise unlink the file once open.
+ */
+int
+mkTempFile(const char *pattern, char **fnamep)
+{
+    static char *tmpdir = NULL;
+    char tfile[MAXPATHLEN];
+    int fd;
+    
+    if (!pattern)
+       pattern = TMPPAT;
+    if (!tmpdir)
+       tmpdir = getTmpdir();
     if (pattern[0] == '/') {
        snprintf(tfile, sizeof(tfile), "%s", pattern);
     } else {
similarity index 91%
rename from commands/make/make.1
rename to usr.bin/make/make.1
index a5aed6740034e041590a546ec4ba00aee2cb2546..51e77dbff9dacde8def4880326e6d561a44b443e 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $NetBSD: make.1,v 1.176 2010/06/10 18:35:22 wiz Exp $
+.\"    $NetBSD: make.1,v 1.202 2012/04/08 22:00:39 wiz Exp $
 .\"
 .\" Copyright (c) 1990, 1993
 .\"    The Regents of the University of California.  All rights reserved.
@@ -29,7 +29,7 @@
 .\"
 .\"    from: @(#)make.1        8.4 (Berkeley) 3/19/94
 .\"
-.Dd June 9, 2010
+.Dd March 31, 2012
 .Dt MAKE 1
 .Os
 .Sh NAME
 .Sh SYNOPSIS
 .Nm
 .Op Fl BeikNnqrstWX
-.Bk -words
 .Op Fl C Ar directory
-.Ek
-.Bk -words
 .Op Fl D Ar variable
-.Ek
-.Bk -words
 .Op Fl d Ar flags
-.Ek
-.Bk -words
 .Op Fl f Ar makefile
-.Ek
-.Bk -words
 .Op Fl I Ar directory
-.Ek
-.Bk -words
 .Op Fl J Ar private
-.Ek
-.Bk -words
 .Op Fl j Ar max_jobs
-.Ek
-.Bk -words
 .Op Fl m Ar directory
-.Ek
-.Bk -words
 .Op Fl T Ar file
-.Ek
-.Bk -words
 .Op Fl V Ar variable
-.Ek
 .Op Ar variable=value
-.Bk -words
 .Op Ar target ...
-.Ek
 .Sh DESCRIPTION
 .Nm
 is a program designed to simplify the maintenance of other programs.
@@ -95,7 +73,7 @@ This manual page is intended as a reference document only.
 For a more thorough description of
 .Nm
 and makefiles, please refer to
-.%T "Make \- A Tutorial" .
+.%T "PMake \- A Tutorial" .
 .Pp
 .Nm
 will prepend the contents of the
@@ -126,7 +104,7 @@ Turn on debugging, and specify which portions of
 .Nm
 are to print debugging information.
 Unless the flags are preceded by
-.Ql -
+.Ql \-
 they are added to the
 .Va MAKEFLAGS
 environment variable and will be processed by any child make processes.
@@ -194,6 +172,8 @@ Print commands in Makefiles regardless of whether or not they are prefixed by
 .Ql @
 or other "quiet" flags.
 Also known as "loud" behavior.
+.It Ar M
+Print debugging information about "meta" mode decisions about targets.
 .It Ar m
 Print debugging information about making targets, including modification
 dates.
@@ -266,6 +246,8 @@ cooperate to avoid overloading the system.
 Specify the maximum number of jobs that
 .Nm
 may have running at any one time.
+The value is saved in
+.Va .MAKE.JOBS .
 Turns compatibility mode off, unless the
 .Ar B
 flag is also specified.
@@ -613,7 +595,7 @@ The list of sources for this target that were deemed out-of-date; also
 known as
 .Ql Va \&? .
 .It Va .PREFIX
-The file prefix of the file, containing only the file portion, no suffix
+The file prefix of the target, containing only the file portion, no suffix
 or preceding directory components; also known as
 .Ql Va * .
 .It Va .TARGET
@@ -759,9 +741,73 @@ Processed after reading all makefiles.
 Can affect the mode that
 .Nm
 runs in.
-Currently just
-.Ql Pa compat
-mode.
+It can contain a number of keywords:
+.Bl -hang -width ignore-cmd
+.It Pa compat
+Like
+.Fl B ,
+puts
+.Nm
+into "compat" mode.
+.It Pa meta
+Puts
+.Nm
+into "meta" mode, where meta files are created for each target
+to capture the command run, the output generated and if
+.Xr filemon 4
+is available, the system calls which are of interest to
+.Nm .
+The captured output can be very useful when diagnosing errors.
+.It Pa curdirOk= Ar bf
+Normally
+.Nm
+will not create .meta files in
+.Ql Va .CURDIR .
+This can be overridden by setting
+.Va bf
+to a value which represents True.
+.It Pa env
+For debugging, it can be useful to inlcude the environment
+in the .meta file.
+.It Pa verbose
+If in "meta" mode, print a clue about the target being built.
+This is useful if the build is otherwise running silently.
+The message printed the value of:
+.Va .MAKE.META.PREFIX .
+.It Pa ignore-cmd
+Some makefiles have commands which are simply not stable.
+This keyword causes them to be ignored for
+determining whether a target is out of date in "meta" mode.
+See also
+.Ic .NOMETA_CMP .
+.It Pa silent= Ar bf
+If
+.Va bf
+is True, when a .meta file is created, mark the target
+.Ic .SILENT .
+.El
+.It Va .MAKE.META.BAILIWICK
+In "meta" mode, provides a list of prefixes which
+match the directories controlled by
+.Nm .
+If a file that was generated outside of
+.Va .OBJDIR
+but within said bailiwick is missing,
+the current target is considered out-of-date.
+.It Va .MAKE.META.CREATED
+In "meta" mode, this variable contains a list of all the meta files
+updated.
+If not empty, it can be used to trigger processing of
+.Va .MAKE.META.FILES .
+.It Va .MAKE.META.FILES
+In "meta" mode, this variable contains a list of all the meta files
+used (updated or not).
+This list can be used to process the meta files to extract dependency
+information.
+.It Va .MAKE.META.PREFIX
+Defines the message printed for each meta file updated in "meta verbose" mode.
+The default value is:
+.Dl Building ${.TARGET:H:tA}/${.TARGET:T}
 .It Va .MAKEOVERRIDES
 This variable is used to record the names of variables assigned to
 on the command line, so that they may be exported as part of
@@ -858,6 +904,9 @@ This variable and
 are both set only while the
 .Ql Pa Makefiles
 are being parsed.
+If you want to retain their current values, assign them to a variable
+using assignment with expansion:
+.Pq Ql Cm \&:= .
 .It Va .PATH
 A variable that represents the list of directories that
 .Nm
@@ -892,6 +941,8 @@ is set to the value of
 for all programs which
 .Nm
 executes.
+.It Ev .TARGETS
+The list of targets explicitly specified on the command line, if any.
 .It Ev VPATH
 Colon-separated
 .Pq Dq \&:
@@ -988,6 +1039,18 @@ safely through recursive invocations of
 .Nm .
 .It Cm \&:R
 Replaces each word in the variable with everything but its suffix.
+.It Cm \&:gmtime
+The value is a format string for
+.Xr strftime 3 ,
+using the current
+.Xr gmtime 3 .
+.It Cm \&:hash
+Compute a 32bit hash of the value and encode it as hex digits.
+.It Cm \&:localtime
+The value is a format string for
+.Xr strftime 3 ,
+using the current
+.Xr localtime 3 .
 .It Cm \&:tA
 Attempt to convert variable to an absolute path using
 .Xr realpath 3 ,
@@ -1127,7 +1190,7 @@ A common error is trying to use expressions like
 .Dl ${NUMBERS:M42:?match:no}
 which actually tests defined(NUMBERS),
 to determine is any words match "42" you need to use something like:
-.Dl ${${NUMBERS:M42} != "":?match:no} .
+.Dl ${"${NUMBERS:M42}" != \&"\&":?match:no} .
 .It Ar :old_string=new_string
 This is the
 .At V
@@ -1175,6 +1238,9 @@ The ODE convention is that
 should start and end with a period.
 For example.
 .Dl ${LINKS:@.LINK.@${LN} ${TARGET} ${.LINK.}@}
+.Pp
+However a single character varaiable is often more readable:
+.Dl ${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'${.newline}@}
 .It Cm \&:U Ns Ar newval
 If the variable is undefined
 .Ar newval
@@ -1196,6 +1262,8 @@ The path of the node which has the same name as the variable
 is the value.
 If no such node exists or its path is null, then the
 name of the variable is used.
+In order for this modifier to work, the name (node) must at least have 
+appeared on the rhs of a dependency.
 .Sm off
 .It Cm \&:\&! Ar cmd Cm \&!
 .Sm on
@@ -1256,7 +1324,7 @@ For the purposes of the
 modifier, the words are indexed both forwards using positive integers
 (where index 1 represents the first word),
 and backwards using negative integers
-(where index -1 represents the last word).
+(where index \-1 represents the last word).
 .Pp
 The
 .Ar range
@@ -1355,6 +1423,11 @@ except for internal variables (those that start with
 This is not affected by the
 .Fl X
 flag, so should be used with caution.
+For compatibility with other
+.Nm
+programs
+.Ql export variable=value
+is also accepted.
 .Pp
 Appending a variable name to
 .Va .MAKE.EXPORTED
@@ -1610,6 +1683,28 @@ or
 options were specified.
 Normally used to mark recursive
 .Nm Ns 's .
+.It Ic .META
+Create a meta file for the target, even if it is flagged as
+.Ic .PHONY ,
+.Ic .MAKE ,
+or
+.Ic .SPECIAL .
+Usage in conjunction with
+.Ic .MAKE
+is the most likely case.
+In "meta" mode, the target is out-of-date if the meta file is missing.
+.It Ic .NOMETA
+Do not create a meta file for the target.
+Meta files are also not created for
+.Ic .PHONY ,
+.Ic .MAKE ,
+or
+.Ic .SPECIAL
+targets.
+.It Ic .NOMETA_CMP
+Ignore differences in commands when deciding if target is out of date.
+This is useful if the command contains a value which always changes.
+If the number of commands change, though, the target will still be out of date.
 .It Ic .NOPATH
 Do not search for the target in the directories specified by
 .Ic .PATH .
@@ -1630,6 +1725,9 @@ correspond to an actual file; it is always considered to be out of date,
 and will not be created with the
 .Fl t
 option.
+Suffix-transformation rules are not applied to
+.Ic .PHONY
+targets.
 .It Ic .PRECIOUS
 When
 .Nm
@@ -1769,7 +1867,7 @@ could be built, unless
 is built by another part of the dependency graph,
 the following is a dependency loop:
 .Bd -literal
-\&.ORDER: a b
+\&.ORDER: b a
 b: a
 .Ed
 .Pp
@@ -1846,8 +1944,8 @@ character when used outside of any quoting characters.
 Example:
 .Bd -literal
 \&.SHELL: name=ksh path=/bin/ksh hasErrCtl=true \e
-       check="set -e" ignore="set +e" \e
-       echo="set -v" quiet="set +v" filter="set +v" \e
+       check="set \-e" ignore="set +e" \e
+       echo="set \-v" quiet="set +v" filter="set +v" \e
        echoFlag=v errFlag=e newline="'\en'"
 .Ed
 .It Ic .SILENT
@@ -1868,7 +1966,7 @@ Example:
 .Bd -literal
 \&.SUFFIXES: .o
 \&.c.o:
-       cc -o ${.TARGET} -c ${.IMPSRC}
+       cc \-o ${.TARGET} \-c ${.IMPSRC}
 .Ed
 .El
 .Sh ENVIRONMENT
@@ -1913,7 +2011,7 @@ however the special variables, variable modifiers and conditionals are not.
 .Pp
 The way that parallel makes are scheduled changed in
 .Nx 4.0
-so that .ORDER and .WAIT apply recursively to the dependant nodes.
+so that .ORDER and .WAIT apply recursively to the dependent nodes.
 The algorithms used may change again in the future.
 .Pp
 The way that .for loop variables are substituted changed after
@@ -1921,6 +2019,21 @@ The way that .for loop variables are substituted changed after
 so that they still appear to be variable expansions.
 In particular this stops them being treated as syntax, and removes some
 obscure problems using them in .if statements.
+.Pp
+Unlike other
+.Nm
+programs, this implementation by default executes all commands for a given
+target using a single shell invocation.
+This is done for both efficiency and to simplify error handling in remote
+command invocations.
+Typically this is transparent to the user, unless the target commands change
+the current working directory using
+.Dq cd
+or
+.Dq chdir .
+To be compatible with Makefiles that do this, one can use
+.Fl B
+to disable this behavior.
 .Sh SEE ALSO
 .Xr mkdep 1
 .Sh HISTORY
@@ -1928,6 +2041,13 @@ A
 .Nm
 command appeared in
 .At v7 .
+This
+.Nm
+implementation is based on Adam De Boor's pmake program which was written
+for Sprint at Berkeley.
+It was designed to be a parallel distributed make running jobs on different
+machines using a daemon called
+.Dq customs .
 .Sh BUGS
 The
 .Nm
similarity index 97%
rename from commands/make/make.c
rename to usr.bin/make/make.c
index 11e2ca8cba3ac0fb68cf00b020b89133a531e552..704718c200ef575d424294685b41dee4d717ecc3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: make.c,v 1.79 2010/04/07 00:11:27 sjg Exp $    */
+/*     $NetBSD: make.c,v 1.85 2012/04/07 18:29:08 christos Exp $       */
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: make.c,v 1.79 2010/04/07 00:11:27 sjg Exp $";
+static char rcsid[] = "$NetBSD: make.c,v 1.85 2012/04/07 18:29:08 christos Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)make.c     8.1 (Berkeley) 6/6/93";
 #else
-__RCSID("$NetBSD: make.c,v 1.79 2010/04/07 00:11:27 sjg Exp $");
+__RCSID("$NetBSD: make.c,v 1.85 2012/04/07 18:29:08 christos Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -94,12 +94,12 @@ __RCSID("$NetBSD: make.c,v 1.79 2010/04/07 00:11:27 sjg Exp $");
  *
  *     Make_Update             Update all parents of a given child. Performs
  *                             various bookkeeping chores like the updating
- *                             of the cmtime field of the parent, filling
+ *                             of the cmgn field of the parent, filling
  *                             of the IMPSRC context variable, etc. It will
  *                             place the parent on the toBeMade queue if it
  *                             should be.
  *
- *     Make_TimeStamp          Function to set the parent's cmtime field
+ *     Make_TimeStamp          Function to set the parent's cmgn field
  *                             based on a child's modification time.
  *
  *     Make_DoAllVar           Set up the various local variables for a
@@ -139,7 +139,7 @@ static int MakeCheckOrder(void *, void *);
 static int MakeBuildChild(void *, void *);
 static int MakeBuildParent(void *, void *);
 
-static void
+__dead static void
 make_abort(GNode *gn, int line)
 {
     static int two = 2;
@@ -154,7 +154,7 @@ make_abort(GNode *gn, int line)
 /*-
  *-----------------------------------------------------------------------
  * Make_TimeStamp --
- *     Set the cmtime field of a parent node based on the mtime stamp in its
+ *     Set the cmgn field of a parent node based on the mtime stamp in its
  *     child. Called from MakeOODate via Lst_ForEach.
  *
  * Input:
@@ -165,15 +165,15 @@ make_abort(GNode *gn, int line)
  *     Always returns 0.
  *
  * Side Effects:
- *     The cmtime of the parent node will be changed if the mtime
+ *     The cmgn of the parent node will be changed if the mtime
  *     field of the child is greater than it.
  *-----------------------------------------------------------------------
  */
 int
 Make_TimeStamp(GNode *pgn, GNode *cgn)
 {
-    if (cgn->mtime > pgn->cmtime) {
-       pgn->cmtime = cgn->mtime;
+    if (pgn->cmgn == NULL || cgn->mtime > pgn->cmgn->mtime) {
+       pgn->cmgn = cgn;
     }
     return (0);
 }
@@ -207,7 +207,7 @@ MakeTimeStamp(void *pgn, void *cgn)
  *     TRUE if the node is out of date. FALSE otherwise.
  *
  * Side Effects:
- *     The mtime field of the node and the cmtime field of its parents
+ *     The mtime field of the node and the cmgn field of its parents
  *     will/may be changed.
  *-----------------------------------------------------------------------
  */
@@ -221,7 +221,7 @@ Make_OODate(GNode *gn)
      * doesn't depend on their modification time...
      */
     if ((gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC)) == 0) {
-       (void)Dir_MTime(gn);
+       (void)Dir_MTime(gn, 0);
        if (DEBUG(MAKE)) {
            if (gn->mtime != 0) {
                fprintf(debug_file, "modified %s...", Targ_FmtTime(gn->mtime));
@@ -265,7 +265,7 @@ Make_OODate(GNode *gn)
         * or non-existent.
         */
        oodate = (gn->mtime == 0 || Arch_LibOODate(gn) || 
-                 (gn->cmtime == 0 && (gn->type & OP_DOUBLEDEP)));
+                 (gn->cmgn == NULL && (gn->type & OP_DOUBLEDEP)));
     } else if (gn->type & OP_JOIN) {
        /*
         * A target with the .JOIN attribute is only considered
@@ -293,21 +293,22 @@ Make_OODate(GNode *gn)
            }
        }
        oodate = TRUE;
-    } else if (gn->mtime < gn->cmtime ||
-              (gn->cmtime == 0 &&
+    } else if ((gn->cmgn != NULL && gn->mtime < gn->cmgn->mtime) ||
+              (gn->cmgn == NULL &&
                ((gn->mtime == 0 && !(gn->type & OP_OPTIONAL))
                  || gn->type & OP_DOUBLEDEP)))
     {
        /*
         * A node whose modification time is less than that of its
-        * youngest child or that has no children (cmtime == 0) and
+        * youngest child or that has no children (cmgn == NULL) and
         * either doesn't exist (mtime == 0) and it isn't optional
         * or was the object of a * :: operator is out-of-date.
         * Why? Because that's the way Make does it.
         */
        if (DEBUG(MAKE)) {
-           if (gn->mtime < gn->cmtime) {
-               fprintf(debug_file, "modified before source...");
+           if (gn->cmgn != NULL && gn->mtime < gn->cmgn->mtime) {
+               fprintf(debug_file, "modified before source %s...",
+                   gn->cmgn->path);
            } else if (gn->mtime == 0) {
                fprintf(debug_file, "non-existent and no sources...");
            } else {
@@ -330,6 +331,12 @@ Make_OODate(GNode *gn)
        oodate = (gn->flags & FORCE) ? TRUE : FALSE;
     }
 
+#ifdef USE_META
+    if (useMeta) {
+       oodate = meta_oodate(gn, oodate);
+    }
+#endif
+
     /*
      * If the target isn't out-of-date, the parents need to know its
      * modification time. Note that targets that appear to be out-of-date
@@ -389,7 +396,7 @@ MakeAddChild(void *gnp, void *lp)
  *     Always returns 0
  *
  * Side Effects:
- *     The path and mtime of the node and the cmtime of the parent are
+ *     The path and mtime of the node and the cmgn of the parent are
  *     updated; the unmade children count of the parent is decremented.
  *-----------------------------------------------------------------------
  */
@@ -399,7 +406,7 @@ MakeFindChild(void *gnp, void *pgnp)
     GNode          *gn = (GNode *)gnp;
     GNode          *pgn = (GNode *)pgnp;
 
-    (void)Dir_MTime(gn);
+    (void)Dir_MTime(gn, 0);
     Make_TimeStamp(pgn, gn);
     pgn->unmade--;
 
@@ -567,7 +574,7 @@ MakeHandleUse(void *cgnp, void *pgnp)
 time_t
 Make_Recheck(GNode *gn)
 {
-    time_t mtime = Dir_MTime(gn);
+    time_t mtime = Dir_MTime(gn, 1);
 
 #ifndef RECHECK
     /*
@@ -657,12 +664,12 @@ Make_Recheck(GNode *gn)
  *     the toBeMade queue if this field becomes 0.
  *
  *     If the child was made, the parent's flag CHILDMADE field will be
- *     set true and its cmtime set to now.
+ *     set true.
  *
  *     If the child is not up-to-date and still does not exist,
  *     set the FORCE flag on the parents.
  *
- *     If the child wasn't made, the cmtime field of the parent will be
+ *     If the child wasn't made, the cmgn field of the parent will be
  *     altered if the child's mtime is big enough.
  *
  *     Finally, if the child is the implied source for the parent, the
@@ -1329,7 +1336,7 @@ Make_ExpandUse(Lst targs)
            *eon = ')';
        }
 
-       (void)Dir_MTime(gn);
+       (void)Dir_MTime(gn, 0);
        Var_Set(TARGET, gn->path ? gn->path : gn->name, gn, 0);
        Lst_ForEach(gn->children, MakeUnmark, gn);
        Lst_ForEach(gn->children, MakeHandleUse, gn);
similarity index 97%
rename from commands/make/make.h
rename to usr.bin/make/make.h
index d770586d60a29727529fed284169787278929de9..04b2ebc80d3cdeee16ea3e4656e5c0b33e86d601 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: make.h,v 1.82 2010/04/23 00:18:50 sjg Exp $    */
+/*     $NetBSD: make.h,v 1.87 2011/09/16 15:38:04 joerg Exp $  */
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
 #endif
 #endif
 
+#if !defined(__dead)
+#define __dead
+#endif
+
 #include "sprite.h"
 #include "lst.h"
 #include "hash.h"
@@ -187,8 +191,7 @@ typedef struct GNode {
     int             unmade;            /* The number of unmade children */
 
     time_t          mtime;             /* Its modification time */
-    time_t                 cmtime;     /* The modification time of its youngest
-                                * child */
+    struct GNode    *cmgn;     /* The youngest child */
 
     Lst            iParents;   /* Links to parents for which this is an
                                 * implied source, if any */
@@ -260,6 +263,9 @@ typedef struct GNode {
 #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 */
 /* 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 */
@@ -392,6 +398,7 @@ extern Boolean      oldVars;        /* Do old-style variable substitution */
 extern Lst     sysIncPath;     /* The system include path. */
 extern Lst     defIncPath;     /* The default include path. */
 
+extern char    curdir[];       /* Startup directory */
 extern char    *progname;      /* The program name */
 extern char    *makeDependfile; /* .depend */
 
@@ -399,11 +406,7 @@ extern char        *makeDependfile; /* .depend */
  * We cannot vfork() in a child of vfork().
  * Most systems do not enforce this but some do.
  */
-#if defined(__minix)
-#define vFork() fork()
-#else
 #define vFork() ((getpid() == myPid) ? vfork() : fork())
-#endif
 extern pid_t   myPid;
 
 #define        MAKEFLAGS       ".MAKEFLAGS"
@@ -437,6 +440,8 @@ extern int debug;
 #define DEBUG_SHELL    0x00800
 #define DEBUG_ERROR    0x01000
 #define DEBUG_LOUD     0x02000
+#define DEBUG_META     0x04000
+
 #define DEBUG_GRAPH3   0x10000
 #define DEBUG_SCRIPT   0x20000
 #define DEBUG_PARSE    0x40000
@@ -462,6 +467,7 @@ void PrintOnError(GNode *, const char *);
 void Main_ExportMAKEFLAGS(Boolean);
 Boolean Main_SetObjdir(const char *);
 int mkTempFile(const char *, char **);
+int str2Lst_Append(Lst, char *, const char *);
 
 #ifdef __GNUC__
 #define UNCONST(ptr)   ({              \
similarity index 92%
rename from commands/make/make_malloc.c
rename to usr.bin/make/make_malloc.c
index ac90d265fa65e3f8c88f872cd3e45c2eac9ea584..f0ccbc44bdaf85133679e00ad7294715841b976a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: make_malloc.c,v 1.5 2009/01/24 23:19:50 dsl Exp $      */
+/*     $NetBSD: make_malloc.c,v 1.6 2010/12/25 20:35:25 dholland Exp $ */
 
 /*-
  * Copyright (c) 2009 The NetBSD Foundation, Inc.
@@ -28,7 +28,7 @@
 
 #ifdef MAKE_NATIVE
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: make_malloc.c,v 1.5 2009/01/24 23:19:50 dsl Exp $");
+__RCSID("$NetBSD: make_malloc.c,v 1.6 2010/12/25 20:35:25 dholland Exp $");
 #endif
 
 #include <stdio.h>
@@ -48,7 +48,7 @@ enomem(void)
 {
        extern char *progname;
 
-       (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno));
+       (void)fprintf(stderr, "%s: %s.\n", progname, strerror(ENOMEM));
        exit(2);
 }
 
diff --git a/usr.bin/make/meta.c b/usr.bin/make/meta.c
new file mode 100644 (file)
index 0000000..37a5b29
--- /dev/null
@@ -0,0 +1,1346 @@
+/*      $NetBSD: meta.c,v 1.24 2011/09/21 14:30:47 christos Exp $ */
+
+/*
+ * Implement 'meta' mode.
+ * Adapted from John Birrell's patches to FreeBSD make.
+ * --sjg
+ */
+/*
+ * Copyright (c) 2009-2010, Juniper Networks, Inc.
+ * Portions Copyright (c) 2009, John Birrell.
+ * 
+ * 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.  
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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. 
+ */
+#if defined(USE_META)
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <errno.h>
+#if !defined(HAVE_CONFIG_H) || defined(HAVE_ERR_H)
+#include <err.h>
+#endif
+
+#include "make.h"
+#include "job.h"
+
+#ifdef HAVE_FILEMON_H
+# include <filemon.h>
+#endif
+#if !defined(USE_FILEMON) && defined(FILEMON_SET_FD)
+# define USE_FILEMON
+#endif
+
+static BuildMon Mybm;                  /* for compat */
+static Lst metaBailiwick;                      /* our scope of control */
+
+Boolean useMeta = FALSE;
+static Boolean useFilemon = FALSE;
+static Boolean writeMeta = FALSE;
+static Boolean metaEnv = FALSE;                /* don't save env unless asked */
+static Boolean metaVerbose = FALSE;
+static Boolean metaIgnoreCMDs = FALSE; /* ignore CMDs in .meta files */
+static Boolean metaCurdirOk = FALSE;   /* write .meta in .CURDIR Ok? */
+static Boolean metaSilent = FALSE;     /* if we have a .meta be SILENT */
+
+extern Boolean forceJobs;
+extern Boolean comatMake;
+
+#define        MAKE_META_PREFIX        ".MAKE.META.PREFIX"
+
+#ifndef N2U
+# define N2U(n, u)   (((n) + ((u) - 1)) / (u))
+#endif
+#ifndef ROUNDUP
+# define ROUNDUP(n, u)   (N2U((n), (u)) * (u))
+#endif
+
+#if !defined(HAVE_STRSEP)
+# define strsep(s, d) stresep((s), (d), 0)
+#endif
+
+/*
+ * Filemon is a kernel module which snoops certain syscalls.
+ *
+ * C chdir
+ * E exec
+ * F [v]fork
+ * L [sym]link
+ * M rename
+ * R read
+ * W write
+ * S stat
+ *
+ * See meta_oodate below - we mainly care about 'E' and 'R'.
+ *
+ * We can still use meta mode without filemon, but 
+ * the benefits are more limited.
+ */
+#ifdef USE_FILEMON
+# ifndef _PATH_FILEMON
+#   define _PATH_FILEMON "/dev/filemon"
+# endif
+
+/*
+ * Open the filemon device.
+ */
+static void
+filemon_open(BuildMon *pbm)
+{
+    int retry;
+    
+    pbm->mon_fd = pbm->filemon_fd = -1;
+    if (!useFilemon)
+       return;
+
+    for (retry = 5; retry >= 0; retry--) {
+       if ((pbm->filemon_fd = open(_PATH_FILEMON, O_RDWR)) >= 0)
+           break;
+    }
+
+    if (pbm->filemon_fd < 0) {
+       useFilemon = FALSE;
+       warn("Could not open %s", _PATH_FILEMON);
+       return;
+    }
+
+    /*
+     * We use a file outside of '.'
+     * to avoid a FreeBSD kernel bug where unlink invalidates
+     * cwd causing getcwd to do a lot more work.
+     * We only care about the descriptor.
+     */
+    pbm->mon_fd = mkTempFile("filemon.XXXXXX", NULL);
+    if (ioctl(pbm->filemon_fd, FILEMON_SET_FD, &pbm->mon_fd) < 0) {
+       err(1, "Could not set filemon file descriptor!");
+    }
+    /* we don't need these once we exec */
+    (void)fcntl(pbm->mon_fd, F_SETFD, 1);
+    (void)fcntl(pbm->filemon_fd, F_SETFD, 1);
+}
+
+/*
+ * Read the build monitor output file and write records to the target's
+ * metadata file.
+ */
+static void
+filemon_read(FILE *mfp, int fd)
+{
+    FILE *fp;
+    char buf[BUFSIZ];
+
+    /* Check if we're not writing to a meta data file.*/
+    if (mfp == NULL) {
+       if (fd >= 0)
+           close(fd);                  /* not interested */
+       return;
+    }
+    /* rewind */
+    (void)lseek(fd, (off_t)0, SEEK_SET);
+    if ((fp = fdopen(fd, "r")) == NULL)
+       err(1, "Could not read build monitor file '%d'", fd);
+
+    fprintf(mfp, "-- filemon acquired metadata --\n");
+
+    while (fgets(buf, sizeof(buf), fp)) {
+       fprintf(mfp, "%s", buf);
+    }
+    fflush(mfp);
+    clearerr(fp);
+    fclose(fp);
+}
+#endif
+
+/*
+ * when realpath() fails,
+ * we use this, to clean up ./ and ../
+ */
+static void
+eat_dots(char *buf, size_t bufsz, int dots)
+{
+    char *cp;
+    char *cp2;
+    const char *eat;
+    size_t eatlen;
+
+    switch (dots) {
+    case 1:
+       eat = "/./";
+       eatlen = 2;
+       break;
+    case 2:
+       eat = "/../";
+       eatlen = 3;
+       break;
+    default:
+       return;
+    }
+    
+    do {
+       cp = strstr(buf, eat);
+       if (cp) {
+           cp2 = cp + eatlen;
+           if (dots == 2 && cp > buf) {
+               do {
+                   cp--;
+               } while (cp > buf && *cp != '/');
+           }
+           if (*cp == '/') {
+               strlcpy(cp, cp2, bufsz - (cp - buf));
+           } else {
+               return;                 /* can't happen? */
+           }
+       }
+    } while (cp);
+}
+
+static char *
+meta_name(struct GNode *gn, char *mname, size_t mnamelen,
+         const char *dname,
+         const char *tname)
+{
+    char buf[MAXPATHLEN];
+    char cwd[MAXPATHLEN];
+    char *rp;
+    char *cp;
+    char *tp;
+    char *p[4];                                /* >= number of possible uses */
+    int i;
+
+    i = 0;
+    if (!dname)
+       dname = Var_Value(".OBJDIR", gn, &p[i++]);
+    if (!tname)
+       tname = Var_Value(TARGET, gn, &p[i++]);
+
+    if (realpath(dname, cwd))
+       dname = cwd;
+
+    /*
+     * Weed out relative paths from the target file name.
+     * We have to be careful though since if target is a
+     * symlink, the result will be unstable.
+     * So we use realpath() just to get the dirname, and leave the
+     * basename as given to us.
+     */
+    if ((cp = strrchr(tname, '/'))) {
+       if (realpath(tname, buf)) {
+           if ((rp = strrchr(buf, '/'))) {
+               rp++;
+               cp++;
+               if (strcmp(cp, rp) != 0)
+                   strlcpy(rp, cp, sizeof(buf) - (rp - buf));
+           }
+           tname = buf;
+       } else {
+           /*
+            * We likely have a directory which is about to be made.
+            * We pretend realpath() succeeded, to have a chance
+            * of generating the same meta file name that we will
+            * next time through.
+            */
+           if (tname[0] == '/') {
+               strlcpy(buf, tname, sizeof(buf));
+           } else {
+               snprintf(buf, sizeof(buf), "%s/%s", cwd, tname);
+           }
+           eat_dots(buf, sizeof(buf), 1);      /* ./ */
+           eat_dots(buf, sizeof(buf), 2);      /* ../ */
+           tname = buf;
+       }
+    }
+    /* on some systems dirname may modify its arg */
+    tp = bmake_strdup(tname);
+    if (strcmp(dname, dirname(tp)) == 0)
+       snprintf(mname, mnamelen, "%s.meta", tname);
+    else {
+       snprintf(mname, mnamelen, "%s/%s.meta", dname, tname);
+
+       /*
+        * Replace path separators in the file name after the
+        * current object directory path.
+        */
+       cp = mname + strlen(dname) + 1;
+
+       while (*cp != '\0') {
+           if (*cp == '/')
+               *cp = '_';
+           cp++;
+       }
+    }
+    free(tp);
+    for (i--; i >= 0; i--) {
+       if (p[i])
+           free(p[i]);
+    }
+    return (mname);
+}
+
+/*
+ * Return true if running ${.MAKE}
+ * Bypassed if target is flagged .MAKE
+ */
+static int
+is_submake(void *cmdp, void *gnp)
+{
+    static char *p_make = NULL;
+    static int p_len;
+    char  *cmd = cmdp;
+    GNode *gn = gnp;
+    char *mp = NULL;
+    char *cp;
+    char *cp2;
+    int rc = 0;                                /* keep looking */
+
+    if (!p_make) {
+       p_make = Var_Value(".MAKE", gn, &cp);
+       p_len = strlen(p_make);
+    }
+    cp = strchr(cmd, '$');
+    if ((cp)) {
+       mp = Var_Subst(NULL, cmd, gn, FALSE);
+       cmd = mp;
+    }
+    cp2 = strstr(cmd, p_make);
+    if ((cp2)) {
+       switch (cp2[p_len]) {
+       case '\0':
+       case ' ':
+       case '\t':
+       case '\n':
+           rc = 1;
+           break;
+       }
+       if (cp2 > cmd && rc > 0) {
+           switch (cp2[-1]) {
+           case ' ':
+           case '\t':
+           case '\n':
+               break;
+           default:
+               rc = 0;                 /* no match */
+               break;
+           }
+       }
+    }
+    if (mp)
+       free(mp);
+    return (rc);
+}
+
+typedef struct meta_file_s {
+    FILE *fp;
+    GNode *gn;
+} meta_file_t;
+
+static int
+printCMD(void *cmdp, void *mfpp)
+{
+    meta_file_t *mfp = mfpp;
+    char *cmd = cmdp;
+    char *cp = NULL;
+
+    if (strchr(cmd, '$')) {
+       cmd = cp = Var_Subst(NULL, cmd, mfp->gn, FALSE);
+    }
+    fprintf(mfp->fp, "CMD %s\n", cmd);
+    if (cp)
+       free(cp);
+    return 0;
+}
+
+/*
+ * Certain node types never get a .meta file
+ */
+#define SKIP_META_TYPE(_type) do { \
+    if ((gn->type & __CONCAT(OP_, _type))) {   \
+       if (DEBUG(META)) { \
+           fprintf(debug_file, "Skipping meta for %s: .%s\n", \
+                   gn->name, __STRING(_type));                \
+       } \
+       return (NULL); \
+    } \
+} while (0)
+
+static FILE *
+meta_create(BuildMon *pbm, GNode *gn)
+{
+    extern char **environ;
+    meta_file_t mf;
+    char buf[MAXPATHLEN];
+    char objdir[MAXPATHLEN];
+    char **ptr;
+    const char *dname;
+    const char *tname;
+    char *fname;
+    const char *cp;
+    char *p[4];                                /* >= possible uses */
+    int i;
+    struct stat fs;
+
+    
+    /* This may be a phony node which we don't want meta data for... */
+    /* Skip .meta for .BEGIN, .END, .ERROR etc as well. */
+    /* Or it may be explicitly flagged as .NOMETA */
+    SKIP_META_TYPE(NOMETA);
+    /* Unless it is explicitly flagged as .META */
+    if (!(gn->type & OP_META)) {
+       SKIP_META_TYPE(PHONY);
+       SKIP_META_TYPE(SPECIAL);
+       SKIP_META_TYPE(MAKE);
+    }
+
+    mf.fp = NULL;
+    
+    i = 0;
+    
+    dname = Var_Value(".OBJDIR", gn, &p[i++]);
+    tname = Var_Value(TARGET, gn, &p[i++]);
+    
+    /* The object directory may not exist. Check it.. */
+    if (stat(dname, &fs) != 0) {
+       if (DEBUG(META))
+           fprintf(debug_file, "Skipping meta for %s: no .OBJDIR\n",
+                   gn->name);
+       goto out;
+    }
+    /* Check if there are no commands to execute. */
+    if (Lst_IsEmpty(gn->commands)) {
+       if (DEBUG(META))
+           fprintf(debug_file, "Skipping meta for %s: no commands\n",
+                   gn->name);
+       goto out;
+    }
+
+    /* make sure these are canonical */
+    if (realpath(dname, objdir))
+       dname = objdir;
+
+    /* If we aren't in the object directory, don't create a meta file. */
+    if (!metaCurdirOk && strcmp(curdir, dname) == 0) {
+       if (DEBUG(META))
+           fprintf(debug_file, "Skipping meta for %s: .OBJDIR == .CURDIR\n",
+                   gn->name);
+       goto out;
+    }
+    if (!(gn->type & OP_META)) {
+       /* We do not generate .meta files for sub-makes */
+       if (Lst_ForEach(gn->commands, is_submake, gn)) {
+           if (DEBUG(META))
+               fprintf(debug_file, "Skipping meta for %s: .MAKE\n",
+                       gn->name);
+           goto out;
+       }
+    }
+
+    if (metaVerbose) {
+       char *mp;
+
+       /* Describe the target we are building */
+       mp = Var_Subst(NULL, "${" MAKE_META_PREFIX "}", gn, 0);
+       if (*mp)
+           fprintf(stdout, "%s\n", mp);
+       free(mp);
+    }
+    /* Get the basename of the target */
+    if ((cp = strrchr(tname, '/')) == NULL) {
+       cp = tname;
+    } else {
+       cp++;
+    }
+
+    fflush(stdout);
+
+    if (strcmp(cp, makeDependfile) == 0)
+       goto out;
+
+    if (!writeMeta)
+       /* Don't create meta data. */
+       goto out;
+
+    fname = meta_name(gn, pbm->meta_fname, sizeof(pbm->meta_fname),
+                     dname, tname);
+
+#ifdef DEBUG_META_MODE
+    if (DEBUG(META))
+       fprintf(debug_file, "meta_create: %s\n", fname);
+#endif
+
+    if ((mf.fp = fopen(fname, "w")) == NULL)
+       err(1, "Could not open meta file '%s'", fname);
+
+    fprintf(mf.fp, "# Meta data file %s\n", fname);
+
+    mf.gn = gn;
+
+    Lst_ForEach(gn->commands, printCMD, &mf);
+
+    fprintf(mf.fp, "CWD %s\n", getcwd(buf, sizeof(buf)));
+    fprintf(mf.fp, "TARGET %s\n", tname);
+
+    if (metaEnv) {
+       for (ptr = environ; *ptr != NULL; ptr++)
+           fprintf(mf.fp, "ENV %s\n", *ptr);
+    }
+
+    fprintf(mf.fp, "-- command output --\n");
+    fflush(mf.fp);
+
+    Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL);
+    Var_Append(".MAKE.META.CREATED", fname, VAR_GLOBAL);
+
+    gn->type |= OP_META;               /* in case anyone wants to know */
+    if (metaSilent) {
+           gn->type |= OP_SILENT;
+    }
+ out:
+    for (i--; i >= 0; i--) {
+       if (p[i])
+           free(p[i]);
+    }
+
+    return (mf.fp);
+}
+
+static Boolean
+boolValue(char *s)
+{
+    switch(*s) {
+    case '0':
+    case 'N':
+    case 'n':
+    case 'F':
+    case 'f':
+       return FALSE;
+    }
+    return TRUE;
+}
+
+void
+meta_init(const char *make_mode)
+{
+    static int once = 0;
+    char *cp;
+
+    useMeta = TRUE;
+    useFilemon = TRUE;
+    writeMeta = TRUE;
+
+    if (make_mode) {
+       if (strstr(make_mode, "env"))
+           metaEnv = TRUE;
+       if (strstr(make_mode, "verb"))
+           metaVerbose = TRUE;
+       if (strstr(make_mode, "read"))
+           writeMeta = FALSE;
+       if (strstr(make_mode, "nofilemon"))
+           useFilemon = FALSE;
+       if ((cp = strstr(make_mode, "curdirok="))) {
+           metaCurdirOk = boolValue(&cp[9]);
+       }
+       if ((cp = strstr(make_mode, "silent="))) {
+           metaSilent = boolValue(&cp[7]);
+       }
+       if (strstr(make_mode, "ignore-cmd"))
+           metaIgnoreCMDs = TRUE;
+       /* for backwards compatability */
+       Var_Set(".MAKE.META_CREATED", "${.MAKE.META.CREATED}", VAR_GLOBAL, 0);
+       Var_Set(".MAKE.META_FILES", "${.MAKE.META.FILES}", VAR_GLOBAL, 0);
+    }
+    if (metaVerbose && !Var_Exists(MAKE_META_PREFIX, VAR_GLOBAL)) {
+       /*
+        * The default value for MAKE_META_PREFIX
+        * prints the absolute path of the target.
+        * This works be cause :H will generate '.' if there is no /
+        * and :tA will resolve that to cwd.
+        */
+       Var_Set(MAKE_META_PREFIX, "Building ${.TARGET:H:tA}/${.TARGET:T}", VAR_GLOBAL, 0);
+    }
+    if (once)
+       return;
+    once = 1;
+    memset(&Mybm, 0, sizeof(Mybm));
+    /*
+     * We consider ourselves master of all within ${.MAKE.META.BAILIWICK}
+     */
+    metaBailiwick = Lst_Init(FALSE);
+    cp = Var_Subst(NULL, "${.MAKE.META.BAILIWICK:O:u:tA}", VAR_GLOBAL, 0);
+    if (cp) {
+       str2Lst_Append(metaBailiwick, cp, NULL);
+    }
+}
+
+/*
+ * In each case below we allow for job==NULL
+ */
+void
+meta_job_start(Job *job, GNode *gn)
+{
+    BuildMon *pbm;
+
+    if (job != NULL) {
+       pbm = &job->bm;
+    } else {
+       pbm = &Mybm;
+    }
+    pbm->mfp = meta_create(pbm, gn);
+#ifdef USE_FILEMON_ONCE
+    /* compat mode we open the filemon dev once per command */
+    if (job == NULL)
+       return;
+#endif
+#ifdef USE_FILEMON
+    if (pbm->mfp != NULL && useFilemon) {
+       filemon_open(pbm);
+    } else {
+       pbm->mon_fd = pbm->filemon_fd = -1;
+    }
+#endif
+}
+
+/*
+ * The child calls this before doing anything.
+ * It does not disturb our state.
+ */
+void
+meta_job_child(Job *job)
+{
+#ifdef USE_FILEMON
+    BuildMon *pbm;
+    pid_t pid;
+
+    if (job != NULL) {
+       pbm = &job->bm;
+    } else {
+       pbm = &Mybm;
+    }
+    pid = getpid();
+    if (pbm->mfp != NULL && useFilemon) {
+       if (ioctl(pbm->filemon_fd, FILEMON_SET_PID, &pid) < 0) {
+           err(1, "Could not set filemon pid!");
+       }
+    }
+#endif
+}
+
+void
+meta_job_error(Job *job, GNode *gn, int flags, int status)
+{
+    char cwd[MAXPATHLEN];
+    BuildMon *pbm;
+
+    if (job != NULL) {
+       pbm = &job->bm;
+    } else {
+       if (!gn)
+           gn = job->node;
+       pbm = &Mybm;
+    }
+    if (pbm->mfp != NULL) {
+       fprintf(pbm->mfp, "*** Error code %d%s\n",
+               status,
+               (flags & JOB_IGNERR) ?
+               "(ignored)" : "");
+    }
+    if (gn) {
+       Var_Set(".ERROR_TARGET", gn->path ? gn->path : gn->name, VAR_GLOBAL, 0);
+    }
+    getcwd(cwd, sizeof(cwd));
+    Var_Set(".ERROR_CWD", cwd, VAR_GLOBAL, 0);
+    if (pbm && pbm->meta_fname[0]) {
+       Var_Set(".ERROR_META_FILE", pbm->meta_fname, VAR_GLOBAL, 0);
+    }
+    meta_job_finish(job);
+}
+
+void
+meta_job_output(Job *job, char *cp, const char *nl)
+{
+    BuildMon *pbm;
+    
+    if (job != NULL) {
+       pbm = &job->bm;
+    } else {
+       pbm = &Mybm;
+    }
+    if (pbm->mfp != NULL) {
+       if (metaVerbose) {
+           static char *meta_prefix = NULL;
+           static int meta_prefix_len;
+
+           if (!meta_prefix) {
+               char *cp2;
+
+               meta_prefix = Var_Subst(NULL, "${" MAKE_META_PREFIX "}", VAR_GLOBAL, 0);
+               if ((cp2 = strchr(meta_prefix, '$')))
+                   meta_prefix_len = cp2 - meta_prefix;
+               else
+                   meta_prefix_len = strlen(meta_prefix);
+           }
+           if (strncmp(cp, meta_prefix, meta_prefix_len) == 0) {
+               cp = strchr(cp+1, '\n');
+               if (!cp++)
+                   return;
+           }
+       }
+       fprintf(pbm->mfp, "%s%s", cp, nl);
+    }
+}
+
+void
+meta_cmd_finish(void *pbmp)
+{
+#ifdef USE_FILEMON
+    BuildMon *pbm = pbmp;
+
+    if (!pbm)
+       pbm = &Mybm;
+
+    if (pbm->filemon_fd >= 0) {
+       close(pbm->filemon_fd);
+       filemon_read(pbm->mfp, pbm->mon_fd);
+       pbm->filemon_fd = pbm->mon_fd = -1;
+    }
+#endif
+}
+
+void
+meta_job_finish(Job *job)
+{
+    BuildMon *pbm;
+
+    if (job != NULL) {
+       pbm = &job->bm;
+    } else {
+       pbm = &Mybm;
+    }
+    if (pbm->mfp != NULL) {
+       meta_cmd_finish(pbm);
+       fclose(pbm->mfp);
+       pbm->mfp = NULL;
+       pbm->meta_fname[0] = '\0';
+    }
+}
+
+/*
+ * Fetch a full line from fp - growing bufp if needed
+ * Return length in bufp.
+ */
+static int 
+fgetLine(char **bufp, size_t *szp, int o, FILE *fp)
+{
+    char *buf = *bufp;
+    size_t bufsz = *szp;
+    struct stat fs;
+    int x;
+
+    if (fgets(&buf[o], bufsz - o, fp) != NULL) {
+    check_newline:
+       x = o + strlen(&buf[o]);
+       if (buf[x - 1] == '\n')
+           return x;
+       /*
+        * We need to grow the buffer.
+        * The meta file can give us a clue.
+        */
+       if (fstat(fileno(fp), &fs) == 0) {
+           size_t newsz;
+           char *p;
+
+           newsz = ROUNDUP((fs.st_size / 2), BUFSIZ);
+           if (newsz <= bufsz)
+               newsz = ROUNDUP(fs.st_size, BUFSIZ);
+           if (DEBUG(META)) 
+               fprintf(debug_file, "growing buffer %zu -> %zu\n",
+                       bufsz, newsz);
+           p = bmake_realloc(buf, newsz);
+           if (p) {
+               *bufp = buf = p;
+               *szp = bufsz = newsz;
+               /* fetch the rest */
+               if (!fgets(&buf[x], bufsz - x, fp))
+                   return x;           /* truncated! */
+               goto check_newline;
+           }
+       }
+    }
+    return 0;
+}
+
+static int
+prefix_match(void *p, void *q)
+{
+    const char *prefix = p;
+    const char *path = q;
+    size_t n = strlen(prefix);
+
+    return (0 == strncmp(path, prefix, n));
+}
+
+static int
+string_match(const void *p, const void *q)
+{
+    const char *p1 = p;
+    const char *p2 = q;
+
+    return strcmp(p1, p2);
+}
+
+
+/*
+ * When running with 'meta' functionality, a target can be out-of-date
+ * if any of the references in it's meta data file is more recent.
+ * We have to track the latestdir on a per-process basis.
+ */
+#define LDIR_VNAME_FMT ".meta.%d.ldir"
+
+/*
+ * It is possible that a .meta file is corrupted,
+ * if we detect this we want to reproduce it.
+ * Setting oodate TRUE will have that effect.
+ */
+#define CHECK_VALID_META(p) if (!(p && *p)) { \
+    warnx("%s: %d: malformed", fname, lineno); \
+    oodate = TRUE; \
+    continue; \
+    }
+
+Boolean
+meta_oodate(GNode *gn, Boolean oodate)
+{
+    static char *tmpdir = NULL;
+    static char cwd[MAXPATHLEN];
+    char ldir_vname[64];
+    char latestdir[MAXPATHLEN];
+    char fname[MAXPATHLEN];
+    char fname1[MAXPATHLEN];
+    char fname2[MAXPATHLEN];
+    char *p;
+    char *cp;
+    static size_t cwdlen = 0;
+    static size_t tmplen = 0;
+    FILE *fp;
+    Boolean ignoreOODATE = FALSE;
+    Lst missingFiles;
+    
+    if (oodate)
+       return oodate;          /* we're done */
+
+    missingFiles = Lst_Init(FALSE);
+
+    /*
+     * We need to check if the target is out-of-date. This includes
+     * checking if the expanded command has changed. This in turn
+     * requires that all variables are set in the same way that they
+     * would be if the target needs to be re-built.
+     */
+    Make_DoAllVar(gn);
+
+    meta_name(gn, fname, sizeof(fname), NULL, NULL);
+
+#ifdef DEBUG_META_MODE
+    if (DEBUG(META))
+       fprintf(debug_file, "meta_oodate: %s\n", fname);
+#endif
+
+    if ((fp = fopen(fname, "r")) != NULL) {
+       static char *buf = NULL;
+       static size_t bufsz;
+       int lineno = 0;
+       int lastpid = 0;
+       int pid;
+       int f = 0;
+       int x;
+       LstNode ln;
+       struct stat fs;
+
+       if (!buf) {
+           bufsz = 8 * BUFSIZ;
+           buf = bmake_malloc(bufsz);
+       }
+
+       if (!cwdlen) {
+           if (getcwd(cwd, sizeof(cwd)) == NULL)
+               err(1, "Could not get current working directory");
+           cwdlen = strlen(cwd);
+       }
+
+       if (!tmpdir) {
+           tmpdir = getTmpdir();
+           tmplen = strlen(tmpdir);
+       }
+
+       /* we want to track all the .meta we read */
+       Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL);
+
+       ln = Lst_First(gn->commands);
+       while (!oodate && (x = fgetLine(&buf, &bufsz, 0, fp)) > 0) {
+           lineno++;
+           if (buf[x - 1] == '\n')
+               buf[x - 1] = '\0';
+           else {
+               warnx("%s: %d: line truncated at %u", fname, lineno, x);
+               oodate = TRUE;
+               break;
+           }
+           /* Find the start of the build monitor section. */
+           if (!f) {
+               if (strncmp(buf, "-- filemon", 10) == 0) {
+                   f = 1;
+                   continue;
+               }
+               if (strncmp(buf, "# buildmon", 10) == 0) {
+                   f = 1;
+                   continue;
+               }
+           }               
+
+           /* Delimit the record type. */
+           p = buf;
+#ifdef DEBUG_META_MODE
+           if (DEBUG(META))
+               fprintf(debug_file, "%s: %d: %s\n", fname, lineno, buf);
+#endif
+           strsep(&p, " ");
+           if (f) {
+               /*
+                * We are in the 'filemon' output section.
+                * Each record from filemon follows the general form:
+                *
+                * <key> <pid> <data>
+                *
+                * Where:
+                * <key> is a single letter, denoting the syscall.
+                * <pid> is the process that made the syscall.
+                * <data> is the arguments (of interest).
+                */
+               switch(buf[0]) {
+               case '#':               /* comment */
+               case 'V':               /* version */
+                   break;
+               default:
+                   /*
+                    * We need to track pathnames per-process.
+                    *
+                    * Each process run by make, starts off in the 'CWD'
+                    * recorded in the .meta file, if it chdirs ('C')
+                    * elsewhere we need to track that - but only for
+                    * that process.  If it forks ('F'), we initialize
+                    * the child to have the same cwd as its parent.
+                    *
+                    * We also need to track the 'latestdir' of
+                    * interest.  This is usually the same as cwd, but
+                    * not if a process is reading directories.
+                    *
+                    * Each time we spot a different process ('pid')
+                    * we save the current value of 'latestdir' in a
+                    * variable qualified by 'lastpid', and
+                    * re-initialize 'latestdir' to any pre-saved
+                    * value for the current 'pid' and 'CWD' if none.
+                    */
+                   CHECK_VALID_META(p);
+                   pid = atoi(p);
+                   if (pid > 0 && pid != lastpid) {
+                       char *ldir;
+                       char *tp;
+                   
+                       if (lastpid > 0) {
+                           /* We need to remember this. */
+                           Var_Set(ldir_vname, latestdir, VAR_GLOBAL, 0);
+                       }
+                       snprintf(ldir_vname, sizeof(ldir_vname), LDIR_VNAME_FMT, pid);
+                       lastpid = pid;
+                       ldir = Var_Value(ldir_vname, VAR_GLOBAL, &tp);
+                       if (ldir) {
+                           strlcpy(latestdir, ldir, sizeof(latestdir));
+                           if (tp)
+                               free(tp);
+                       } else 
+                           strlcpy(latestdir, cwd, sizeof(latestdir));
+                   }
+                   /* Skip past the pid. */
+                   if (strsep(&p, " ") == NULL)
+                       continue;
+#ifdef DEBUG_META_MODE
+                   if (DEBUG(META))
+                       fprintf(debug_file, "%s: %d: cwd=%s ldir=%s\n", fname, lineno, cwd, latestdir);
+#endif
+                   break;
+               }
+
+               CHECK_VALID_META(p);
+
+               /* Process according to record type. */
+               switch (buf[0]) {
+               case 'X':               /* eXit */
+                   Var_Delete(ldir_vname, VAR_GLOBAL);
+                   lastpid = 0;        /* no need to save ldir_vname */
+                   break;
+
+               case 'F':               /* [v]Fork */
+                   {
+                       char cldir[64];
+                       int child;
+
+                       child = atoi(p);
+                       if (child > 0) {
+                           snprintf(cldir, sizeof(cldir), LDIR_VNAME_FMT, child);
+                           Var_Set(cldir, latestdir, VAR_GLOBAL, 0);
+                       }
+                   }
+                   break;
+
+               case 'C':               /* Chdir */
+                   /* Update the latest directory. */
+                   strlcpy(latestdir, p, sizeof(latestdir));
+                   break;
+
+               case 'M':               /* renaMe */
+                   if (Lst_IsEmpty(missingFiles))
+                       break;
+                   /* 'L' and 'M' put single quotes around the args */
+                   if (*p == '\'') {
+                       char *ep;
+
+                       p++;
+                       if ((ep = strchr(p, '\'')))
+                           *ep = '\0';
+                   }
+                   /* FALLTHROUGH */
+               case 'D':               /* unlink */
+                   if (*p == '/' && !Lst_IsEmpty(missingFiles)) {
+                       /* remove p from the missingFiles list if present */
+                       if ((ln = Lst_Find(missingFiles, p, string_match)) != NULL) {
+                           char *tp = Lst_Datum(ln);
+                           Lst_Remove(missingFiles, ln);
+                           free(tp);
+                       }
+                   }
+                   break;
+               case 'L':               /* Link */
+                   /* we want the target */
+                   if (strsep(&p, " ") == NULL)
+                       continue;
+                   CHECK_VALID_META(p);
+                   /* 'L' and 'M' put single quotes around the args */
+                   if (*p == '\'') {
+                       char *ep;
+
+                       p++;
+                       if ((ep = strchr(p, '\'')))
+                           *ep = '\0';
+                   }
+                   /* FALLTHROUGH */
+               case 'W':               /* Write */
+                   /*
+                    * If a file we generated within our bailiwick
+                    * but outside of .OBJDIR is missing,
+                    * we need to do it again. 
+                    */
+                   /* ignore non-absolute paths */
+                   if (*p != '/')
+                       break;
+
+                   if (Lst_IsEmpty(metaBailiwick))
+                       break;
+
+                   /* ignore cwd - normal dependencies handle those */
+                   if (strncmp(p, cwd, cwdlen) == 0)
+                       break;
+
+                   if (!Lst_ForEach(metaBailiwick, prefix_match, p))
+                       break;
+
+                   /* tmpdir might be within */
+                   if (tmplen > 0 && strncmp(p, tmpdir, tmplen) == 0)
+                       break;
+
+                   /* ignore anything containing the string "tmp" */
+                   if ((strstr("tmp", p)))
+                       break;
+
+                   if (stat(p, &fs) < 0) {
+                       Lst_AtEnd(missingFiles, bmake_strdup(p));
+                   }
+                   break;
+               case 'R':               /* Read */
+               case 'E':               /* Exec */
+                   /*
+                    * Check for runtime files that can't
+                    * be part of the dependencies because
+                    * they are _expected_ to change.
+                    */
+                   if (strncmp(p, "/tmp/", 5) == 0 ||
+                       (tmplen > 0 && strncmp(p, tmpdir, tmplen) == 0))
+                       break;
+
+                   if (strncmp(p, "/var/", 5) == 0)
+                       break;
+
+                   /* Ignore device files. */
+                   if (strncmp(p, "/dev/", 5) == 0)
+                       break;
+
+                   /* Ignore /etc/ files. */
+                   if (strncmp(p, "/etc/", 5) == 0)
+                       break;
+
+                   if ((cp = strrchr(p, '/'))) {
+                       cp++;
+                       /*
+                        * We don't normally expect to see this,
+                        * but we do expect it to change.
+                        */
+                       if (strcmp(cp, makeDependfile) == 0)
+                           break;
+                   }
+
+                   /*
+                    * The rest of the record is the file name.
+                    * Check if it's not an absolute path.
+                    */
+                   {
+                       char *sdirs[4];
+                       char **sdp;
+                       int sdx = 0;
+                       int found = 0;
+
+                       if (*p == '/') {
+                           sdirs[sdx++] = p; /* done */
+                       } else {
+                           if (strcmp(".", p) == 0)
+                               continue;  /* no point */
+
+                           /* Check vs latestdir */
+                           snprintf(fname1, sizeof(fname1), "%s/%s", latestdir, p);
+                           sdirs[sdx++] = fname1;
+
+                           if (strcmp(latestdir, cwd) != 0) {
+                               /* Check vs cwd */
+                               snprintf(fname2, sizeof(fname2), "%s/%s", cwd, p);
+                               sdirs[sdx++] = fname2;
+                           }
+                       }
+                       sdirs[sdx++] = NULL;
+
+                       for (sdp = sdirs; *sdp && !found; sdp++) {
+#ifdef DEBUG_META_MODE
+                           if (DEBUG(META))
+                               fprintf(debug_file, "%s: %d: looking for: %s\n", fname, lineno, *sdp);
+#endif
+                           if (stat(*sdp, &fs) == 0) {
+                               found = 1;
+                               p = *sdp;
+                           }
+                       }
+                       if (found) {
+#ifdef DEBUG_META_MODE
+                           if (DEBUG(META))
+                               fprintf(debug_file, "%s: %d: found: %s\n", fname, lineno, p);
+#endif
+                           if (!S_ISDIR(fs.st_mode) &&
+                               fs.st_mtime > gn->mtime) {
+                               if (DEBUG(META))
+                                   fprintf(debug_file, "%s: %d: file '%s' is newer than the target...\n", fname, lineno, p);
+                               oodate = TRUE;
+                           } else if (S_ISDIR(fs.st_mode)) {
+                               /* Update the latest directory. */
+                               realpath(p, latestdir);
+                           }
+                       } else if (errno == ENOENT && *p == '/' &&
+                                  strncmp(p, cwd, cwdlen) != 0) {
+                           /*
+                            * A referenced file outside of CWD is missing.
+                            * We cannot catch every eventuality here...
+                            */
+                           if (DEBUG(META))
+                               fprintf(debug_file, "%s: %d: file '%s' may have moved?...\n", fname, lineno, p);
+                           oodate = TRUE;
+                       }
+                   }
+                   break;
+               default:
+                   break;
+               }
+           } else if (strcmp(buf, "CMD") == 0) {
+               /*
+                * Compare the current command with the one in the
+                * meta data file.
+                */
+               if (ln == NULL) {
+                   if (DEBUG(META))
+                       fprintf(debug_file, "%s: %d: there were more build commands in the meta data file than there are now...\n", fname, lineno);
+                   oodate = TRUE;
+               } else {
+                   char *cmd = (char *)Lst_Datum(ln);
+
+                   if (!ignoreOODATE) {
+                       if (strstr(cmd, "$?"))
+                           ignoreOODATE = TRUE;
+                       else if ((cp = strstr(cmd, ".OODATE"))) {
+                           /* check for $[{(].OODATE[)}] */
+                           if (cp > cmd + 2 && cp[-2] == '$')
+                               ignoreOODATE = TRUE;
+                       }
+                       if (ignoreOODATE && DEBUG(META))
+                           fprintf(debug_file, "%s: %d: cannot compare commands using .OODATE\n", fname, lineno);
+                   }
+                   cmd = Var_Subst(NULL, cmd, gn, TRUE);
+
+                   if ((cp = strchr(cmd, '\n'))) {
+                       int n;
+
+                       /*
+                        * This command contains newlines, we need to
+                        * fetch more from the .meta file before we
+                        * attempt a comparison.
+                        */
+                       /* first put the newline back at buf[x - 1] */
+                       buf[x - 1] = '\n';
+                       do {
+                           /* now fetch the next line */
+                           if ((n = fgetLine(&buf, &bufsz, x, fp)) <= 0)
+                               break;
+                           x = n;
+                           lineno++;
+                           if (buf[x - 1] != '\n') {
+                               warnx("%s: %d: line truncated at %u", fname, lineno, x);
+                               break;
+                           }
+                           cp = strchr(++cp, '\n');
+                       } while (cp);
+                       if (buf[x - 1] == '\n')
+                           buf[x - 1] = '\0';
+                   }
+                   if (!ignoreOODATE &&
+                       !(gn->type & OP_NOMETA_CMP) &&
+                       strcmp(p, cmd) != 0) {
+                       if (DEBUG(META))
+                           fprintf(debug_file, "%s: %d: a build command has changed\n%s\nvs\n%s\n", fname, lineno, p, cmd);
+                       if (!metaIgnoreCMDs)
+                           oodate = TRUE;
+                   }
+                   free(cmd);
+                   ln = Lst_Succ(ln);
+               }
+           } else if (strcmp(buf, "CWD") == 0) {
+               /*
+                * Check if there are extra commands now
+                * that weren't in the meta data file.
+                */
+               if (!oodate && ln != NULL) {
+                   if (DEBUG(META))
+                       fprintf(debug_file, "%s: %d: there are extra build commands now that weren't in the meta data file\n", fname, lineno);
+                   oodate = TRUE;
+               }
+               if (strcmp(p, cwd) != 0) {
+                   if (DEBUG(META))
+                       fprintf(debug_file, "%s: %d: the current working directory has changed from '%s' to '%s'\n", fname, lineno, p, curdir);
+                   oodate = TRUE;
+               }
+           }
+       }
+
+       fclose(fp);
+       if (!Lst_IsEmpty(missingFiles)) {
+           if (DEBUG(META))
+               fprintf(debug_file, "%s: missing files: %s...\n",
+                       fname, (char *)Lst_Datum(Lst_First(missingFiles)));
+           oodate = TRUE;
+           Lst_Destroy(missingFiles, (FreeProc *)free);
+       }
+    } else {
+       if ((gn->type & OP_META)) {
+           if (DEBUG(META))
+               fprintf(debug_file, "%s: required but missing\n", fname);
+           oodate = TRUE;
+       }
+    }
+    if (oodate && ignoreOODATE) {
+       /*
+        * Target uses .OODATE, so we need to re-compute it.
+        * We need to clean up what Make_DoAllVar() did.
+        */
+       Var_Delete(ALLSRC, gn);
+       Var_Delete(OODATE, gn);
+       gn->flags &= ~DONE_ALLSRC;
+    }
+    return oodate;
+}
+
+/* support for compat mode */
+
+static int childPipe[2];
+
+void
+meta_compat_start(void)
+{
+#ifdef USE_FILEMON_ONCE
+    /*
+     * We need to re-open filemon for each cmd.
+     */
+    BuildMon *pbm = &Mybm;
+    
+    if (pbm->mfp != NULL && useFilemon) {
+       filemon_open(pbm);
+    } else {
+       pbm->mon_fd = pbm->filemon_fd = -1;
+    }
+#endif
+    if (pipe(childPipe) < 0)
+       Punt("Cannot create pipe: %s", strerror(errno));
+    /* Set close-on-exec flag for both */
+    (void)fcntl(childPipe[0], F_SETFD, 1);
+    (void)fcntl(childPipe[1], F_SETFD, 1);
+}
+
+void
+meta_compat_child(void)
+{
+    meta_job_child(NULL);
+    if (dup2(childPipe[1], 1) < 0 ||
+       dup2(1, 2) < 0) {
+       execError("dup2", "pipe");
+       _exit(1);
+    }
+}
+
+void
+meta_compat_parent(void)
+{
+    FILE *fp;
+    char buf[BUFSIZ];
+    
+    close(childPipe[1]);                       /* child side */
+    fp = fdopen(childPipe[0], "r");
+    while (fgets(buf, sizeof(buf), fp)) {
+       meta_job_output(NULL, buf, "");
+       printf("%s", buf);
+    }
+    fclose(fp);
+}
+
+#endif /* USE_META */
diff --git a/usr.bin/make/meta.h b/usr.bin/make/meta.h
new file mode 100644 (file)
index 0000000..1ce01ca
--- /dev/null
@@ -0,0 +1,54 @@
+/*      $NetBSD: meta.h,v 1.2 2011/03/30 22:03:49 sjg Exp $ */
+
+/*
+ * Things needed for 'meta' mode.
+ */
+/*
+ * Copyright (c) 2009-2010, Juniper Networks, Inc.
+ * 
+ * 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 copyright holders 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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. 
+ */
+
+typedef struct BuildMon {
+    char       meta_fname[MAXPATHLEN];
+    int                filemon_fd;
+    int                mon_fd;
+    FILE       *mfp;
+} BuildMon;
+
+extern Boolean useMeta;
+
+struct Job;                            /* not defined yet */
+void meta_init(const char *);
+void meta_job_start(struct Job *, GNode *);
+void meta_job_child(struct Job *);
+void meta_job_error(struct Job *, GNode *, int, int);
+void meta_job_output(struct Job *, char *, const char *);
+void meta_cmd_finish(void *);
+void meta_job_finish(struct Job *);
+Boolean meta_oodate(GNode *, Boolean);
+void meta_compat_start(void);
+void meta_compat_child(void);
+void meta_compat_parent(void);
similarity index 96%
rename from commands/make/nonints.h
rename to usr.bin/make/nonints.h
index f49759a708ce95bed5dd814b40d4a1903269da1e..5050e2a9cff6c539b69d4eee21269fda0580be60 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: nonints.h,v 1.59 2010/06/03 15:40:16 sjg Exp $ */
+/*     $NetBSD: nonints.h,v 1.63 2011/09/16 15:38:04 joerg Exp $       */
 
 /*-
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -106,6 +106,9 @@ int For_Eval(char *);
 int For_Accum(char *);
 void For_Run(int);
 
+/* job.c */
+void JobReapChild(pid_t, int, Boolean);
+
 /* main.c */
 void Main_ParseArgLine(const char *);
 void MakeMode(const char *);
@@ -118,9 +121,10 @@ void Punt(const char *, ...)
     __attribute__((__format__(__printf__, 1, 2),__noreturn__));
 void DieHorribly(void) __attribute__((__noreturn__));
 int PrintAddr(void *, void *);
-void Finish(int);
+void Finish(int) __dead;
 int eunlink(const char *);
 void execError(const char *, const char *);
+char *getTmpdir(void);
 
 /* parse.c */
 void Parse_Error(int, const char *, ...)
@@ -132,7 +136,7 @@ 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 *), void *);
+void Parse_SetInput(const char *, int, int, char *(*)(void *, size_t *), void *);
 Lst Parse_MainName(void);
 
 /* str.c */
similarity index 87%
rename from commands/make/parse.c
rename to usr.bin/make/parse.c
index 7c6538e096f3c730c3df0ed1a5a231bb5940b7a9..ade5278374a248b605110d9afc0e8bed4e7c6c37 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: parse.c,v 1.164 2010/05/24 21:04:49 sjg Exp $  */
+/*     $NetBSD: parse.c,v 1.182 2012/03/31 00:12:24 christos Exp $     */
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: parse.c,v 1.164 2010/05/24 21:04:49 sjg Exp $";
+static char rcsid[] = "$NetBSD: parse.c,v 1.182 2012/03/31 00:12:24 christos Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)parse.c    8.3 (Berkeley) 3/19/94";
 #else
-__RCSID("$NetBSD: parse.c,v 1.164 2010/05/24 21:04:49 sjg Exp $");
+__RCSID("$NetBSD: parse.c,v 1.182 2012/03/31 00:12:24 christos Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -123,12 +123,23 @@ __RCSID("$NetBSD: parse.c,v 1.164 2010/05/24 21:04:49 sjg Exp $");
  *     Parse_MainName              Returns a Lst of the main target to create.
  */
 
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <stdio.h>
 
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+#ifndef MAP_COPY
+#define MAP_COPY MAP_PRIVATE
+#endif
+
 #include "make.h"
 #include "hash.h"
 #include "dir.h"
@@ -136,56 +147,36 @@ __RCSID("$NetBSD: parse.c,v 1.164 2010/05/24 21:04:49 sjg Exp $");
 #include "buf.h"
 #include "pathnames.h"
 
+////////////////////////////////////////////////////////////
+// types and constants
+
 /*
- * These values are returned by ParseEOF to tell Parse_File whether to
- * CONTINUE parsing, i.e. it had only reached the end of an include file,
- * or if it's DONE.
+ * Structure for a file being read ("included file")
  */
-#define        CONTINUE        1
-#define        DONE            0
-static Lst                 targets;    /* targets we're working on */
-#ifdef CLEANUP
-static Lst                 targCmds;   /* command lines for targets */
-#endif
-static Boolean     inLine;     /* true if currently in a dependency
-                                * line or its commands */
-static int         fatals = 0;
-
-static GNode       *mainNode;  /* The main target to create. This is the
-                                * first target on the first dependency
-                                * line in the first makefile */
 typedef struct IFile {
     const char      *fname;         /* name of file */
     int             lineno;         /* current line number in file */
     int             first_lineno;   /* line number of start of text */
-    int             fd;             /* the open file */
     int             cond_depth;     /* 'if' nesting when file opened */
     char            *P_str;         /* point to base of string buffer */
     char            *P_ptr;         /* point to next char of string buffer */
     char            *P_end;         /* point to the end of string buffer */
-    int             P_buflen;       /* current size of file buffer */
-    char            *(*nextbuf)(void *); /* Function to get more data */
+    char            *(*nextbuf)(void *, size_t *); /* Function to get more data */
     void            *nextbuf_arg;   /* Opaque arg for nextbuf() */
+    struct loadedfile *lf;          /* loadedfile object, if any */
 } IFile;
 
-#define IFILE_BUFLEN 0x8000
-static IFile       *curFile;
-
 
 /*
- * Definitions for handling #include specifications
+ * These values are returned by ParseEOF to tell Parse_File whether to
+ * CONTINUE parsing, i.e. it had only reached the end of an include file,
+ * or if it's DONE.
  */
+#define CONTINUE       1
+#define DONE           0
 
-static Lst      includes;      /* stack of IFiles generated by .includes */
-Lst            parseIncPath;   /* list of directories for "..." includes */
-Lst            sysIncPath;     /* list of directories for <...> includes */
-Lst            defIncPath;     /* default directories for <...> includes */
-
-/*-
- * specType contains the SPECial TYPE of the current target. It is
- * Not if the target is unspecial. If it *is* special, however, the children
- * are linked as children of the parent but not vice versa. This variable is
- * set in ParseDoDependency
+/*
+ * Tokens for target attributes
  */
 typedef enum {
     Begin,         /* .BEGIN */
@@ -196,10 +187,13 @@ typedef enum {
     Includes,      /* .INCLUDES */
     Interrupt,     /* .INTERRUPT */
     Libs,          /* .LIBS */
+    Meta,          /* .META */
     MFlags,        /* .MFLAGS or .MAKEFLAGS */
     Main,          /* .MAIN and we don't have anything user-specified to
                     * make */
     NoExport,      /* .NOEXPORT */
+    NoMeta,        /* .NOMETA */
+    NoMetaCmp,     /* .NOMETA_CMP */
     NoPath,        /* .NOPATH */
     Not,           /* Not special */
     NotParallel,    /* .NOTPARALLEL */
@@ -221,16 +215,74 @@ typedef enum {
     Attribute      /* Generic attribute */
 } ParseSpecial;
 
+/*
+ * Other tokens
+ */
+#define LPAREN '('
+#define RPAREN ')'
+
+
+////////////////////////////////////////////////////////////
+// result data
+
+/*
+ * The main target to create. This is the first target on the first
+ * dependency line in the first makefile.
+ */
+static GNode *mainNode;
+
+////////////////////////////////////////////////////////////
+// eval state
+
+/* targets we're working on */
+static Lst targets;
+
+#ifdef CLEANUP
+/* command lines for targets */
+static Lst targCmds;
+#endif
+
+/*
+ * specType contains the SPECial TYPE of the current target. It is
+ * Not if the target is unspecial. If it *is* special, however, the children
+ * are linked as children of the parent but not vice versa. This variable is
+ * set in ParseDoDependency
+ */
 static ParseSpecial specType;
 
-#define        LPAREN  '('
-#define        RPAREN  ')'
 /*
  * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER
  * seen, then set to each successive source on the line.
  */
 static GNode   *predecessor;
 
+////////////////////////////////////////////////////////////
+// parser state
+
+/* true if currently in a dependency line or its commands */
+static Boolean inLine;
+
+/* number of fatal errors */
+static int fatals = 0;
+
+/*
+ * Variables for doing includes
+ */
+
+/* current file being read */
+static IFile *curFile;
+
+/* stack of IFiles generated by .includes */
+static Lst includes;
+
+/* include paths (lists of directories) */
+Lst parseIncPath;      /* dirs for "..." includes */
+Lst sysIncPath;                /* dirs for <...> includes */
+Lst defIncPath;                /* default for sysIncPath */
+
+////////////////////////////////////////////////////////////
+// parser tables
+
 /*
  * The parseKeywords table is searched using binary search when deciding
  * if a target or source is special. The 'spec' field is the ParseSpecial
@@ -238,7 +290,7 @@ static GNode        *predecessor;
  * the 'op' field is the operator to apply to the list of targets if the
  * keyword is used as a source ("0" if the keyword isn't special as a source)
  */
-static struct {
+static const struct {
     const char   *name;        /* Name of keyword */
     ParseSpecial  spec;                /* Type when used as a target */
     int                  op;           /* Operator when used as a source */
@@ -258,7 +310,10 @@ static struct {
 { ".MAIN",       Main,         0 },
 { ".MAKE",       Attribute,    OP_MAKE },
 { ".MAKEFLAGS",          MFlags,       0 },
+{ ".META",       Meta,         OP_META },
 { ".MFLAGS",     MFlags,       0 },
+{ ".NOMETA",     NoMeta,       OP_NOMETA },
+{ ".NOMETA_CMP",  NoMetaCmp,   OP_NOMETA_CMP },
 { ".NOPATH",     NoPath,       OP_NOPATH },
 { ".NOTMAIN",    Attribute,    OP_NOTMAIN },
 { ".NOTPARALLEL", NotParallel, 0 },
@@ -284,6 +339,9 @@ static struct {
 { ".WAIT",       Wait,         0 },
 };
 
+////////////////////////////////////////////////////////////
+// local functions
+
 static int ParseIsEscaped(const char *, const char *);
 static void ParseErrorInternal(const char *, size_t, int, const char *, ...)
      __attribute__((__format__(__printf__, 4, 5)));
@@ -304,13 +362,220 @@ static void ParseSetParseFile(const char *);
 #ifdef SYSVINCLUDE
 static void ParseTraditionalInclude(char *);
 #endif
+#ifdef GMAKEEXPORT
+static void ParseGmakeExport(char *);
+#endif
 static int ParseEOF(void);
 static char *ParseReadLine(void);
 static void ParseFinishLine(void);
 static void ParseMark(GNode *);
 
-extern int  maxJobs;
+////////////////////////////////////////////////////////////
+// file loader
+
+struct loadedfile {
+       const char *path;               /* name, for error reports */
+       char *buf;                      /* contents buffer */
+       size_t len;                     /* length of contents */
+       size_t maplen;                  /* length of mmap area, or 0 */
+       Boolean used;                   /* XXX: have we used the data yet */
+};
+
+/*
+ * Constructor/destructor for loadedfile
+ */
+static struct loadedfile *
+loadedfile_create(const char *path)
+{
+       struct loadedfile *lf;
+
+       lf = bmake_malloc(sizeof(*lf));
+       lf->path = (path == NULL ? "(stdin)" : path);
+       lf->buf = NULL;
+       lf->len = 0;
+       lf->maplen = 0;
+       lf->used = FALSE;
+       return lf;
+}
+
+static void
+loadedfile_destroy(struct loadedfile *lf)
+{
+       if (lf->buf != NULL) {
+               if (lf->maplen > 0) {
+#ifndef __minix
+                       munmap(lf->buf, lf->maplen);
+#endif
+               } else {
+                       free(lf->buf);
+               }
+       }
+       free(lf);
+}
+
+/*
+ * nextbuf() operation for loadedfile, as needed by the weird and twisted
+ * logic below. Once that's cleaned up, we can get rid of lf->used...
+ */
+static char *
+loadedfile_nextbuf(void *x, size_t *len)
+{
+       struct loadedfile *lf = x;
+
+       if (lf->used) {
+               return NULL;
+       }
+       lf->used = TRUE;
+       *len = lf->len;
+       return lf->buf;
+}
+
+/*
+ * Try to get the size of a file.
+ */
+static ReturnStatus
+load_getsize(int fd, size_t *ret)
+{
+       struct stat st;
+
+       if (fstat(fd, &st) < 0) {
+               return FAILURE;
+       }
+
+       if (!S_ISREG(st.st_mode)) {
+               return FAILURE;
+       }
+
+       /*
+        * st_size is an off_t, which is 64 bits signed; *ret is
+        * size_t, which might be 32 bits unsigned or 64 bits
+        * unsigned. Rather than being elaborate, just punt on
+        * files that are more than 2^31 bytes. We should never
+        * see a makefile that size in practice...
+        *
+        * While we're at it reject negative sizes too, just in case.
+        */
+       if (st.st_size < 0 || st.st_size > 0x7fffffff) {
+               return FAILURE;
+       }
+
+       *ret = (size_t) st.st_size;
+       return SUCCESS;
+}
+
+/*
+ * Read in a file.
+ *
+ * Until the path search logic can be moved under here instead of
+ * being in the caller in another source file, we need to have the fd
+ * passed in already open. Bleh.
+ *
+ * If the path is NULL use stdin and (to insure against fd leaks)
+ * assert that the caller passed in -1.
+ */
+static struct loadedfile *
+loadfile(const char *path, int fd)
+{
+       struct loadedfile *lf;
+       long pagesize;
+       ssize_t result;
+       size_t bufpos;
+
+       lf = loadedfile_create(path);
+
+       if (path == NULL) {
+               assert(fd == -1);
+               fd = STDIN_FILENO;
+       } else {
+#if 0 /* notyet */
+               fd = open(path, O_RDONLY);
+               if (fd < 0) {
+                       ...
+                       Error("%s: %s", path, strerror(errno));
+                       exit(1);
+               }
+#endif
+       }
+
+#ifndef __minix
+       if (load_getsize(fd, &lf->len) == SUCCESS) {
+               /* found a size, try mmap */
+               pagesize = sysconf(_SC_PAGESIZE);
+               if (pagesize <= 0) {
+                       pagesize = 0x1000;
+               }
+               /* round size up to a page */
+               lf->maplen = pagesize * ((lf->len + pagesize - 1)/pagesize);
+
+               /*
+                * XXX hack for dealing with empty files; remove when
+                * we're no longer limited by interfacing to the old
+                * logic elsewhere in this file.
+                */
+               if (lf->maplen == 0) {
+                       lf->maplen = pagesize;
+               }
+
+               /*
+                * FUTURE: remove PROT_WRITE when the parser no longer
+                * needs to scribble on the input.
+                */
+               lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE,
+                              MAP_FILE|MAP_COPY, fd, 0);
+               if (lf->buf != MAP_FAILED) {
+                       /* succeeded */
+                       if (lf->len == lf->maplen && lf->buf[lf->len - 1] != '\n') {
+                               char *b = malloc(lf->len + 1);
+                               b[lf->len] = '\n';
+                               memcpy(b, lf->buf, lf->len++);
+                               munmap(lf->buf, lf->maplen);
+                               lf->maplen = 0;
+                               lf->buf = b;
+                       }
+                       goto done;
+               }
+       }
+#endif
+       /* cannot mmap; load the traditional way */
+
+       lf->maplen = 0;
+       lf->len = 1024;
+       lf->buf = bmake_malloc(lf->len);
+
+       bufpos = 0;
+       while (1) {
+               assert(bufpos <= lf->len);
+               if (bufpos == lf->len) {
+                       lf->len *= 2;
+                       lf->buf = bmake_realloc(lf->buf, lf->len);
+               }
+               result = read(fd, lf->buf + bufpos, lf->len - bufpos);
+               if (result < 0) {
+                       Error("%s: read error: %s", path, strerror(errno));
+                       exit(1);
+               }
+               if (result == 0) {
+                       break;
+               }
+               bufpos += result;
+       }
+       assert(bufpos <= lf->len);
+       lf->len = bufpos;
+
+       /* truncate malloc region to actual length (maybe not useful) */
+       if (lf->len > 0) {
+               lf->buf = bmake_realloc(lf->buf, lf->len);
+       }
+
+done:
+       if (path != NULL) {
+               close(fd);
+       }
+       return lf;
+}
 
+////////////////////////////////////////////////////////////
+// old code
 
 /*-
  *----------------------------------------------------------------------
@@ -404,7 +669,7 @@ ParseVErrorInternal(FILE *f, const char *cfname, size_t clineno, int type,
                        const char *dir;
 
                        /*
-                        * Nothing is more anoying than not knowing
+                        * Nothing is more annoying than not knowing
                         * which Makefile is the culprit.
                         */
                        dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &cp);
@@ -915,7 +1180,7 @@ ParseDoDependency(char *line)
     tOp = 0;
 
     specType = Not;
-    paths = (Lst)NULL;
+    paths = NULL;
 
     curTargs = Lst_Init(FALSE);
 
@@ -1085,7 +1350,7 @@ ParseDoDependency(char *line)
                                 &line[5]);
                    goto out;
                } else {
-                   if (paths == (Lst)NULL) {
+                   if (paths == NULL) {
                        paths = Lst_Init(FALSE);
                    }
                    (void)Lst_AtEnd(paths, path);
@@ -1786,6 +2051,7 @@ Parse_AddIncludeDir(char *dir)
 static void
 Parse_include_file(char *file, Boolean isSystem, int silent)
 {
+    struct loadedfile *lf;
     char          *fullname;   /* full pathname of file */
     char          *newName;
     char          *prefEnd, *incdir;
@@ -1876,8 +2142,12 @@ Parse_include_file(char *file, Boolean isSystem, int silent)
        return;
     }
 
+    /* load it */
+    lf = loadfile(fullname, fd);
+
     /* Start reading from this file next */
-    Parse_SetInput(fullname, 0, fd, NULL, NULL);
+    Parse_SetInput(fullname, 0, -1, loadedfile_nextbuf, lf);
+    curFile->lf = lf;
 }
 
 static void
@@ -1949,23 +2219,27 @@ ParseDoInclude(char *line)
 static void
 ParseSetParseFile(const char *filename)
 {
-    char *slash;
-    char *dirname;
+    char *slash, *dirname;
+    const char *pd, *pf;
     int len;
 
     slash = strrchr(filename, '/');
     if (slash == NULL) {
-       Var_Set(".PARSEDIR", ".", VAR_GLOBAL, 0);
-       Var_Set(".PARSEFILE", filename, VAR_GLOBAL, 0);
+       Var_Set(".PARSEDIR", pd = curdir, VAR_GLOBAL, 0);
+       Var_Set(".PARSEFILE", pf = filename, VAR_GLOBAL, 0);
+       dirname= NULL;
     } else {
        len = slash - filename;
        dirname = bmake_malloc(len + 1);
        memcpy(dirname, filename, len);
-       dirname[len] = 0;
-       Var_Set(".PARSEDIR", dirname, VAR_GLOBAL, 0);
-       Var_Set(".PARSEFILE", slash+1, VAR_GLOBAL, 0);
-       free(dirname);
+       dirname[len] = '\0';
+       Var_Set(".PARSEDIR", pd = dirname, VAR_GLOBAL, 0);
+       Var_Set(".PARSEFILE", pf = slash + 1, VAR_GLOBAL, 0);
     }
+    if (DEBUG(PARSE))
+       fprintf(debug_file, "ParseSetParseFile: ${.PARSEDIR} = `%s' "
+           "${.PARSEFILE} = `%s'\n", pd, pf);
+    free(dirname);
 }
 
 /*
@@ -2014,9 +2288,11 @@ ParseTrackInput(const char *name)
  *---------------------------------------------------------------------
  */
 void
-Parse_SetInput(const char *name, int line, int fd, char *(*nextbuf)(void *), void *arg)
+Parse_SetInput(const char *name, int line, int fd,
+       char *(*nextbuf)(void *, size_t *), void *arg)
 {
     char *buf;
+    size_t len;
 
     if (name == NULL)
        name = curFile->fname;
@@ -2047,33 +2323,22 @@ Parse_SetInput(const char *name, int line, int fd, char *(*nextbuf)(void *), voi
     curFile->fname = name;
     curFile->lineno = line;
     curFile->first_lineno = line;
-    curFile->fd = fd;
     curFile->nextbuf = nextbuf;
     curFile->nextbuf_arg = arg;
+    curFile->lf = NULL;
 
-    if (nextbuf == NULL) {
-       /*
-        * Allocate a 32k data buffer (as stdio seems to).
-        * Set pointers so that first ParseReadc has to do a file read.
-        */
-       buf = bmake_malloc(IFILE_BUFLEN);
-       buf[0] = 0;
-       curFile->P_str = buf;
-       curFile->P_ptr = buf;
-       curFile->P_end = buf;
-       curFile->P_buflen = IFILE_BUFLEN;
-    } else {
-       /* Get first block of input data */
-       buf = curFile->nextbuf(curFile->nextbuf_arg);
-       if (buf == NULL) {
-           /* Was all a waste of time ... */
-           free(curFile);
-           return;
-       }
-       curFile->P_str = buf;
-       curFile->P_ptr = buf;
-       curFile->P_end = NULL;
+    assert(nextbuf != NULL);
+
+    /* Get first block of input data */
+    buf = curFile->nextbuf(curFile->nextbuf_arg, &len);
+    if (buf == NULL) {
+        /* Was all a waste of time ... */
+       free(curFile);
+       return;
     }
+    curFile->P_str = buf;
+    curFile->P_ptr = buf;
+    curFile->P_end = buf+len;
 
     curFile->cond_depth = Cond_save_depth();
     ParseSetParseFile(name);
@@ -2143,6 +2408,55 @@ ParseTraditionalInclude(char *line)
 }
 #endif
 
+#ifdef SYSVINCLUDE
+/*-
+ *---------------------------------------------------------------------
+ * ParseGmakeExport  --
+ *     Parse export <variable>=<value>
+ *
+ *     And set the environment with it.
+ *
+ * Results:
+ *     None
+ *
+ * Side Effects:
+ *     None
+ *---------------------------------------------------------------------
+ */
+static void
+ParseGmakeExport(char *line)
+{
+    char         *variable = &line[6];
+    char         *value;
+
+    if (DEBUG(PARSE)) {
+           fprintf(debug_file, "ParseTraditionalInclude: %s\n", variable);
+    }
+
+    /*
+     * Skip over whitespace
+     */
+    while (isspace((unsigned char)*variable))
+       variable++;
+
+    for (value = variable; *value && *value != '='; value++)
+       continue;
+
+    if (*value != '=') {
+       Parse_Error(PARSE_FATAL,
+                    "Variable/Value missing from \"include\"");
+       return;
+    }
+
+    /*
+     * Substitute for any variables in the file name before trying to
+     * find the thing.
+     */
+    value = Var_Subst(NULL, value, VAR_CMD, FALSE);
+    setenv(variable, value, 1);
+}
+#endif
+
 /*-
  *---------------------------------------------------------------------
  * ParseEOF  --
@@ -2162,26 +2476,31 @@ static int
 ParseEOF(void)
 {
     char *ptr;
-
-    if (curFile->nextbuf != NULL) {
-       /* eg .for loop data, get next iteration */
-       ptr = curFile->nextbuf(curFile->nextbuf_arg);
-       curFile->P_ptr = ptr;
-       curFile->P_str = ptr;
-       curFile->lineno = curFile->first_lineno;
-       if (ptr != NULL) {
-           /* Iterate again */
-           return CONTINUE;
-       }
+    size_t len;
+
+    assert(curFile->nextbuf != NULL);
+
+    /* get next input buffer, if any */
+    ptr = curFile->nextbuf(curFile->nextbuf_arg, &len);
+    curFile->P_ptr = ptr;
+    curFile->P_str = ptr;
+    curFile->P_end = ptr + len;
+    curFile->lineno = curFile->first_lineno;
+    if (ptr != NULL) {
+       /* Iterate again */
+       return CONTINUE;
     }
 
     /* Ensure the makefile (or loop) didn't have mismatched conditionals */
     Cond_restore_depth(curFile->cond_depth);
 
+    if (curFile->lf != NULL) {
+           loadedfile_destroy(curFile->lf);
+           curFile->lf = NULL;
+    }
+
     /* Dispose of curFile info */
     /* Leak curFile->fname because all the gnodes have pointers to it */
-    if (curFile->fd != -1)
-       close(curFile->fd);
     free(curFile->P_str);
     free(curFile);
 
@@ -2195,8 +2514,8 @@ ParseEOF(void)
     }
 
     if (DEBUG(PARSE))
-       fprintf(debug_file, "ParseEOF: returning to file %s, line %d, fd %d\n",
-           curFile->fname, curFile->lineno, curFile->fd);
+       fprintf(debug_file, "ParseEOF: returning to file %s, line %d\n",
+           curFile->fname, curFile->lineno);
 
     /* Restore the PARSEDIR/PARSEFILE variables */
     ParseSetParseFile(curFile->fname);
@@ -2217,7 +2536,6 @@ ParseGetLine(int flags, int *length)
     char *escaped;
     char *comment;
     char *tp;
-    int len, dist;
 
     /* Loop through blank lines and comment lines */
     for (;;) {
@@ -2228,67 +2546,25 @@ ParseGetLine(int flags, int *length)
        escaped = NULL;
        comment = NULL;
        for (;;) {
+           if (cf->P_end != NULL && ptr == cf->P_end) {
+               /* end of buffer */
+               ch = 0;
+               break;
+           }
            ch = *ptr;
            if (ch == 0 || (ch == '\\' && ptr[1] == 0)) {
                if (cf->P_end == NULL)
                    /* End of string (aka for loop) data */
                    break;
-               /* End of data read from file, read more data */
-               if (ptr != cf->P_end && (ch != '\\' || ptr + 1 != cf->P_end)) {
-                   Parse_Error(PARSE_FATAL, "Zero byte read from file");
-                   return NULL;
-               }
-               /* Move existing data to (near) start of file buffer */
-               len = cf->P_end - cf->P_ptr;
-               tp = cf->P_str + 32;
-               memmove(tp, cf->P_ptr, len);
-               dist = cf->P_ptr - tp;
-               /* Update all pointers to reflect moved data */
-               ptr -= dist;
-               line -= dist;
-               line_end -= dist;
-               if (escaped)
-                   escaped -= dist;
-               if (comment)
-                   comment -= dist;
-               cf->P_ptr = tp;
-               tp += len;
-               cf->P_end = tp;
-               /* Try to read more data from file into buffer space */
-               len = cf->P_str + cf->P_buflen - tp - 32;
-               if (len <= 0) {
-                   /* We need a bigger buffer to hold this line */
-                   tp = bmake_realloc(cf->P_str, cf->P_buflen + IFILE_BUFLEN);
-                   cf->P_ptr = cf->P_ptr - cf->P_str + tp;
-                   cf->P_end = cf->P_end - cf->P_str + tp;
-                   ptr = ptr - cf->P_str + tp;
-                   line = line - cf->P_str + tp;
-                   line_end = line_end - cf->P_str + tp;
-                   if (escaped)
-                       escaped = escaped - cf->P_str + tp;
-                   if (comment)
-                       comment = comment - cf->P_str + tp;
-                   cf->P_str = tp;
-                   tp = cf->P_end;
-                   len += IFILE_BUFLEN;
-                   cf->P_buflen += IFILE_BUFLEN;
-               }
-               len = read(cf->fd, tp, len);
-               if (len <= 0) {
-                   if (len < 0) {
-                       Parse_Error(PARSE_FATAL, "Makefile read error: %s",
-                               strerror(errno));
-                       return NULL;
-                   }
-                   /* End of file */
+               if (cf->nextbuf != NULL) {
+                   /*
+                    * End of this buffer; return EOF and outer logic
+                    * will get the next one. (eww)
+                    */
                    break;
                }
-               /* 0 terminate the data, and update end pointer */
-               tp += len;
-               cf->P_end = tp;
-               *tp = 0;
-               /* Process newly read characters */
-               continue;
+               Parse_Error(PARSE_FATAL, "Zero byte read from file");
+               return NULL;
            }
 
            if (ch == '\\') {
@@ -2303,7 +2579,9 @@ ParseGetLine(int flags, int *length)
            }
            if (ch == '#' && comment == NULL) {
                /* Remember first '#' for comment stripping */
-               comment = line_end;
+               /* Unless previous char was '[', as in modifier :[#] */
+               if (!(ptr > line && ptr[-1] == '['))
+                   comment = line_end;
            }
            ptr++;
            if (ch == '\n')
@@ -2459,7 +2737,7 @@ ParseReadLine(void)
                line = ParseGetLine(PARSE_RAW, &lineLength);
                if (line == NULL) {
                    Parse_Error(PARSE_FATAL,
-                            "Unexpected end of file in for loop.\n");
+                            "Unexpected end of file in for loop.");
                    break;
                }
            } while (For_Accum(line));
@@ -2522,11 +2800,19 @@ Parse_File(const char *name, int fd)
 {
     char         *cp;          /* pointer into the line */
     char          *line;       /* the line we're working on */
+    struct loadedfile *lf;
+
+    lf = loadfile(name, fd);
 
     inLine = FALSE;
     fatals = 0;
 
-    Parse_SetInput(name, 0, fd, NULL, NULL);
+    if (name == NULL) {
+           name = "(stdin)";
+    }
+
+    Parse_SetInput(name, 0, -1, loadedfile_nextbuf, lf);
+    curFile->lf = lf;
 
     do {
        for (; (line = ParseReadLine()) != NULL; ) {
@@ -2619,6 +2905,17 @@ Parse_File(const char *name, int fd)
                ParseTraditionalInclude(line);
                continue;
            }
+#endif
+#ifdef GMAKEEXPORT
+           if (strncmp(line, "export", 6) == 0 &&
+               isspace((unsigned char) line[6]) &&
+               strchr(line, ':') == NULL) {
+               /*
+                * It's an Gmake"export".
+                */
+               ParseGmakeExport(line);
+               continue;
+           }
 #endif
            if (Parse_IsVar(line)) {
                ParseFinishLine();
@@ -2719,7 +3016,7 @@ Parse_File(const char *name, int fd)
     if (fatals) {
        (void)fflush(stdout);
        (void)fprintf(stderr,
-           "%s: Fatal errors encountered -- cannot continue\n",
+           "%s: Fatal errors encountered -- cannot continue",
            progname);
        PrintOnError(NULL, NULL);
        exit(1);
similarity index 100%
rename from commands/make/sprite.h
rename to usr.bin/make/sprite.h
similarity index 97%
rename from commands/make/str.c
rename to usr.bin/make/str.c
index f1b93a0a13e6c9c07505670f0abb2b4153a58efd..bc324b8c9c2056650b04901bed2e07388415a5ea 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: str.c,v 1.33 2009/02/25 21:17:21 sno Exp $     */
+/*     $NetBSD: str.c,v 1.34 2012/03/03 23:16:47 dholland Exp $        */
 
 /*-
  * Copyright (c) 1988, 1989, 1990, 1993
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: str.c,v 1.33 2009/02/25 21:17:21 sno Exp $";
+static char rcsid[] = "$NetBSD: str.c,v 1.34 2012/03/03 23:16:47 dholland Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char     sccsid[] = "@(#)str.c  5.8 (Berkeley) 6/1/90";
 #else
-__RCSID("$NetBSD: str.c,v 1.33 2009/02/25 21:17:21 sno Exp $");
+__RCSID("$NetBSD: str.c,v 1.34 2012/03/03 23:16:47 dholland Exp $");
 #endif
 #endif                         /* not lint */
 #endif
@@ -319,6 +319,8 @@ Str_FindSubstring(const char *string, const char *substring)
  * matching operation permits the following special characters in the
  * pattern: *?\[] (see the man page for details on what these mean).
  *
+ * XXX this function does not detect or report malformed patterns.
+ *
  * Side effects: None.
  */
 int
similarity index 99%
rename from commands/make/suff.c
rename to usr.bin/make/suff.c
index a4cd626d362bcccfe9c5705c82e5ab9bf9e7b55c..6abdeb0459e51b73606aedbf0f0b1d2708bd880d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: suff.c,v 1.67 2009/01/23 21:58:28 dsl Exp $    */
+/*     $NetBSD: suff.c,v 1.69 2011/09/29 23:38:04 sjg Exp $    */
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: suff.c,v 1.67 2009/01/23 21:58:28 dsl Exp $";
+static char rcsid[] = "$NetBSD: suff.c,v 1.69 2011/09/29 23:38:04 sjg Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)suff.c     8.4 (Berkeley) 3/21/94";
 #else
-__RCSID("$NetBSD: suff.c,v 1.67 2009/01/23 21:58:28 dsl Exp $");
+__RCSID("$NetBSD: suff.c,v 1.69 2011/09/29 23:38:04 sjg Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -136,7 +136,6 @@ __RCSID("$NetBSD: suff.c,v 1.67 2009/01/23 21:58:28 dsl Exp $");
  */
 
 #include         <stdio.h>
-#include         <strings.h>
 #include         "make.h"
 #include         "hash.h"
 #include         "dir.h"
@@ -1435,7 +1434,7 @@ SuffFindCmds(Src *targ, Lst slst)
             * We haven't looked to see if .OPTIONAL files exist yet, so
             * don't use one as the implicit source.
             * This allows us to use .OPTIONAL in .depend files so make won't
-            * complain "don't know how to make xxx.h' when a dependant file
+            * complain "don't know how to make xxx.h' when a dependent file
             * has been moved/deleted.
             */
            continue;
@@ -2407,16 +2406,25 @@ Suff_FindDeps(GNode *gn)
 static void
 SuffFindDeps(GNode *gn, Lst slst)
 {
-    if (gn->type & (OP_DEPS_FOUND|OP_PHONY)) {
+    if (gn->type & OP_DEPS_FOUND) {
        /*
         * If dependencies already found, no need to do it again...
-        * If this is a .PHONY target, we do not apply suffix rules.
         */
        return;
     } else {
        gn->type |= OP_DEPS_FOUND;
     }
-
+    /*
+     * Make sure we have these set, may get revised below.
+     */
+    Var_Set(TARGET, gn->path ? gn->path : gn->name, gn, 0);
+    Var_Set(PREFIX, gn->name, gn, 0);
+    if (gn->type & OP_PHONY) {
+       /*
+        * If this is a .PHONY target, we do not apply suffix rules.
+        */
+       return;
+    }
     if (DEBUG(SUFF)) {
        fprintf(debug_file, "SuffFindDeps (%s)\n", gn->name);
     }
similarity index 98%
rename from commands/make/targ.c
rename to usr.bin/make/targ.c
index b0f63d9e759be031a74d2b4919391141254f124e..20fe05ca3317a40ee4e44ea8f432e78e24955352 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: targ.c,v 1.55 2009/01/23 21:26:30 dsl Exp $    */
+/*     $NetBSD: targ.c,v 1.56 2010/11/25 21:31:09 christos Exp $       */
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: targ.c,v 1.55 2009/01/23 21:26:30 dsl Exp $";
+static char rcsid[] = "$NetBSD: targ.c,v 1.56 2010/11/25 21:31:09 christos Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)targ.c     8.2 (Berkeley) 3/19/94";
 #else
-__RCSID("$NetBSD: targ.c,v 1.55 2009/01/23 21:26:30 dsl Exp $");
+__RCSID("$NetBSD: targ.c,v 1.56 2010/11/25 21:31:09 christos Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -130,7 +130,6 @@ __RCSID("$NetBSD: targ.c,v 1.55 2009/01/23 21:26:30 dsl Exp $");
  */
 
 #include         <stdio.h>
-#include         <strings.h>
 #include         <time.h>
 
 #include         "make.h"
@@ -249,8 +248,9 @@ Targ_NewGN(const char *name)
     gn->centurion =            NULL;
     gn->made =                 UNMADE;
     gn->flags =        0;
-    gn->checked = 0;
-    gn->mtime = gn->cmtime = 0;
+    gn->checked =      0;
+    gn->mtime =                0;
+    gn->cmgn =         NULL;
     gn->iParents =     Lst_Init(FALSE);
     gn->cohorts =      Lst_Init(FALSE);
     gn->parents =      Lst_Init(FALSE);
similarity index 94%
rename from commands/make/trace.c
rename to usr.bin/make/trace.c
index 0640e5bf9ea04fd7d809cf04bcb7b3a50d4dfadb..267177ff56185b5987e5ba93aa417e632d863974 100644 (file)
@@ -96,17 +96,10 @@ Trace_Log(TrEvent event, Job *job)
 
        gettimeofday(&rightnow, NULL);
 
-#if defined(__minix)
-       fprintf(trfile, "%ld.%06ld %d %s %d %s",
-           (long)rightnow.tv_sec, (long)rightnow.tv_usec,
-           jobTokensRunning,
-           evname[event], trpid, trwd);
-#else
        fprintf(trfile, "%lld.%06ld %d %s %d %s",
            (long long)rightnow.tv_sec, (long)rightnow.tv_usec,
            jobTokensRunning,
            evname[event], trpid, trwd);
-#endif
        if (job != NULL) {
                fprintf(trfile, " %s %d %x %x", job->node->name,
                    job->pid, job->flags, job->node->type);
similarity index 100%
rename from commands/make/trace.h
rename to usr.bin/make/trace.h
similarity index 83%
rename from commands/make/unit-tests/Makefile
rename to usr.bin/make/unit-tests/Makefile
index b3fd0a8185d6b108ce993725e8fe4af19d001355..05ccd4f0f72433086371f1dd8656432d1c9f7453 100644 (file)
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.25 2009/11/19 00:30:25 sjg Exp $
+# $NetBSD: Makefile,v 1.33 2011/09/29 23:38:04 sjg Exp $
 #
 # Unit tests for make(1)
 # The main targets are:
@@ -21,18 +21,24 @@ UNIT_TESTS:= ${.PARSEDIR}
 SUBFILES= \
        comment \
        cond1 \
+       error \
        export \
        export-all \
+       doterror \
        dotwait \
        forsubst \
+       hash \
+       misc \
        moderrs \
        modmatch \
        modmisc \
        modorder \
        modts \
        modword \
+       phony-end \
        posix \
        qequals \
+       sysv \
        ternary \
        unexport \
        unexport-env \
@@ -40,18 +46,26 @@ SUBFILES= \
 
 all: ${SUBFILES}
 
+flags.doterror=
+
 # the tests are actually done with sub-makes.
 .PHONY: ${SUBFILES}
 .PRECIOUS: ${SUBFILES}
 ${SUBFILES}:
-       -@${.MAKE} -k -f ${UNIT_TESTS}/$@
+       -@${.MAKE} ${flags.$@:U-k} -f ${UNIT_TESTS}/$@
 
 clean:
        rm -f *.out *.fail *.core
 
-.include <bsd.obj.mk>
+.-include <bsd.obj.mk>
 
 TEST_MAKE?= ${.MAKE}
+TOOL_SED?= sed
+
+# ensure consistent results from sort(1)
+LC_ALL= C
+LANG= C
+.export LANG LC_ALL
 
 # The driver.
 # We always pretend .MAKE was called 'make' 
similarity index 92%
rename from commands/make/unit-tests/cond1
rename to usr.bin/make/unit-tests/cond1
index cf51b5c526f097dac38d6d987c70e77108c5ea4c..7d3df40dc31d73f6ae821b01b0855cd60fc8d369 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: cond1,v 1.4 2008/10/29 15:37:08 sjg Exp $
+# $Id: cond1,v 1.5 2011/03/06 00:02:14 sjg Exp $
 
 # hard code these!
 TEST_UNAME_S= NetBSD
@@ -95,6 +95,11 @@ C=clever
 C=dim
 .endif
 
+.if defined(nosuch) && ${nosuch:Mx} != ""
+# this should not happen
+.info nosuch is x
+.endif
+
 all:
        @echo "$n is $X prime"
        @echo "A='$A' B='$B' C='$C' o='$o,${o2}'"
diff --git a/usr.bin/make/unit-tests/doterror b/usr.bin/make/unit-tests/doterror
new file mode 100644 (file)
index 0000000..ec63321
--- /dev/null
@@ -0,0 +1,20 @@
+# $Id: doterror,v 1.1 2010/04/08 17:41:29 sjg Exp $
+
+
+.BEGIN:
+       @echo At first, I am
+
+.END:
+       @echo not reached
+
+.ERROR:
+       @echo "$@: Looks like '${.ERROR_TARGET}' is upset."
+
+all:   happy sad
+
+happy:
+       @echo $@
+
+sad:
+       @echo and now: $@; exit 1
+
diff --git a/usr.bin/make/unit-tests/error b/usr.bin/make/unit-tests/error
new file mode 100644 (file)
index 0000000..05c3d86
--- /dev/null
@@ -0,0 +1,10 @@
+# $Id: error,v 1.2 2010/05/24 21:04:49 sjg Exp $
+
+.info just FYI
+.warning this could be serious
+.error this is fatal
+
+all:
+
+.info.html:
+       @echo this should be ignored
diff --git a/usr.bin/make/unit-tests/export-all b/usr.bin/make/unit-tests/export-all
new file mode 100644 (file)
index 0000000..d1c79e2
--- /dev/null
@@ -0,0 +1,23 @@
+# $Id: export-all,v 1.2 2010/04/21 04:25:28 sjg Exp $
+
+UT_OK=good
+UT_F=fine
+
+# the old way to do :tA
+M_tAbad = C,.*,cd & \&\& 'pwd',:sh
+# the new
+M_tA = tA
+
+here := ${.PARSEDIR}
+
+# this will cause trouble (recursing if we let it)
+UT_BADDIR = ${${here}/../${here:T}:L:${M_tAbad}:T}
+# this will be ok
+UT_OKDIR = ${${here}/../${here:T}:L:${M_tA}:T}
+
+.export
+
+.include "export"
+
+UT_TEST=export-all
+UT_ALL=even this gets exported
diff --git a/usr.bin/make/unit-tests/hash b/usr.bin/make/unit-tests/hash
new file mode 100644 (file)
index 0000000..1ed84e7
--- /dev/null
@@ -0,0 +1,18 @@
+STR1=
+STR2=  a
+STR3=  ab
+STR4=  abc
+STR5=  abcd
+STR6=  abcde
+STR7=  abcdef
+STR8=  abcdefghijklmnopqrstuvwxyz
+
+all:
+       @echo ${STR1:hash}
+       @echo ${STR2:hash}
+       @echo ${STR3:hash}
+       @echo ${STR4:hash}
+       @echo ${STR5:hash}
+       @echo ${STR6:hash}
+       @echo ${STR7:hash}
+       @echo ${STR8:hash}
diff --git a/usr.bin/make/unit-tests/misc b/usr.bin/make/unit-tests/misc
new file mode 100644 (file)
index 0000000..bb54df4
--- /dev/null
@@ -0,0 +1,16 @@
+# $Id: misc,v 1.1 2011/03/06 00:02:14 sjg Exp $
+
+.if !exists(${.CURDIR}/)
+.warning ${.CURDIR}/ doesn't exist ?
+.endif
+
+.if !exists(${.CURDIR}/.)
+.warning ${.CURDIR}/. doesn't exist ?
+.endif
+
+.if !exists(${.CURDIR}/..)
+.warning ${.CURDIR}/.. doesn't exist ?
+.endif
+
+all:
+       @: all is well
similarity index 74%
rename from commands/make/unit-tests/modmisc
rename to usr.bin/make/unit-tests/modmisc
index 11f22eaed5a7edac2e7d35ffecfc23ddde4b7d49..bb537558786e0e5b0b2f03c589120ba6dc870e48 100644 (file)
@@ -1,8 +1,10 @@
-# $Id: modmisc,v 1.4 2006/05/11 15:37:07 sjg Exp $
+# $Id: modmisc,v 1.7 2011/04/11 15:10:15 sjg Exp $
 #
 # miscellaneous modifier tests
 
-path=:/bin:/usr/bin::/sbin:/usr/sbin:.:/home/user/bin:.
+# do not put any dirs in this list which exist on some
+# but not all target systems - an exists() check is below.
+path=:/bin:/tmp::/:.:/no/such/dir:.
 # strip cwd from path.
 MOD_NODOT=S/:/ /g:N.:ts:
 # and decorate, note that $'s need to be doubled. Also note that 
@@ -13,7 +15,10 @@ MOD_HOMES=S,/home/,/homes/,
 MOD_OPT=@d@$${exists($$d):?$$d:$${d:S,/usr,/opt,}}@
 MOD_SEP=S,:, ,g
 
-all:   modvar modvarloop
+all:   modvar modvarloop modsysv
+
+modsysv:
+       @echo "The answer is ${libfoo.a:L:libfoo.a=42}"
 
 modvar:
        @echo "path='${path}'"
diff --git a/usr.bin/make/unit-tests/modts b/usr.bin/make/unit-tests/modts
new file mode 100644 (file)
index 0000000..616bd89
--- /dev/null
@@ -0,0 +1,43 @@
+
+LIST= one two three
+LIST+= four five six
+
+FU_mod-ts = a / b / cool
+
+AAA= a a a
+B.aaa= Baaa
+
+all:   mod-ts
+
+# Use print or printf iff they are builtin.
+# XXX note that this causes problems, when make decides 
+# there is no need to use a shell, so avoid where possible.
+.if ${type print 2> /dev/null || echo:L:sh:Mbuiltin} != ""
+PRINT= print -r --
+.elif ${type printf 2> /dev/null || echo:L:sh:Mbuiltin} != ""
+PRINT= printf '%s\n'
+.else
+PRINT= echo
+.endif
+
+mod-ts:
+       @echo 'LIST="${LIST}"'
+       @echo 'LIST:ts,="${LIST:ts,}"'
+       @echo 'LIST:ts/:tu="${LIST:ts/:tu}"'
+       @echo 'LIST:ts::tu="${LIST:ts::tu}"'
+       @echo 'LIST:ts:tu="${LIST:ts:tu}"'
+       @echo 'LIST:tu:ts/="${LIST:tu:ts/}"'
+       @echo 'LIST:ts:="${LIST:ts:}"'
+       @echo 'LIST:ts="${LIST:ts}"'
+       @echo 'LIST:ts:S/two/2/="${LIST:ts:S/two/2/}"'
+       @echo 'LIST:S/two/2/:ts="${LIST:S/two/2/:ts}"'
+       @echo 'LIST:ts/:S/two/2/="${LIST:ts/:S/two/2/}"'
+       @echo "Pretend the '/' in '/n' etc. below are back-slashes."
+       @${PRINT} 'LIST:ts/n="${LIST:ts\n}"'
+       @${PRINT} 'LIST:ts/t="${LIST:ts\t}"'
+       @${PRINT} 'LIST:ts/012:tu="${LIST:ts\012:tu}"'
+       @${PRINT} 'LIST:tx="${LIST:tx}"'
+       @${PRINT} 'LIST:ts/x:tu="${LIST:ts\x:tu}"'
+       @${PRINT} 'FU_$@="${FU_${@:ts}:ts}"'
+       @${PRINT} 'FU_$@:ts:T="${FU_${@:ts}:ts:T}" == cool?'
+       @${PRINT} 'B.$${AAA:ts}="${B.${AAA:ts}}" == Baaa?'
diff --git a/usr.bin/make/unit-tests/phony-end b/usr.bin/make/unit-tests/phony-end
new file mode 100644 (file)
index 0000000..f7e627c
--- /dev/null
@@ -0,0 +1,9 @@
+# $Id: phony-end,v 1.1 2011/09/29 23:38:04 sjg Exp $
+
+all ok also.ok bug phony:
+       @echo '${.TARGET .PREFIX .IMPSRC:L:@v@$v="${$v}"@}'
+
+.END:  ok also.ok bug
+
+phony bug:     .PHONY
+all: phony
diff --git a/usr.bin/make/unit-tests/sysv b/usr.bin/make/unit-tests/sysv
new file mode 100644 (file)
index 0000000..2d304f6
--- /dev/null
@@ -0,0 +1,26 @@
+# $Id: sysv,v 1.2 2011/06/03 21:10:42 sjg Exp $
+
+FOO ?=
+FOOBAR = $(FOO:=bar)
+
+_this := ${.PARSEDIR}/${.PARSEFILE}
+
+B = /b
+S = /
+FUN = ${B}${S}fun
+SUN = the Sun
+
+# we expect nothing when FOO is empty
+all: foo fun
+
+foo:
+       @echo FOOBAR = $(FOOBAR)
+.if empty(FOO)
+       @FOO="foo fu" ${.MAKE} -f ${_this} foo
+.endif
+
+fun:
+       @echo ${FUN:T}
+       @echo ${FUN:${B}${S}fun=fun}
+       @echo ${FUN:${B}${S}%=%}
+       @echo ${In:L:%=% ${SUN}}
similarity index 89%
rename from commands/make/unit-tests/test.exp
rename to usr.bin/make/unit-tests/test.exp
index c242a040d6fb4cd4d077173301c298cfa5afd724..cbb2912a081e3370b13910b04381154a57aa9ed9 100644 (file)
@@ -24,20 +24,33 @@ make: warning: String comparison operator should be either == or !=
 make: Bad conditional expression `"0" > 0' in "0" > 0?OK:No
 
 OK
+make: "error" line 3: just FYI
+make: "error" line 4: warning: this could be serious
+make: "error" line 5: this is fatal
 UT_DOLLAR=This is $UT_FU
 UT_FOO=foobar is fubar
 UT_FU=fubar
 UT_TEST=export
 UT_ZOO=hoopie
 UT_ALL=even this gets exported
+UT_BADDIR=unit-tests
 UT_DOLLAR=This is $UT_FU
 UT_F=fine
 UT_FOO=foobar is fubar
 UT_FU=fubar
 UT_NO=all
 UT_OK=good
+UT_OKDIR=unit-tests
 UT_TEST=export-all
 UT_ZOO=hoopie
+At first, I am
+happy
+and now: sad
+.ERROR: Looks like 'sad' is upset.
+*** Error code 1
+
+Stop.
+make: stopped in unit-tests
 simple.1
 simple.1
 simple.2
@@ -68,6 +81,14 @@ make: Graph cycles through `cycle.2.97'
 cycle.1.99
 cycle.1.99
 .for with :S;... OK
+b2af338b
+3360ac65
+7747f046
+9ca87054
+880fe816
+208fcbd3
+d5d376eb
+de41416c
 Expect: Unknown modifier 'Z'
 make: Unknown modifier 'Z'
 VAR:Z=
@@ -99,14 +120,15 @@ LIB=e X_LIBS:M${LIB${LIB:tu}} is "/tmp/libe.a"
 LIB=e X_LIBS:M*/lib${LIB}.a is "/tmp/libe.a"
 LIB=e X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBE.A"
 Mscanner=OK
-path=':/bin:/usr/bin::/sbin:/usr/sbin:.:/home/user/bin:.'
-path='/bin:/usr/bin:/sbin:/usr/sbin:/home/user/bin'
-path='/bin:/usr/bin:/sbin:/usr/sbin:/homes/user/bin'
-path='/bin':'/usr/bin':'/sbin':'/usr/sbin':'/home/user/bin'
-path='/bin':'/usr/bin':'/sbin':'/usr/sbin':'/homes/user/bin'
+path=':/bin:/tmp::/:.:/no/such/dir:.'
+path='/bin:/tmp:/:/no/such/dir'
+path='/bin:/tmp:/:/no/such/dir'
+path='/bin':'/tmp':'/':'/no/such/dir'
+path='/bin':'/tmp':'/':'/no/such/dir'
 path_/usr/xbin=/opt/xbin/
-paths=/bin /usr/bin /sbin /usr/sbin /homes/user/bin /opt/xbin
-PATHS=/BIN /USR/BIN /SBIN /USR/SBIN /HOMES/USER/BIN /OPT/XBIN
+paths=/bin /tmp / /no/such/dir /opt/xbin
+PATHS=/BIN /TMP / /NO/SUCH/DIR /OPT/XBIN
+The answer is 42
 LIST      = one two three four five six seven eight nine ten
 LIST:O    = eight five four nine one seven six ten three two
 LIST:Ox   = Ok
@@ -270,6 +292,11 @@ LIST:tw:C/ /,/g="one two three four five six"
 LIST:tw:C/ /,/1g="one two three four five six"
 LIST:tw:tW:C/ /,/="one,two three four five six"
 LIST:tW:tw:C/ /,/="one two three four five six"
+.TARGET="phony" .PREFIX="phony" .IMPSRC=""
+.TARGET="all" .PREFIX="all" .IMPSRC=""
+.TARGET="ok" .PREFIX="ok" .IMPSRC=""
+.TARGET="also.ok" .PREFIX="also.ok" .IMPSRC=""
+.TARGET="bug" .PREFIX="bug" .IMPSRC=""
 Posix says we should execute the command as if run by system(3)
 Expect 'Hello,' and 'World!'
 Hello,
@@ -293,6 +320,12 @@ Now we expect an error...
 *** Error code 1 (continuing)
 `all' not remade because of errors.
 V.i386 ?= OK
+FOOBAR =
+FOOBAR = foobar fubar
+fun
+fun
+fun
+In the Sun
 The answer is unknown
 The answer is unknown
 The answer is empty
@@ -314,3 +347,5 @@ five FU=<v>bar</v> FOO=<v>goo</v> VAR=<v>Internal</v>
 five v=is x k=is x
 six v=is y k=is y
 show-v v=override k=override
+*** Error code 1 (ignored)
+*** Error code 1 (ignored)
similarity index 97%
rename from commands/make/util.c
rename to usr.bin/make/util.c
index 3c27089d3cc6b04ac90ba16f8b5490bf9296284f..e50f2a3b4f276dfb06aba25f55ac84fb684e39d1 100644 (file)
@@ -1,15 +1,15 @@
-/*     $NetBSD: util.c,v 1.50 2010/06/03 15:40:16 sjg Exp $    */
+/*     $NetBSD: util.c,v 1.51 2011/04/02 07:58:30 mbalmer Exp $        */
 
 /*
  * Missing stuff from OS's
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: util.c,v 1.50 2010/06/03 15:40:16 sjg Exp $";
+static char rcsid[] = "$NetBSD: util.c,v 1.51 2011/04/02 07:58:30 mbalmer Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: util.c,v 1.50 2010/06/03 15:40:16 sjg Exp $");
+__RCSID("$NetBSD: util.c,v 1.51 2011/04/02 07:58:30 mbalmer Exp $");
 #endif
 #endif
 
@@ -49,7 +49,7 @@ findenv(const char *name, int *offset)
        char *p, *q;
 
        for (i = 0; (q = environ[i]); i++) {
-               char *p = strchr(q, '=');
+               p = strchr(q, '=');
                if (p == NULL)
                        continue;
                if (strncmp(name, q, len = p - q) == 0) {
similarity index 96%
rename from commands/make/var.c
rename to usr.bin/make/var.c
index d644674c7acda9d31a6de86c40ccfcf8b56a57c5..d66e5aa0d42cf60d465a2517c75d41de9dee4a76 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: var.c,v 1.159 2010/06/06 01:13:12 sjg Exp $    */
+/*     $NetBSD: var.c,v 1.167 2011/06/03 21:10:42 sjg Exp $    */
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
  */
 
 #ifndef MAKE_NATIVE
-static char rcsid[] = "$NetBSD: var.c,v 1.159 2010/06/06 01:13:12 sjg Exp $";
+static char rcsid[] = "$NetBSD: var.c,v 1.167 2011/06/03 21:10:42 sjg Exp $";
 #else
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)var.c      8.3 (Berkeley) 3/19/94";
 #else
-__RCSID("$NetBSD: var.c,v 1.159 2010/06/06 01:13:12 sjg Exp $");
+__RCSID("$NetBSD: var.c,v 1.167 2011/06/03 21:10:42 sjg Exp $");
 #endif
 #endif /* not lint */
 #endif
@@ -129,8 +129,10 @@ __RCSID("$NetBSD: var.c,v 1.159 2010/06/06 01:13:12 sjg Exp $");
 #include    <regex.h>
 #endif
 #include    <ctype.h>
+#include    <inttypes.h>
 #include    <stdlib.h>
 #include    <limits.h>
+#include    <time.h>
 
 #include    "make.h"
 #include    "buf.h"
@@ -302,6 +304,7 @@ static char *VarGetPattern(GNode *, Var_Parse_State *,
                           VarPattern *);
 static char *VarQuote(char *);
 static char *VarChangeCase(char *, int);
+static char *VarHash(char *);
 static char *VarModify(GNode *, Var_Parse_State *,
     const char *,
     Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *),
@@ -379,6 +382,12 @@ VarFind(const char *name, GNode *ctxt, int flags)
                                name = TARGET;
                        break;
                }
+#ifdef notyet
+    /* for compatibility with gmake */
+    if (name[0] == '^' && name[1] == '\0')
+           name = ALLSRC;
+#endif
+
     /*
      * First look for the variable in the given context. If it's not there,
      * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
@@ -2254,6 +2263,79 @@ VarQuote(char *str)
     return str;
 }
 
+/*-
+ *-----------------------------------------------------------------------
+ * VarHash --
+ *      Hash the string using the MurmurHash3 algorithm.
+ *      Output is computed using 32bit Little Endian arithmetic.
+ *
+ * Input:
+ *     str             String to modify
+ *
+ * Results:
+ *      Hash value of str, encoded as 8 hex digits.
+ *
+ * Side Effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------
+ */
+static char *
+VarHash(char *str)
+{
+    static const char    hexdigits[16] = "0123456789abcdef";
+    Buffer         buf;
+    size_t         len, len2;
+    unsigned char  *ustr = (unsigned char *)str;
+    uint32_t       h, k, c1, c2;
+    int            done;
+
+    done = 1;
+    h  = 0x971e137bU;
+    c1 = 0x95543787U;
+    c2 = 0x2ad7eb25U;
+    len2 = strlen(str);
+
+    for (len = len2; len; ) {
+       k = 0;
+       switch (len) {
+       default:
+           k = (ustr[3] << 24) | (ustr[2] << 16) | (ustr[1] << 8) | ustr[0];
+           len -= 4;
+           ustr += 4;
+           break;
+       case 3:
+           k |= (ustr[2] << 16);
+       case 2:
+           k |= (ustr[1] << 8);
+       case 1:
+           k |= ustr[0];
+           len = 0;
+       }
+       c1 = c1 * 5 + 0x7b7d159cU;
+       c2 = c2 * 5 + 0x6bce6396U;
+       k *= c1;
+       k = (k << 11) ^ (k >> 21);
+       k *= c2;
+       h = (h << 13) ^ (h >> 19);
+       h = h * 5 + 0x52dce729U;
+       h ^= k;
+   } while (!done);
+   h ^= len2;
+   h *= 0x85ebca6b;
+   h ^= h >> 13;
+   h *= 0xc2b2ae35;
+   h ^= h >> 16;
+
+   Buf_Init(&buf, 0);
+   for (len = 0; len < 8; ++len) {
+       Buf_AddByte(&buf, hexdigits[h & 15]);
+       h >>= 4;
+   }
+
+   return Buf_Destroy(&buf, FALSE);
+}
+
 /*-
  *-----------------------------------------------------------------------
  * VarChangeCase --
@@ -2285,6 +2367,21 @@ VarChangeCase(char *str, int upper)
    return Buf_Destroy(&buf, FALSE);
 }
 
+static char *
+VarStrftime(const char *fmt, int zulu)
+{
+    char buf[BUFSIZ];
+    time_t utc;
+
+    time(&utc);
+    if (!*fmt)
+       fmt = "%c";
+    strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc));
+    
+    buf[sizeof(buf) - 1] = '\0';
+    return bmake_strdup(buf);
+}
+
 /*
  * Now we need to apply any modifiers the user wants applied.
  * These are:
@@ -2370,6 +2467,10 @@ VarChangeCase(char *str, int upper)
  *                     variable.
  */
 
+/* we now have some modifiers with long names */
+#define STRMOD_MATCH(s, want, n) \
+    (strncmp(s, want, n) == 0 && (s[n] == endc || s[n] == ':'))
+
 static char *
 ApplyModifiers(char *nstr, const char *tstr,
               int startc, int endc,
@@ -2397,14 +2498,28 @@ ApplyModifiers(char *nstr, const char *tstr,
 
        if (*tstr == '$') {
            /*
-            * We have some complex modifiers in a variable.
+            * We may have some complex modifiers in a variable.
             */
            void *freeIt;
            char *rval;
            int rlen;
+           int c;
 
            rval = Var_Parse(tstr, ctxt, errnum, &rlen, &freeIt);
 
+           /*
+            * If we have not parsed up to endc or ':',
+            * we are not interested.
+            */
+           if (rval != NULL && *rval &&
+               (c = tstr[rlen]) != '\0' &&
+               c != ':' &&
+               c != endc) {
+               if (freeIt)
+                   free(freeIt);
+               goto apply_mods;
+           }
+
            if (DEBUG(VAR)) {
                fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n",
                       rval, rlen, tstr, rlen, tstr + rlen);
@@ -2436,6 +2551,7 @@ ApplyModifiers(char *nstr, const char *tstr,
            }
            continue;
        }
+    apply_mods:
        if (DEBUG(VAR)) {
            fprintf(debug_file, "Applying :%c to \"%s\"\n", *tstr, nstr);
        }
@@ -2486,7 +2602,7 @@ ApplyModifiers(char *nstr, const char *tstr,
                        cp = ++tstr;
                        break;
                    }
-                   delim = BRCLOSE;
+                   delim = startc == PROPEN ? PRCLOSE : BRCLOSE;
                    pattern.flags = 0;
 
                    pattern.rhs = VarGetPattern(ctxt, &parsestate, errnum,
@@ -2815,6 +2931,36 @@ ApplyModifiers(char *nstr, const char *tstr,
                }
 
            }
+       case 'g':
+           cp = tstr + 1;      /* make sure it is set */
+           if (STRMOD_MATCH(tstr, "gmtime", 6)) {
+               newStr = VarStrftime(nstr, 1);
+               cp = tstr + 6;
+               termc = *cp;
+           } else {
+               goto default_case;
+           }
+           break;
+       case 'h':
+           cp = tstr + 1;      /* make sure it is set */
+           if (STRMOD_MATCH(tstr, "hash", 4)) {
+               newStr = VarHash(nstr);
+               cp = tstr + 4;
+               termc = *cp;
+           } else {
+               goto default_case;
+           }
+           break;
+       case 'l':
+           cp = tstr + 1;      /* make sure it is set */
+           if (STRMOD_MATCH(tstr, "localtime", 9)) {
+               newStr = VarStrftime(nstr, 0);
+               cp = tstr + 9;
+               termc = *cp;
+           } else {
+               goto default_case;
+           }
+           break;
        case 't':
            {
                cp = tstr + 1;  /* make sure it is set */
@@ -3340,9 +3486,13 @@ ApplyModifiers(char *nstr, const char *tstr,
                 */
                termc = *--cp;
                delim = '\0';
-               newStr = VarModify(ctxt, &parsestate, nstr,
-                                  VarSYSVMatch,
-                                  &pattern);
+               if (pattern.leftLen == 0 && *nstr == '\0') {
+                   newStr = nstr;      /* special case */
+               } else {
+                   newStr = VarModify(ctxt, &parsestate, nstr,
+                                      VarSYSVMatch,
+                                      &pattern);
+               }
                free(UNCONST(pattern.lhs));
                free(UNCONST(pattern.rhs));
            } else
@@ -3740,7 +3890,7 @@ Var_Parse(const char *str, GNode *ctxt, Boolean errnum, int *lengthPtr,
                nstr = bmake_strndup(start, *lengthPtr);
                *freePtr = nstr;
            } else {
-               nstr = var_Error;
+               nstr = errnum ? var_Error : varNoError;
            }
        }
        if (nstr != Buf_GetAll(&v->val, NULL))