Import NetBSD make

This commit is contained in:
Thomas Veerman 2012-06-06 14:24:31 +00:00
parent 357f105029
commit 2e2caf5919
100 changed files with 2894 additions and 526 deletions

View file

@ -16,7 +16,7 @@ SUBDIR= add_route arp ash at \
hostaddr id ifconfig ifdef install \ hostaddr id ifconfig ifdef install \
intr ipcrm ipcs irdpd isoread join kill last \ intr ipcrm ipcs irdpd isoread join kill last \
less loadkeys loadramdisk logger look lp \ less loadkeys loadramdisk logger look lp \
lpd ls lspci mail make MAKEDEV \ lpd ls lspci mail MAKEDEV \
mdb mesg mined mkfifo mkfs.mfs mknod \ mdb mesg mined mkfifo mkfs.mfs mknod \
mkproto mount mt netconf nice acknm nohup \ mkproto mount mt netconf nice acknm nohup \
nonamed od paste patch pax \ nonamed od paste patch pax \

View file

@ -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}

View file

@ -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

View file

@ -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?'

View file

@ -3,7 +3,7 @@
.include <bsd.own.mk> .include <bsd.own.mk>
# NetBSD imports # 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 \ apropos chpass newgrp passwd bzip2 bzip2recover gzip su genassym \
ldd/elf32 .WAIT ldd ldd/elf32 .WAIT ldd

View 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 # @(#)Makefile 5.2 (Berkeley) 12/28/90
PROG= make 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 lstMember.c lstNext.c lstOpen.c lstRemove.c lstReplace.c lstSucc.c
SRCS += lstPrev.c SRCS += lstPrev.c
.PATH: ${.CURDIR}/lst.lib # let people experiment for a bit
.if make(install) USE_META ?= no
SUBDIR= PSD.doc .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
.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) .if make(obj) || make(clean)
SUBDIR+= unit-tests SUBDIR+= unit-tests
.endif .endif
@ -24,10 +42,13 @@ SUBDIR+= unit-tests
.include <bsd.prog.mk> .include <bsd.prog.mk>
.include <bsd.subdir.mk> .include <bsd.subdir.mk>
CPPFLAGS+= -DMAKE_NATIVE
COPTS.var.c+= -Wno-cast-qual
.ifdef TOOLDIR .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, # this is a native netbsd build,
# use libutil rather than the local emalloc etc. # use libutil rather than the local emalloc etc.
CPPFLAGS+= -DUSE_EMALLOC CPPFLAGS+= -DUSE_EMALLOC

71
usr.bin/make/Makefile.bak Normal file
View file

@ -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}

View 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... # a very simple makefile...
# #
@ -6,9 +6,7 @@
# #
# modify MACHINE and MACHINE_ARCH as appropriate for your target architecture # modify MACHINE and MACHINE_ARCH as appropriate for your target architecture
# #
#CC=gcc -O -g CC=gcc -O -g
CC=cc
CFLAGS=-g -Wall -DHAVE_SETENV -DHAVE_STRERROR -DHAVE_STRDUP -DHAVE_STRFTIME -DHAVE_VSNPRINTF -DUSE_SELECT -D_POSIX_SOURCE
.c.o: .c.o:
${CC} ${CFLAGS} -c $< -o $@ ${CC} ${CFLAGS} -c $< -o $@
@ -18,7 +16,7 @@ MACHINE_ARCH=i386
# tested on HP-UX 10.20 # tested on HP-UX 10.20
#MAKE_MACHINE=hp700 #MAKE_MACHINE=hp700
#MAKE_MACHINE_ARCH=hppa #MAKE_MACHINE_ARCH=hppa
CFLAGS+= -DTARGET_MACHINE=\"${MACHINE}\" \ CFLAGS= -DTARGET_MACHINE=\"${MACHINE}\" \
-DTARGET_MACHINE_ARCH=\"${MACHINE_ARCH}\" \ -DTARGET_MACHINE_ARCH=\"${MACHINE_ARCH}\" \
-DMAKE_MACHINE=\"${MACHINE}\" -DMAKE_MACHINE=\"${MACHINE}\"
LIBS= LIBS=

View 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 .\" Copyright (c) 1988, 1989, 1993
.\" The Regents of the University of California. All rights reserved. .\" The Regents of the University of California. All rights reserved.
.\" .\"
@ -114,14 +114,15 @@
.nr g4 \\n(.s .nr g4 \\n(.s
.sp -1 .sp -1
.\" .st cf .\" .st cf
\D's -1u'\D't 5u' \D't 5u'
.sp -1 .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 .sp -1
\D't 3u' \D't 3u'
.sp -1 .sp -1
.sp 7u .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 .sp -1
.ft R .ft R
.ps 6 .ps 6
@ -131,7 +132,7 @@
\h'85u'\v'0.85n'\h-\w\\*(g9u/2u\&\\*(g9 \h'85u'\v'0.85n'\h-\w\\*(g9u/2u\&\\*(g9
.sp |\\n(g8u .sp |\\n(g8u
.sp 166u .sp 166u
\D't 3u'\D's -1u' \D't 3u'
.br .br
.po .po
.rt .rt

View 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 * Copyright (c) 1988, 1989, 1990, 1993
@ -69,14 +69,14 @@
*/ */
#ifndef MAKE_NATIVE #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 #else
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
#if 0 #if 0
static char sccsid[] = "@(#)arch.c 8.2 (Berkeley) 1/2/94"; static char sccsid[] = "@(#)arch.c 8.2 (Berkeley) 1/2/94";
#else #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
#endif /* not lint */ #endif /* not lint */
#endif #endif
@ -1212,7 +1212,7 @@ Arch_FindLib(GNode *gn, Lst path)
* A library will be considered out-of-date for any of these reasons, * A library will be considered out-of-date for any of these reasons,
* given that it is a target on a dependency line somewhere: * given that it is a target on a dependency line somewhere:
* Its modification time is less than that of one of its * 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 * Its modification time is greater than the time at which the
* make began (i.e. it's been modified in the course * make began (i.e. it's been modified in the course
* of the make, probably by archiving). * of the make, probably by archiving).
@ -1245,8 +1245,9 @@ Arch_LibOODate(GNode *gn)
oodate = TRUE; oodate = TRUE;
} else if (OP_NOP(gn->type) && Lst_IsEmpty(gn->children)) { } else if (OP_NOP(gn->type) && Lst_IsEmpty(gn->children)) {
oodate = FALSE; oodate = FALSE;
} else if ((!Lst_IsEmpty(gn->children) && gn->cmtime == 0) || } else if ((!Lst_IsEmpty(gn->children) && gn->cmgn == NULL) ||
(gn->mtime > now) || (gn->mtime < gn->cmtime)) { (gn->mtime > now) ||
(gn->cmgn != NULL && gn->mtime < gn->cmgn->mtime)) {
oodate = TRUE; oodate = TRUE;
} else { } else {
#ifdef RANLIBMAG #ifdef RANLIBMAG
@ -1261,7 +1262,7 @@ Arch_LibOODate(GNode *gn)
if (DEBUG(ARCH) || DEBUG(MAKE)) { if (DEBUG(ARCH) || DEBUG(MAKE)) {
fprintf(debug_file, "%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC)); fprintf(debug_file, "%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC));
} }
oodate = (gn->cmtime > modTimeTOC); oodate = (gn->cmgn == NULL || gn->cmgn->mtime > modTimeTOC);
} else { } else {
/* /*
* A library w/o a table of contents is out-of-date * A library w/o a table of contents is out-of-date

View 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. * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@ -70,14 +70,14 @@
*/ */
#ifndef MAKE_NATIVE #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 #else
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
#if 0 #if 0
static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94"; static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94";
#else #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
#endif /* not lint */ #endif /* not lint */
#endif #endif
@ -121,7 +121,7 @@ static char meta[256];
static GNode *curTarg = NULL; static GNode *curTarg = NULL;
static GNode *ENDNode; static GNode *ENDNode;
static void CompatInterrupt(int); static void CompatInterrupt(int) __dead;
static void static void
Compat_Init(void) Compat_Init(void)
@ -347,11 +347,17 @@ again:
useShell = 1; useShell = 1;
goto again; goto again;
} }
av = (const char **)mav; av = (void *)mav;
} }
local = TRUE; local = TRUE;
#ifdef USE_META
if (useMeta) {
meta_compat_start();
}
#endif
/* /*
* Fork and execute the single command. If the fork fails, we abort. * Fork and execute the single command. If the fork fails, we abort.
*/ */
@ -362,6 +368,11 @@ again:
if (cpid == 0) { if (cpid == 0) {
Check_Cwd(av); Check_Cwd(av);
Var_ExportVars(); Var_ExportVars();
#ifdef USE_META
if (useMeta) {
meta_compat_child();
}
#endif
if (local) if (local)
(void)execvp(av[0], (char *const *)UNCONST(av)); (void)execvp(av[0], (char *const *)UNCONST(av));
else else
@ -375,12 +386,20 @@ again:
free(bp); free(bp);
Lst_Replace(cmdNode, NULL); 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... * The child is off and running. Now all we can do is wait...
*/ */
while (1) { while (1) {
while ((retstat = wait(&reason)) != cpid) { while ((retstat = wait(&reason)) != cpid) {
if (retstat > 0)
JobReapChild(retstat, reason, FALSE); /* not ours? */
if (retstat == -1 && errno != EINTR) { if (retstat == -1 && errno != EINTR) {
break; break;
} }
@ -391,6 +410,11 @@ again:
status = WSTOPSIG(reason); /* stopped */ status = WSTOPSIG(reason); /* stopped */
} else if (WIFEXITED(reason)) { } else if (WIFEXITED(reason)) {
status = WEXITSTATUS(reason); /* exited */ status = WEXITSTATUS(reason); /* exited */
#if defined(USE_META) && defined(USE_FILEMON_ONCE)
if (useMeta) {
meta_cmd_finish(NULL);
}
#endif
if (status != 0) { if (status != 0) {
if (DEBUG(ERROR)) { if (DEBUG(ERROR)) {
fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ",
@ -417,6 +441,11 @@ again:
if (!WIFEXITED(reason) || (status != 0)) { if (!WIFEXITED(reason) || (status != 0)) {
if (errCheck) { if (errCheck) {
#ifdef USE_META
if (useMeta) {
meta_job_error(NULL, gn, 0, status);
}
#endif
gn->made = ERROR; gn->made = ERROR;
if (keepgoing) { if (keepgoing) {
/* /*
@ -498,10 +527,10 @@ Compat_Make(void *gnp, void *pgnp)
} }
/* /*
* All the children were made ok. Now cmtime contains the modification * All the children were made ok. Now cmgn->mtime contains the
* time of the newest child, we need to find out if we exist and when * modification time of the newest child, we need to find out if we
* we were modified last. The criteria for datedness are defined by the * exist and when we were modified last. The criteria for datedness
* Make_OODate function. * are defined by the Make_OODate function.
*/ */
if (DEBUG(MAKE)) { if (DEBUG(MAKE)) {
fprintf(debug_file, "Examining %s...", gn->name); fprintf(debug_file, "Examining %s...", gn->name);
@ -549,6 +578,11 @@ Compat_Make(void *gnp, void *pgnp)
*/ */
if (!touchFlag || (gn->type & OP_MAKE)) { if (!touchFlag || (gn->type & OP_MAKE)) {
curTarg = gn; curTarg = gn;
#ifdef USE_META
if (useMeta && !NoExecute(gn)) {
meta_job_start(NULL, gn);
}
#endif
Lst_ForEach(gn->commands, CompatRunCommand, gn); Lst_ForEach(gn->commands, CompatRunCommand, gn);
curTarg = NULL; curTarg = NULL;
} else { } else {
@ -557,6 +591,11 @@ Compat_Make(void *gnp, void *pgnp)
} else { } else {
gn->made = ERROR; gn->made = ERROR;
} }
#ifdef USE_META
if (useMeta && !NoExecute(gn)) {
meta_job_finish(NULL);
}
#endif
if (gn->made != ERROR) { if (gn->made != ERROR) {
/* /*

View 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. * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@ -70,14 +70,14 @@
*/ */
#ifndef MAKE_NATIVE #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 #else
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
#if 0 #if 0
static char sccsid[] = "@(#)cond.c 8.2 (Berkeley) 1/2/94"; static char sccsid[] = "@(#)cond.c 8.2 (Berkeley) 1/2/94";
#else #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
#endif /* not lint */ #endif /* not lint */
#endif #endif
@ -327,7 +327,7 @@ CondGetArg(char **linePtr, char **argPtr, const char *func)
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
*/ */
static Boolean static Boolean
CondDoDefined(int argLen, const char *arg) CondDoDefined(int argLen __unused, const char *arg)
{ {
char *p1; char *p1;
Boolean result; Boolean result;
@ -376,7 +376,7 @@ CondStrMatch(const void *string, const void *pattern)
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
*/ */
static Boolean static Boolean
CondDoMake(int argLen, const char *arg) CondDoMake(int argLen __unused, const char *arg)
{ {
return Lst_Find(create, arg, CondStrMatch) != NULL; return Lst_Find(create, arg, CondStrMatch) != NULL;
} }
@ -395,22 +395,22 @@ CondDoMake(int argLen, const char *arg)
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
*/ */
static Boolean static Boolean
CondDoExists(int argLen, const char *arg) CondDoExists(int argLen __unused, const char *arg)
{ {
Boolean result; Boolean result;
char *path; char *path;
path = Dir_FindFile(arg, dirSearchPath); path = Dir_FindFile(arg, dirSearchPath);
if (DEBUG(COND)) {
fprintf(debug_file, "exists(%s) result is \"%s\"\n",
arg, path ? path : "");
}
if (path != NULL) { if (path != NULL) {
result = TRUE; result = TRUE;
free(path); free(path);
} else { } else {
result = FALSE; result = FALSE;
} }
if (DEBUG(COND)) {
fprintf(debug_file, "exists(%s) result is \"%s\"\n",
arg, path ? path : "");
}
return (result); return (result);
} }
@ -428,7 +428,7 @@ CondDoExists(int argLen, const char *arg)
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
*/ */
static Boolean static Boolean
CondDoTarget(int argLen, const char *arg) CondDoTarget(int argLen __unused, const char *arg)
{ {
GNode *gn; GNode *gn;
@ -452,7 +452,7 @@ CondDoTarget(int argLen, const char *arg)
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
*/ */
static Boolean static Boolean
CondDoCommands(int argLen, const char *arg) CondDoCommands(int argLen __unused, const char *arg)
{ {
GNode *gn; GNode *gn;
@ -790,7 +790,7 @@ done:
} }
static int 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 * 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 static Boolean
CondDoEmpty(int arglen, const char *arg) CondDoEmpty(int arglen, const char *arg __unused)
{ {
return arglen == 1; return arglen == 1;
} }

View 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. * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@ -132,6 +132,12 @@
#define SYSVINCLUDE #define SYSVINCLUDE
#define SYSVVARSUB #define SYSVVARSUB
/*
* GMAKEEXPORT
* Recognize gmake like variable export directives [export <VAR>=<VALUE>]
*/
#define GMAKEEXPORT
/* /*
* SUNSHCMD * SUNSHCMD
* Recognize SunOS and Solaris: * Recognize SunOS and Solaris:

View 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. * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@ -70,14 +70,14 @@
*/ */
#ifndef MAKE_NATIVE #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 #else
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
#if 0 #if 0
static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94"; static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94";
#else #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
#endif /* not lint */ #endif /* not lint */
#endif #endif
@ -1061,6 +1061,7 @@ Dir_FindFile(const char *name, Lst path)
Boolean hasSlash; /* true if 'name' contains a / */ Boolean hasSlash; /* true if 'name' contains a / */
struct stat stb; /* Buffer for stat, if necessary */ struct stat stb; /* Buffer for stat, if necessary */
Hash_Entry *entry; /* Entry for mtimes table */ Hash_Entry *entry; /* Entry for mtimes table */
const char *trailing_dot = ".";
/* /*
* Find the final component of the name and note whether it has a * 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; return NULL;
} }
if (*cp == '\0') {
/* we were given a trailing "/" */
cp = trailing_dot;
}
if (name[0] != '/') { if (name[0] != '/') {
Boolean checkedDot = FALSE; Boolean checkedDot = FALSE;
@ -1272,6 +1278,10 @@ Dir_FindFile(const char *name, Lst path)
* b/c we added it here. This is not good... * b/c we added it here. This is not good...
*/ */
#ifdef notdef #ifdef notdef
if (cp == traling_dot) {
cp = strrchr(name, '/');
cp += 1;
}
cp[-1] = '\0'; cp[-1] = '\0';
(void)Dir_AddDir(path, name); (void)Dir_AddDir(path, name);
cp[-1] = '/'; cp[-1] = '/';
@ -1418,7 +1428,7 @@ Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen) {
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
*/ */
int int
Dir_MTime(GNode *gn) Dir_MTime(GNode *gn, Boolean recheck)
{ {
char *fullName; /* the full pathname of name */ char *fullName; /* the full pathname of name */
struct stat stb; /* buffer for finding the mod time */ struct stat stb; /* buffer for finding the mod time */
@ -1434,6 +1444,31 @@ Dir_MTime(GNode *gn)
fullName = NULL; fullName = NULL;
else { else {
fullName = Dir_FindFile(gn->name, Suff_FindPath(gn)); 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)) if (DEBUG(DIR))
fprintf(debug_file, "Found '%s' as '%s'\n", fprintf(debug_file, "Found '%s' as '%s'\n",
gn->name, fullName ? fullName : "(not found)" ); gn->name, fullName ? fullName : "(not found)" );
@ -1446,19 +1481,16 @@ Dir_MTime(GNode *gn)
fullName = bmake_strdup(gn->name); fullName = bmake_strdup(gn->name);
} }
entry = Hash_FindEntry(&mtimes, fullName); if (!recheck)
entry = Hash_FindEntry(&mtimes, fullName);
else
entry = NULL;
if (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)) { if (DEBUG(DIR)) {
fprintf(debug_file, "Using cached time %s for %s\n", fprintf(debug_file, "Using cached time %s for %s\n",
Targ_FmtTime(Hash_GetTimeValue(entry)), fullName); Targ_FmtTime(Hash_GetTimeValue(entry)), fullName);
} }
stb.st_mtime = Hash_GetTimeValue(entry); stb.st_mtime = Hash_GetTimeValue(entry);
Hash_DeleteEntry(&mtimes, entry);
} else if (stat(fullName, &stb) < 0) { } else if (stat(fullName, &stb) < 0) {
if (gn->type & OP_MEMBER) { if (gn->type & OP_MEMBER) {
if (fullName != gn->path) if (fullName != gn->path)
@ -1467,12 +1499,16 @@ Dir_MTime(GNode *gn)
} else { } else {
stb.st_mtime = 0; stb.st_mtime = 0;
} }
} else if (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 * 0 handled specially by the code, if the time is really 0,
*/ * return something else instead
stb.st_mtime = 1; */
stb.st_mtime = 1;
}
entry = Hash_CreateEntry(&mtimes, fullName, NULL);
Hash_SetTimeValue(entry, stb.st_mtime);
} }
if (fullName && gn->path == NULL) { if (fullName && gn->path == NULL) {

View 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. * 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); void Dir_Expand(const char *, Lst, Lst);
char *Dir_FindFile(const char *, Lst); char *Dir_FindFile(const char *, Lst);
int Dir_FindHereOrAbove(char *, char *, char *, int); int Dir_FindHereOrAbove(char *, char *, char *, int);
int Dir_MTime(GNode *); int Dir_MTime(GNode *, Boolean);
Path *Dir_AddDir(Lst, const char *); Path *Dir_AddDir(Lst, const char *);
char *Dir_MakeFlags(const char *, Lst); char *Dir_MakeFlags(const char *, Lst);
void Dir_ClearPath(Lst); void Dir_ClearPath(Lst);

View 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. * Copyright (c) 1992, The Regents of the University of California.
@ -30,14 +30,14 @@
*/ */
#ifndef MAKE_NATIVE #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 #else
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
#if 0 #if 0
static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93"; static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93";
#else #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
#endif /* not lint */ #endif /* not lint */
#endif #endif
@ -366,7 +366,7 @@ for_substitute(Buffer *cmds, strlist_t *items, unsigned int item_no, char ech)
} }
static char * static char *
For_Iterate(void *v_arg) For_Iterate(void *v_arg, size_t *ret_len)
{ {
For *arg = v_arg; For *arg = v_arg;
int i, len; int i, len;
@ -451,6 +451,7 @@ For_Iterate(void *v_arg)
arg->sub_next += strlist_num(&arg->vars); arg->sub_next += strlist_num(&arg->vars);
arg->parse_buf = cp; arg->parse_buf = cp;
*ret_len = strlen(cp);
return cp; return cp;
} }

View 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. * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@ -70,14 +70,14 @@
*/ */
#ifndef MAKE_NATIVE #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 #else
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
#if 0 #if 0
static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94";
#else #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
#endif /* not lint */ #endif /* not lint */
#endif #endif
@ -321,10 +321,7 @@ static int readyfd(Job *);
STATIC GNode *lastNode; /* The node for which output was most recently STATIC GNode *lastNode; /* The node for which output was most recently
* produced. */ * produced. */
STATIC const char *targFmt; /* Format string to use to head output from a static char *targPrefix = NULL; /* What we print at the start of TARG_FMT */
* job when it's not the most-recent job heard
* from */
static char *targPrefix = NULL; /* What we print at the start of targFmt */
static Job tokenWaitJob; /* token wait pseudo-job */ static Job tokenWaitJob; /* token wait pseudo-job */
static Job childExitJob; /* child exit 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 TARG_FMT "%s %s ---\n" /* Default format */
#define MESSAGE(fp, gn) \ #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 */ 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)) #define KILLPG(pid, sig) kill(-(pid), (sig))
#else #else
#define KILLPG(pid, sig) killpg((pid), (sig)) #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 JobChildSig(int);
static void JobContinueSig(int); static void JobContinueSig(int);
static Job *JobFindPid(int, int); static Job *JobFindPid(int, int, Boolean);
static int JobPrintCommand(void *, void *); static int JobPrintCommand(void *, void *);
static int JobSaveCommand(void *, void *); static int JobSaveCommand(void *, void *);
static void JobClose(Job *); static void JobClose(Job *);
@ -354,7 +352,7 @@ static int JobStart(GNode *, int);
static char *JobOutput(Job *, char *, char *, int); static char *JobOutput(Job *, char *, char *, int);
static void JobDoOutput(Job *, Boolean); static void JobDoOutput(Job *, Boolean);
static Shell *JobMatchShell(const char *); static Shell *JobMatchShell(const char *);
static void JobInterrupt(int, int); static void JobInterrupt(int, int) __dead;
static void JobRestartJobs(void); static void JobRestartJobs(void);
static void JobTokenAdd(void); static void JobTokenAdd(void);
static void JobSigLock(sigset_t *); static void JobSigLock(sigset_t *);
@ -525,14 +523,14 @@ JobContinueSig(int signo __unused)
* *
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
*/ */
static void __dead static void
JobPassSig_int(int signo) JobPassSig_int(int signo)
{ {
/* Run .INTERRUPT target then exit */ /* Run .INTERRUPT target then exit */
JobInterrupt(TRUE, signo); JobInterrupt(TRUE, signo);
} }
static void __dead static void
JobPassSig_term(int signo) JobPassSig_term(int signo)
{ {
/* Dont run .INTERRUPT target then exit */ /* Dont run .INTERRUPT target then exit */
@ -616,7 +614,7 @@ JobPassSig_suspend(int signo)
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
*/ */
static Job * static Job *
JobFindPid(int pid, int status) JobFindPid(int pid, int status, Boolean isJobs)
{ {
Job *job; Job *job;
@ -624,7 +622,7 @@ JobFindPid(int pid, int status)
if ((job->job_state == status) && job->pid == pid) if ((job->job_state == status) && job->pid == pid)
return job; return job;
} }
if (DEBUG(JOB)) if (DEBUG(JOB) && isJobs)
job_table_dump("no pid"); job_table_dump("no pid");
return NULL; return NULL;
} }
@ -713,6 +711,7 @@ JobPrintCommand(void *cmdp, void *jobp)
shutUp = DEBUG(LOUD) ? FALSE : TRUE; shutUp = DEBUG(LOUD) ? FALSE : TRUE;
break; break;
case '-': case '-':
job->flags |= JOB_IGNERR;
errOff = TRUE; errOff = TRUE;
break; break;
case '+': case '+':
@ -761,7 +760,7 @@ JobPrintCommand(void *cmdp, void *jobp)
} }
if (errOff) { if (errOff) {
if ( !(job->flags & JOB_IGNERR) && !noSpecials) { if (!noSpecials) {
if (commandShell->hasErrCtl) { if (commandShell->hasErrCtl) {
/* /*
* we don't want the error-control commands showing * we don't want the error-control commands showing
@ -1016,10 +1015,15 @@ JobFinish(Job *job, int status)
MESSAGE(stdout, job->node); MESSAGE(stdout, job->node);
lastNode = 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", (void)printf("*** [%s] Error code %d%s\n",
job->node->name, job->node->name,
WEXITSTATUS(status), WEXITSTATUS(status),
(job->flags & JOB_IGNERR) ? "(ignored)" : ""); (job->flags & JOB_IGNERR) ? " (ignored)" : "");
if (job->flags & JOB_IGNERR) { if (job->flags & JOB_IGNERR) {
status = 0; status = 0;
} else { } else {
@ -1044,6 +1048,12 @@ JobFinish(Job *job, int status)
(void)fflush(stdout); (void)fflush(stdout);
} }
#ifdef USE_META
if (useMeta) {
meta_job_finish(job);
}
#endif
return_job_token = FALSE; return_job_token = FALSE;
Trace_Log(JOBEND, job); Trace_Log(JOBEND, job);
@ -1123,7 +1133,8 @@ Job_Touch(GNode *gn, Boolean silent)
int streamID; /* ID of stream opened to do the touch */ int streamID; /* ID of stream opened to do the touch */
struct utimbuf times; /* Times for utime() call */ 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 * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets
* and, as such, shouldn't really be created. * 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); Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn, 0);
if (p1) if (p1)
free(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 * 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 * 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) { 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); msg, gn->name);
(void)fflush(stdout); (void)fflush(stdout);
} else if (keepgoing) { } else if (keepgoing) {
(void)fprintf(stdout, "%s%s %s(continuing)\n", progname, (void)fprintf(stdout, "%s%s %s (continuing)\n", progname,
msg, gn->name); msg, gn->name);
(void)fflush(stdout); (void)fflush(stdout);
return FALSE; return FALSE;
@ -1310,6 +1321,11 @@ JobExec(Job *job, char **argv)
/* Child */ /* Child */
sigset_t tmask; sigset_t tmask;
#ifdef USE_META
if (useMeta) {
meta_job_child(job);
}
#endif
/* /*
* Reset all signal handlers; this is necessary because we also * Reset all signal handlers; this is necessary because we also
* need to unblock signals before we exec(2). * need to unblock signals before we exec(2).
@ -1552,6 +1568,7 @@ JobStart(GNode *gn, int flags)
* also dead... * also dead...
*/ */
if (!cmdsOK) { if (!cmdsOK) {
PrintOnError(gn, NULL); /* provide some clue */
DieHorribly(); DieHorribly();
} }
@ -1572,6 +1589,14 @@ JobStart(GNode *gn, int flags)
*/ */
noExec = FALSE; 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 * We can do all the commands at once. hooray for sanity
*/ */
@ -1844,6 +1869,11 @@ end_loop:
MESSAGE(stdout, job->node); MESSAGE(stdout, job->node);
lastNode = 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)fprintf(stdout, "%s%s", cp, gotNL ? "\n" : "");
(void)fflush(stdout); (void)fflush(stdout);
} }
@ -1926,7 +1956,6 @@ void
Job_CatchChildren(void) Job_CatchChildren(void)
{ {
int pid; /* pid of dead child */ int pid; /* pid of dead child */
Job *job; /* job descriptor for dead child */
int status; /* Exit/termination status */ int status; /* Exit/termination status */
/* /*
@ -1940,41 +1969,60 @@ Job_CatchChildren(void)
(void)fprintf(debug_file, "Process %d exited/stopped status %x.\n", pid, (void)fprintf(debug_file, "Process %d exited/stopped status %x.\n", pid,
status); status);
} }
JobReapChild(pid, status, TRUE);
}
}
job = JobFindPid(pid, JOB_ST_RUNNING); /*
if (job == NULL) { * 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, isJobs);
if (job == NULL) {
if (isJobs) {
if (!lurking_children) if (!lurking_children)
Error("Child (%d) status %x not in table?", pid, status); Error("Child (%d) status %x not in table?", pid, status);
continue;
} }
if (WIFSTOPPED(status)) { return; /* not ours */
if (DEBUG(JOB)) {
(void)fprintf(debug_file, "Process %d (%s) stopped.\n",
job->pid, job->node->name);
}
if (!make_suspended) {
switch (WSTOPSIG(status)) {
case SIGTSTP:
(void)printf("*** [%s] Suspended\n", job->node->name);
break;
case SIGSTOP:
(void)printf("*** [%s] Stopped\n", job->node->name);
break;
default:
(void)printf("*** [%s] Stopped -- signal %d\n",
job->node->name, WSTOPSIG(status));
}
job->job_suspended = 1;
}
(void)fflush(stdout);
continue;
}
job->job_state = JOB_ST_FINISHED;
job->exit_status = status;
JobFinish(job, status);
} }
if (WIFSTOPPED(status)) {
if (DEBUG(JOB)) {
(void)fprintf(debug_file, "Process %d (%s) stopped.\n",
job->pid, job->node->name);
}
if (!make_suspended) {
switch (WSTOPSIG(status)) {
case SIGTSTP:
(void)printf("*** [%s] Suspended\n", job->node->name);
break;
case SIGSTOP:
(void)printf("*** [%s] Stopped\n", job->node->name);
break;
default:
(void)printf("*** [%s] Stopped -- signal %d\n",
job->node->name, WSTOPSIG(status));
}
job->job_suspended = 1;
}
(void)fflush(stdout);
return;
}
job->job_state = JOB_ST_FINISHED;
job->exit_status = status;
JobFinish(job, status);
} }
/*- /*-
@ -2131,16 +2179,6 @@ Job_Init(void)
lastNode = NULL; 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. * There is a non-zero chance that we already have children.
* eg after 'make -f- <<EOF' * eg after 'make -f- <<EOF'

View 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. * 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; struct pollfd;
#ifdef USE_META
# include "meta.h"
#endif
#define JOB_BUFSIZE 1024 #define JOB_BUFSIZE 1024
typedef struct Job { typedef struct Job {
int pid; /* The child's process ID */ int pid; /* The child's process ID */
@ -165,6 +170,10 @@ typedef struct Job {
/* Buffer for storing the output of the /* Buffer for storing the output of the
* job, line by line */ * job, line by line */
int curPos; /* Current position in op_outBuf */ int curPos; /* Current position in op_outBuf */
#ifdef USE_META
struct BuildMon bm;
#endif
} Job; } Job;
#define inPipe jobPipe[0] #define inPipe jobPipe[0]

View 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 * Copyright (c) 1988, 1989, 1990, 1993
@ -69,7 +69,7 @@
*/ */
#ifndef MAKE_NATIVE #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 #else
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
@ -81,7 +81,7 @@ __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\
#if 0 #if 0
static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94";
#else #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
#endif /* not lint */ #endif /* not lint */
#endif #endif
@ -178,11 +178,11 @@ static const char * tracefile;
static char * Check_Cwd_av(int, char **, int); static char * Check_Cwd_av(int, char **, int);
static void MainParseArgs(int, char **); static void MainParseArgs(int, char **);
static int ReadMakefile(const void *, const void *); 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 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 */ static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */
char curdir[MAXPATHLEN + 1]; /* Startup directory */
char *progname; /* the program name */ char *progname; /* the program name */
char *makeDependfile; char *makeDependfile;
pid_t myPid; pid_t myPid;
@ -242,6 +242,9 @@ parse_debug_options(const char *argvalue)
case 'l': case 'l':
debug |= DEBUG_LOUD; debug |= DEBUG_LOUD;
break; break;
case 'M':
debug |= DEBUG_META;
break;
case 'm': case 'm':
debug |= DEBUG_MAKE; debug |= DEBUG_MAKE;
break; break;
@ -684,7 +687,7 @@ ReadAllMakefiles(const void *p, const void *q)
return (ReadMakefile(p, q) == 0); return (ReadMakefile(p, q) == 0);
} }
static int int
str2Lst_Append(Lst lp, char *str, const char *sep) str2Lst_Append(Lst lp, char *str, const char *sep)
{ {
char *cp; char *cp;
@ -703,7 +706,7 @@ str2Lst_Append(Lst lp, char *str, const char *sep)
#ifdef SIGINFO #ifdef SIGINFO
/*ARGSUSED*/ /*ARGSUSED*/
static void static void
siginfo(int signo) siginfo(int signo __unused)
{ {
char dir[MAXPATHLEN]; char dir[MAXPATHLEN];
char str[2 * MAXPATHLEN]; char str[2 * MAXPATHLEN];
@ -732,6 +735,10 @@ MakeMode(const char *mode)
compatMake = TRUE; compatMake = TRUE;
forceJobs = FALSE; forceJobs = FALSE;
} }
#if USE_META
if (strstr(mode, "meta"))
meta_init(mode);
#endif
} }
if (mp) if (mp)
free(mp); free(mp);
@ -762,7 +769,7 @@ main(int argc, char **argv)
struct stat sb, sa; struct stat sb, sa;
char *p1, *path, *pwd; char *p1, *path, *pwd;
char mdpath[MAXPATHLEN]; char mdpath[MAXPATHLEN];
char *machine = getenv("MACHINE"); const char *machine = getenv("MACHINE");
const char *machine_arch = getenv("MACHINE_ARCH"); const char *machine_arch = getenv("MACHINE_ARCH");
char *syspath = getenv("MAKESYSPATH"); char *syspath = getenv("MAKESYSPATH");
Lst sysMkPath; /* Path of sys.mk */ Lst sysMkPath; /* Path of sys.mk */
@ -957,7 +964,8 @@ main(int argc, char **argv)
* We take care of PWD for the automounter below... * We take care of PWD for the automounter below...
*/ */
if (getcwd(curdir, MAXPATHLEN) == NULL) { 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); exit(2);
} }
@ -1300,7 +1308,7 @@ ReadMakefile(const void *p, const void *q __unused)
char *name, *path = bmake_malloc(len); char *name, *path = bmake_malloc(len);
if (!strcmp(fname, "-")) { if (!strcmp(fname, "-")) {
Parse_File("(stdin)", dup(fileno(stdin))); Parse_File(NULL /*stdin*/, -1);
Var_Set("MAKEFILE", "", VAR_GLOBAL, 0); Var_Set("MAKEFILE", "", VAR_GLOBAL, 0);
} else { } else {
/* if we've chdir'd, rebuild the path name */ /* 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. * 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; continue;
}
cc = Buf_Size(&buf); cc = Buf_Size(&buf);
res = Buf_Destroy(&buf, FALSE); res = Buf_Destroy(&buf, FALSE);
@ -1958,20 +1967,10 @@ Main_ExportMAKEFLAGS(Boolean first)
} }
} }
/* char *
* Create and open a temp file using "pattern". getTmpdir(void)
* 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; static char *tmpdir = NULL;
char tfile[MAXPATHLEN];
int fd;
if (!pattern)
pattern = TMPPAT;
if (!tmpdir) { if (!tmpdir) {
struct stat st; struct stat st;
@ -1986,6 +1985,25 @@ mkTempFile(const char *pattern, char **fnamep)
tmpdir = bmake_strdup(_PATH_TMP); 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] == '/') { if (pattern[0] == '/') {
snprintf(tfile, sizeof(tfile), "%s", pattern); snprintf(tfile, sizeof(tfile), "%s", pattern);
} else { } else {

View 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 .\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved. .\" The Regents of the University of California. All rights reserved.
@ -29,7 +29,7 @@
.\" .\"
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94 .\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
.\" .\"
.Dd June 9, 2010 .Dd March 31, 2012
.Dt MAKE 1 .Dt MAKE 1
.Os .Os
.Sh NAME .Sh NAME
@ -38,40 +38,18 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl BeikNnqrstWX .Op Fl BeikNnqrstWX
.Bk -words
.Op Fl C Ar directory .Op Fl C Ar directory
.Ek
.Bk -words
.Op Fl D Ar variable .Op Fl D Ar variable
.Ek
.Bk -words
.Op Fl d Ar flags .Op Fl d Ar flags
.Ek
.Bk -words
.Op Fl f Ar makefile .Op Fl f Ar makefile
.Ek
.Bk -words
.Op Fl I Ar directory .Op Fl I Ar directory
.Ek
.Bk -words
.Op Fl J Ar private .Op Fl J Ar private
.Ek
.Bk -words
.Op Fl j Ar max_jobs .Op Fl j Ar max_jobs
.Ek
.Bk -words
.Op Fl m Ar directory .Op Fl m Ar directory
.Ek
.Bk -words
.Op Fl T Ar file .Op Fl T Ar file
.Ek
.Bk -words
.Op Fl V Ar variable .Op Fl V Ar variable
.Ek
.Op Ar variable=value .Op Ar variable=value
.Bk -words
.Op Ar target ... .Op Ar target ...
.Ek
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
is a program designed to simplify the maintenance of other programs. 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 For a more thorough description of
.Nm .Nm
and makefiles, please refer to and makefiles, please refer to
.%T "Make \- A Tutorial" . .%T "PMake \- A Tutorial" .
.Pp .Pp
.Nm .Nm
will prepend the contents of the will prepend the contents of the
@ -126,7 +104,7 @@ Turn on debugging, and specify which portions of
.Nm .Nm
are to print debugging information. are to print debugging information.
Unless the flags are preceded by Unless the flags are preceded by
.Ql - .Ql \-
they are added to the they are added to the
.Va MAKEFLAGS .Va MAKEFLAGS
environment variable and will be processed by any child make processes. 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 @ .Ql @
or other "quiet" flags. or other "quiet" flags.
Also known as "loud" behavior. Also known as "loud" behavior.
.It Ar M
Print debugging information about "meta" mode decisions about targets.
.It Ar m .It Ar m
Print debugging information about making targets, including modification Print debugging information about making targets, including modification
dates. dates.
@ -266,6 +246,8 @@ cooperate to avoid overloading the system.
Specify the maximum number of jobs that Specify the maximum number of jobs that
.Nm .Nm
may have running at any one time. may have running at any one time.
The value is saved in
.Va .MAKE.JOBS .
Turns compatibility mode off, unless the Turns compatibility mode off, unless the
.Ar B .Ar B
flag is also specified. flag is also specified.
@ -613,7 +595,7 @@ The list of sources for this target that were deemed out-of-date; also
known as known as
.Ql Va \&? . .Ql Va \&? .
.It Va .PREFIX .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 or preceding directory components; also known as
.Ql Va * . .Ql Va * .
.It Va .TARGET .It Va .TARGET
@ -759,9 +741,73 @@ Processed after reading all makefiles.
Can affect the mode that Can affect the mode that
.Nm .Nm
runs in. runs in.
Currently just It can contain a number of keywords:
.Ql Pa compat .Bl -hang -width ignore-cmd
mode. .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 .It Va .MAKEOVERRIDES
This variable is used to record the names of variables assigned to 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 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 are both set only while the
.Ql Pa Makefiles .Ql Pa Makefiles
are being parsed. 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 .It Va .PATH
A variable that represents the list of directories that A variable that represents the list of directories that
.Nm .Nm
@ -892,6 +941,8 @@ is set to the value of
for all programs which for all programs which
.Nm .Nm
executes. executes.
.It Ev .TARGETS
The list of targets explicitly specified on the command line, if any.
.It Ev VPATH .It Ev VPATH
Colon-separated Colon-separated
.Pq Dq \&: .Pq Dq \&:
@ -988,6 +1039,18 @@ safely through recursive invocations of
.Nm . .Nm .
.It Cm \&:R .It Cm \&:R
Replaces each word in the variable with everything but its suffix. 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 .It Cm \&:tA
Attempt to convert variable to an absolute path using Attempt to convert variable to an absolute path using
.Xr realpath 3 , .Xr realpath 3 ,
@ -1127,7 +1190,7 @@ A common error is trying to use expressions like
.Dl ${NUMBERS:M42:?match:no} .Dl ${NUMBERS:M42:?match:no}
which actually tests defined(NUMBERS), which actually tests defined(NUMBERS),
to determine is any words match "42" you need to use something like: 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 .It Ar :old_string=new_string
This is the This is the
.At V .At V
@ -1175,6 +1238,9 @@ The ODE convention is that
should start and end with a period. should start and end with a period.
For example. For example.
.Dl ${LINKS:@.LINK.@${LN} ${TARGET} ${.LINK.}@} .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 .It Cm \&:U Ns Ar newval
If the variable is undefined If the variable is undefined
.Ar newval .Ar newval
@ -1196,6 +1262,8 @@ The path of the node which has the same name as the variable
is the value. is the value.
If no such node exists or its path is null, then the If no such node exists or its path is null, then the
name of the variable is used. 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 .Sm off
.It Cm \&:\&! Ar cmd Cm \&! .It Cm \&:\&! Ar cmd Cm \&!
.Sm on .Sm on
@ -1256,7 +1324,7 @@ For the purposes of the
modifier, the words are indexed both forwards using positive integers modifier, the words are indexed both forwards using positive integers
(where index 1 represents the first word), (where index 1 represents the first word),
and backwards using negative integers and backwards using negative integers
(where index -1 represents the last word). (where index \-1 represents the last word).
.Pp .Pp
The The
.Ar range .Ar range
@ -1355,6 +1423,11 @@ except for internal variables (those that start with
This is not affected by the This is not affected by the
.Fl X .Fl X
flag, so should be used with caution. flag, so should be used with caution.
For compatibility with other
.Nm
programs
.Ql export variable=value
is also accepted.
.Pp .Pp
Appending a variable name to Appending a variable name to
.Va .MAKE.EXPORTED .Va .MAKE.EXPORTED
@ -1610,6 +1683,28 @@ or
options were specified. options were specified.
Normally used to mark recursive Normally used to mark recursive
.Nm Ns 's . .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 .It Ic .NOPATH
Do not search for the target in the directories specified by Do not search for the target in the directories specified by
.Ic .PATH . .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 and will not be created with the
.Fl t .Fl t
option. option.
Suffix-transformation rules are not applied to
.Ic .PHONY
targets.
.It Ic .PRECIOUS .It Ic .PRECIOUS
When When
.Nm .Nm
@ -1769,7 +1867,7 @@ could be built, unless
is built by another part of the dependency graph, is built by another part of the dependency graph,
the following is a dependency loop: the following is a dependency loop:
.Bd -literal .Bd -literal
\&.ORDER: a b \&.ORDER: b a
b: a b: a
.Ed .Ed
.Pp .Pp
@ -1846,8 +1944,8 @@ character when used outside of any quoting characters.
Example: Example:
.Bd -literal .Bd -literal
\&.SHELL: name=ksh path=/bin/ksh hasErrCtl=true \e \&.SHELL: name=ksh path=/bin/ksh hasErrCtl=true \e
check="set -e" ignore="set +e" \e check="set \-e" ignore="set +e" \e
echo="set -v" quiet="set +v" filter="set +v" \e echo="set \-v" quiet="set +v" filter="set +v" \e
echoFlag=v errFlag=e newline="'\en'" echoFlag=v errFlag=e newline="'\en'"
.Ed .Ed
.It Ic .SILENT .It Ic .SILENT
@ -1868,7 +1966,7 @@ Example:
.Bd -literal .Bd -literal
\&.SUFFIXES: .o \&.SUFFIXES: .o
\&.c.o: \&.c.o:
cc -o ${.TARGET} -c ${.IMPSRC} cc \-o ${.TARGET} \-c ${.IMPSRC}
.Ed .Ed
.El .El
.Sh ENVIRONMENT .Sh ENVIRONMENT
@ -1913,7 +2011,7 @@ however the special variables, variable modifiers and conditionals are not.
.Pp .Pp
The way that parallel makes are scheduled changed in The way that parallel makes are scheduled changed in
.Nx 4.0 .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. The algorithms used may change again in the future.
.Pp .Pp
The way that .for loop variables are substituted changed after 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. so that they still appear to be variable expansions.
In particular this stops them being treated as syntax, and removes some In particular this stops them being treated as syntax, and removes some
obscure problems using them in .if statements. 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 .Sh SEE ALSO
.Xr mkdep 1 .Xr mkdep 1
.Sh HISTORY .Sh HISTORY
@ -1928,6 +2041,13 @@ A
.Nm .Nm
command appeared in command appeared in
.At v7 . .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 .Sh BUGS
The The
.Nm .Nm

View 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 * Copyright (c) 1988, 1989, 1990, 1993
@ -69,14 +69,14 @@
*/ */
#ifndef MAKE_NATIVE #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 #else
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
#if 0 #if 0
static char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93"; static char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93";
#else #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
#endif /* not lint */ #endif /* not lint */
#endif #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 * Make_Update Update all parents of a given child. Performs
* various bookkeeping chores like the updating * 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 * of the IMPSRC context variable, etc. It will
* place the parent on the toBeMade queue if it * place the parent on the toBeMade queue if it
* should be. * 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. * based on a child's modification time.
* *
* Make_DoAllVar Set up the various local variables for a * 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 MakeBuildChild(void *, void *);
static int MakeBuildParent(void *, void *); static int MakeBuildParent(void *, void *);
static void __dead static void
make_abort(GNode *gn, int line) make_abort(GNode *gn, int line)
{ {
static int two = 2; static int two = 2;
@ -154,7 +154,7 @@ make_abort(GNode *gn, int line)
/*- /*-
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
* Make_TimeStamp -- * 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. * child. Called from MakeOODate via Lst_ForEach.
* *
* Input: * Input:
@ -165,15 +165,15 @@ make_abort(GNode *gn, int line)
* Always returns 0. * Always returns 0.
* *
* Side Effects: * 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. * field of the child is greater than it.
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
*/ */
int int
Make_TimeStamp(GNode *pgn, GNode *cgn) Make_TimeStamp(GNode *pgn, GNode *cgn)
{ {
if (cgn->mtime > pgn->cmtime) { if (pgn->cmgn == NULL || cgn->mtime > pgn->cmgn->mtime) {
pgn->cmtime = cgn->mtime; pgn->cmgn = cgn;
} }
return (0); return (0);
} }
@ -207,7 +207,7 @@ MakeTimeStamp(void *pgn, void *cgn)
* TRUE if the node is out of date. FALSE otherwise. * TRUE if the node is out of date. FALSE otherwise.
* *
* Side Effects: * 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. * will/may be changed.
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
*/ */
@ -221,7 +221,7 @@ Make_OODate(GNode *gn)
* doesn't depend on their modification time... * doesn't depend on their modification time...
*/ */
if ((gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC)) == 0) { 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 (DEBUG(MAKE)) {
if (gn->mtime != 0) { if (gn->mtime != 0) {
fprintf(debug_file, "modified %s...", Targ_FmtTime(gn->mtime)); fprintf(debug_file, "modified %s...", Targ_FmtTime(gn->mtime));
@ -265,7 +265,7 @@ Make_OODate(GNode *gn)
* or non-existent. * or non-existent.
*/ */
oodate = (gn->mtime == 0 || Arch_LibOODate(gn) || 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) { } else if (gn->type & OP_JOIN) {
/* /*
* A target with the .JOIN attribute is only considered * A target with the .JOIN attribute is only considered
@ -293,21 +293,22 @@ Make_OODate(GNode *gn)
} }
} }
oodate = TRUE; oodate = TRUE;
} else if (gn->mtime < gn->cmtime || } else if ((gn->cmgn != NULL && gn->mtime < gn->cmgn->mtime) ||
(gn->cmtime == 0 && (gn->cmgn == NULL &&
((gn->mtime == 0 && !(gn->type & OP_OPTIONAL)) ((gn->mtime == 0 && !(gn->type & OP_OPTIONAL))
|| gn->type & OP_DOUBLEDEP))) || gn->type & OP_DOUBLEDEP)))
{ {
/* /*
* A node whose modification time is less than that of its * 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 * either doesn't exist (mtime == 0) and it isn't optional
* or was the object of a * :: operator is out-of-date. * or was the object of a * :: operator is out-of-date.
* Why? Because that's the way Make does it. * Why? Because that's the way Make does it.
*/ */
if (DEBUG(MAKE)) { if (DEBUG(MAKE)) {
if (gn->mtime < gn->cmtime) { if (gn->cmgn != NULL && gn->mtime < gn->cmgn->mtime) {
fprintf(debug_file, "modified before source..."); fprintf(debug_file, "modified before source %s...",
gn->cmgn->path);
} else if (gn->mtime == 0) { } else if (gn->mtime == 0) {
fprintf(debug_file, "non-existent and no sources..."); fprintf(debug_file, "non-existent and no sources...");
} else { } else {
@ -330,6 +331,12 @@ Make_OODate(GNode *gn)
oodate = (gn->flags & FORCE) ? TRUE : FALSE; 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 * 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 * modification time. Note that targets that appear to be out-of-date
@ -389,7 +396,7 @@ MakeAddChild(void *gnp, void *lp)
* Always returns 0 * Always returns 0
* *
* Side Effects: * 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. * updated; the unmade children count of the parent is decremented.
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
*/ */
@ -399,7 +406,7 @@ MakeFindChild(void *gnp, void *pgnp)
GNode *gn = (GNode *)gnp; GNode *gn = (GNode *)gnp;
GNode *pgn = (GNode *)pgnp; GNode *pgn = (GNode *)pgnp;
(void)Dir_MTime(gn); (void)Dir_MTime(gn, 0);
Make_TimeStamp(pgn, gn); Make_TimeStamp(pgn, gn);
pgn->unmade--; pgn->unmade--;
@ -567,7 +574,7 @@ MakeHandleUse(void *cgnp, void *pgnp)
time_t time_t
Make_Recheck(GNode *gn) Make_Recheck(GNode *gn)
{ {
time_t mtime = Dir_MTime(gn); time_t mtime = Dir_MTime(gn, 1);
#ifndef RECHECK #ifndef RECHECK
/* /*
@ -657,12 +664,12 @@ Make_Recheck(GNode *gn)
* the toBeMade queue if this field becomes 0. * the toBeMade queue if this field becomes 0.
* *
* If the child was made, the parent's flag CHILDMADE field will be * 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, * If the child is not up-to-date and still does not exist,
* set the FORCE flag on the parents. * 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. * altered if the child's mtime is big enough.
* *
* Finally, if the child is the implied source for the parent, the * Finally, if the child is the implied source for the parent, the
@ -1329,7 +1336,7 @@ Make_ExpandUse(Lst targs)
*eon = ')'; *eon = ')';
} }
(void)Dir_MTime(gn); (void)Dir_MTime(gn, 0);
Var_Set(TARGET, gn->path ? gn->path : gn->name, gn, 0); Var_Set(TARGET, gn->path ? gn->path : gn->name, gn, 0);
Lst_ForEach(gn->children, MakeUnmark, gn); Lst_ForEach(gn->children, MakeUnmark, gn);
Lst_ForEach(gn->children, MakeHandleUse, gn); Lst_ForEach(gn->children, MakeHandleUse, gn);

View 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 * Copyright (c) 1988, 1989, 1990, 1993
@ -111,6 +111,10 @@
#endif #endif
#endif #endif
#if !defined(__dead)
#define __dead
#endif
#include "sprite.h" #include "sprite.h"
#include "lst.h" #include "lst.h"
#include "hash.h" #include "hash.h"
@ -187,8 +191,7 @@ typedef struct GNode {
int unmade; /* The number of unmade children */ int unmade; /* The number of unmade children */
time_t mtime; /* Its modification time */ time_t mtime; /* Its modification time */
time_t cmtime; /* The modification time of its youngest struct GNode *cmgn; /* The youngest child */
* child */
Lst iParents; /* Links to parents for which this is an Lst iParents; /* Links to parents for which this is an
* implied source, if any */ * implied source, if any */
@ -260,6 +263,9 @@ typedef struct GNode {
#define OP_PHONY 0x00010000 /* Not a file target; run always */ #define OP_PHONY 0x00010000 /* Not a file target; run always */
#define OP_NOPATH 0x00020000 /* Don't search for file in the path */ #define OP_NOPATH 0x00020000 /* Don't search for file in the path */
#define OP_WAIT 0x00040000 /* .WAIT phony node */ #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 */ /* Attributes applied by PMake */
#define OP_TRANSFORM 0x80000000 /* The node is a transformation rule */ #define OP_TRANSFORM 0x80000000 /* The node is a transformation rule */
#define OP_MEMBER 0x40000000 /* Target is a member of an archive */ #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 sysIncPath; /* The system include path. */
extern Lst defIncPath; /* The default include path. */ extern Lst defIncPath; /* The default include path. */
extern char curdir[]; /* Startup directory */
extern char *progname; /* The program name */ extern char *progname; /* The program name */
extern char *makeDependfile; /* .depend */ extern char *makeDependfile; /* .depend */
@ -399,11 +406,7 @@ extern char *makeDependfile; /* .depend */
* We cannot vfork() in a child of vfork(). * We cannot vfork() in a child of vfork().
* Most systems do not enforce this but some do. * Most systems do not enforce this but some do.
*/ */
#if defined(__minix)
#define vFork() fork()
#else
#define vFork() ((getpid() == myPid) ? vfork() : fork()) #define vFork() ((getpid() == myPid) ? vfork() : fork())
#endif
extern pid_t myPid; extern pid_t myPid;
#define MAKEFLAGS ".MAKEFLAGS" #define MAKEFLAGS ".MAKEFLAGS"
@ -437,6 +440,8 @@ extern int debug;
#define DEBUG_SHELL 0x00800 #define DEBUG_SHELL 0x00800
#define DEBUG_ERROR 0x01000 #define DEBUG_ERROR 0x01000
#define DEBUG_LOUD 0x02000 #define DEBUG_LOUD 0x02000
#define DEBUG_META 0x04000
#define DEBUG_GRAPH3 0x10000 #define DEBUG_GRAPH3 0x10000
#define DEBUG_SCRIPT 0x20000 #define DEBUG_SCRIPT 0x20000
#define DEBUG_PARSE 0x40000 #define DEBUG_PARSE 0x40000
@ -462,6 +467,7 @@ void PrintOnError(GNode *, const char *);
void Main_ExportMAKEFLAGS(Boolean); void Main_ExportMAKEFLAGS(Boolean);
Boolean Main_SetObjdir(const char *); Boolean Main_SetObjdir(const char *);
int mkTempFile(const char *, char **); int mkTempFile(const char *, char **);
int str2Lst_Append(Lst, char *, const char *);
#ifdef __GNUC__ #ifdef __GNUC__
#define UNCONST(ptr) ({ \ #define UNCONST(ptr) ({ \

View 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. * Copyright (c) 2009 The NetBSD Foundation, Inc.
@ -28,7 +28,7 @@
#ifdef MAKE_NATIVE #ifdef MAKE_NATIVE
#include <sys/cdefs.h> #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 #endif
#include <stdio.h> #include <stdio.h>
@ -48,7 +48,7 @@ enomem(void)
{ {
extern char *progname; extern char *progname;
(void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); (void)fprintf(stderr, "%s: %s.\n", progname, strerror(ENOMEM));
exit(2); exit(2);
} }

1346
usr.bin/make/meta.c Normal file

File diff suppressed because it is too large Load diff

54
usr.bin/make/meta.h Normal file
View file

@ -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);

View 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 * Copyright (c) 1988, 1989, 1990, 1993
@ -106,6 +106,9 @@ int For_Eval(char *);
int For_Accum(char *); int For_Accum(char *);
void For_Run(int); void For_Run(int);
/* job.c */
void JobReapChild(pid_t, int, Boolean);
/* main.c */ /* main.c */
void Main_ParseArgLine(const char *); void Main_ParseArgLine(const char *);
void MakeMode(const char *); void MakeMode(const char *);
@ -118,9 +121,10 @@ void Punt(const char *, ...)
__attribute__((__format__(__printf__, 1, 2),__noreturn__)); __attribute__((__format__(__printf__, 1, 2),__noreturn__));
void DieHorribly(void) __attribute__((__noreturn__)); void DieHorribly(void) __attribute__((__noreturn__));
int PrintAddr(void *, void *); int PrintAddr(void *, void *);
void Finish(int); void Finish(int) __dead;
int eunlink(const char *); int eunlink(const char *);
void execError(const char *, const char *); void execError(const char *, const char *);
char *getTmpdir(void);
/* parse.c */ /* parse.c */
void Parse_Error(int, const char *, ...) void Parse_Error(int, const char *, ...)
@ -132,7 +136,7 @@ void Parse_AddIncludeDir(char *);
void Parse_File(const char *, int); void Parse_File(const char *, int);
void Parse_Init(void); void Parse_Init(void);
void Parse_End(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); Lst Parse_MainName(void);
/* str.c */ /* str.c */

View 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 * Copyright (c) 1988, 1989, 1990, 1993
@ -69,14 +69,14 @@
*/ */
#ifndef MAKE_NATIVE #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 #else
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
#if 0 #if 0
static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94"; static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94";
#else #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
#endif /* not lint */ #endif /* not lint */
#endif #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. * 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 <ctype.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.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 "make.h"
#include "hash.h" #include "hash.h"
#include "dir.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 "buf.h"
#include "pathnames.h" #include "pathnames.h"
////////////////////////////////////////////////////////////
// types and constants
/*
* Structure for a file being read ("included file")
*/
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 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 */
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;
/* /*
* These values are returned by ParseEOF to tell Parse_File whether to * 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, * CONTINUE parsing, i.e. it had only reached the end of an include file,
* or if it's DONE. * or if it's DONE.
*/ */
#define CONTINUE 1 #define CONTINUE 1
#define DONE 0 #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 */
void *nextbuf_arg; /* Opaque arg for nextbuf() */
} IFile;
#define IFILE_BUFLEN 0x8000
static IFile *curFile;
/* /*
* Definitions for handling #include specifications * Tokens for target attributes
*/
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
*/ */
typedef enum { typedef enum {
Begin, /* .BEGIN */ Begin, /* .BEGIN */
@ -196,10 +187,13 @@ typedef enum {
Includes, /* .INCLUDES */ Includes, /* .INCLUDES */
Interrupt, /* .INTERRUPT */ Interrupt, /* .INTERRUPT */
Libs, /* .LIBS */ Libs, /* .LIBS */
Meta, /* .META */
MFlags, /* .MFLAGS or .MAKEFLAGS */ MFlags, /* .MFLAGS or .MAKEFLAGS */
Main, /* .MAIN and we don't have anything user-specified to Main, /* .MAIN and we don't have anything user-specified to
* make */ * make */
NoExport, /* .NOEXPORT */ NoExport, /* .NOEXPORT */
NoMeta, /* .NOMETA */
NoMetaCmp, /* .NOMETA_CMP */
NoPath, /* .NOPATH */ NoPath, /* .NOPATH */
Not, /* Not special */ Not, /* Not special */
NotParallel, /* .NOTPARALLEL */ NotParallel, /* .NOTPARALLEL */
@ -221,16 +215,74 @@ typedef enum {
Attribute /* Generic attribute */ Attribute /* Generic attribute */
} ParseSpecial; } 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; static ParseSpecial specType;
#define LPAREN '('
#define RPAREN ')'
/* /*
* Predecessor node for handling .ORDER. Initialized to NULL when .ORDER * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER
* seen, then set to each successive source on the line. * seen, then set to each successive source on the line.
*/ */
static GNode *predecessor; 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 * The parseKeywords table is searched using binary search when deciding
* if a target or source is special. The 'spec' field is the ParseSpecial * 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 * 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) * 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 */ const char *name; /* Name of keyword */
ParseSpecial spec; /* Type when used as a target */ ParseSpecial spec; /* Type when used as a target */
int op; /* Operator when used as a source */ int op; /* Operator when used as a source */
@ -258,7 +310,10 @@ static struct {
{ ".MAIN", Main, 0 }, { ".MAIN", Main, 0 },
{ ".MAKE", Attribute, OP_MAKE }, { ".MAKE", Attribute, OP_MAKE },
{ ".MAKEFLAGS", MFlags, 0 }, { ".MAKEFLAGS", MFlags, 0 },
{ ".META", Meta, OP_META },
{ ".MFLAGS", MFlags, 0 }, { ".MFLAGS", MFlags, 0 },
{ ".NOMETA", NoMeta, OP_NOMETA },
{ ".NOMETA_CMP", NoMetaCmp, OP_NOMETA_CMP },
{ ".NOPATH", NoPath, OP_NOPATH }, { ".NOPATH", NoPath, OP_NOPATH },
{ ".NOTMAIN", Attribute, OP_NOTMAIN }, { ".NOTMAIN", Attribute, OP_NOTMAIN },
{ ".NOTPARALLEL", NotParallel, 0 }, { ".NOTPARALLEL", NotParallel, 0 },
@ -284,6 +339,9 @@ static struct {
{ ".WAIT", Wait, 0 }, { ".WAIT", Wait, 0 },
}; };
////////////////////////////////////////////////////////////
// local functions
static int ParseIsEscaped(const char *, const char *); static int ParseIsEscaped(const char *, const char *);
static void ParseErrorInternal(const char *, size_t, int, const char *, ...) static void ParseErrorInternal(const char *, size_t, int, const char *, ...)
__attribute__((__format__(__printf__, 4, 5))); __attribute__((__format__(__printf__, 4, 5)));
@ -304,13 +362,220 @@ static void ParseSetParseFile(const char *);
#ifdef SYSVINCLUDE #ifdef SYSVINCLUDE
static void ParseTraditionalInclude(char *); static void ParseTraditionalInclude(char *);
#endif #endif
#ifdef GMAKEEXPORT
static void ParseGmakeExport(char *);
#endif
static int ParseEOF(void); static int ParseEOF(void);
static char *ParseReadLine(void); static char *ParseReadLine(void);
static void ParseFinishLine(void); static void ParseFinishLine(void);
static void ParseMark(GNode *); 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; const char *dir;
/* /*
* Nothing is more anoying than not knowing * Nothing is more annoying than not knowing
* which Makefile is the culprit. * which Makefile is the culprit.
*/ */
dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &cp); dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &cp);
@ -915,7 +1180,7 @@ ParseDoDependency(char *line)
tOp = 0; tOp = 0;
specType = Not; specType = Not;
paths = (Lst)NULL; paths = NULL;
curTargs = Lst_Init(FALSE); curTargs = Lst_Init(FALSE);
@ -1085,7 +1350,7 @@ ParseDoDependency(char *line)
&line[5]); &line[5]);
goto out; goto out;
} else { } else {
if (paths == (Lst)NULL) { if (paths == NULL) {
paths = Lst_Init(FALSE); paths = Lst_Init(FALSE);
} }
(void)Lst_AtEnd(paths, path); (void)Lst_AtEnd(paths, path);
@ -1786,6 +2051,7 @@ Parse_AddIncludeDir(char *dir)
static void static void
Parse_include_file(char *file, Boolean isSystem, int silent) Parse_include_file(char *file, Boolean isSystem, int silent)
{ {
struct loadedfile *lf;
char *fullname; /* full pathname of file */ char *fullname; /* full pathname of file */
char *newName; char *newName;
char *prefEnd, *incdir; char *prefEnd, *incdir;
@ -1876,8 +2142,12 @@ Parse_include_file(char *file, Boolean isSystem, int silent)
return; return;
} }
/* load it */
lf = loadfile(fullname, fd);
/* Start reading from this file next */ /* 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 static void
@ -1949,23 +2219,27 @@ ParseDoInclude(char *line)
static void static void
ParseSetParseFile(const char *filename) ParseSetParseFile(const char *filename)
{ {
char *slash; char *slash, *dirname;
char *dirname; const char *pd, *pf;
int len; int len;
slash = strrchr(filename, '/'); slash = strrchr(filename, '/');
if (slash == NULL) { if (slash == NULL) {
Var_Set(".PARSEDIR", ".", VAR_GLOBAL, 0); Var_Set(".PARSEDIR", pd = curdir, VAR_GLOBAL, 0);
Var_Set(".PARSEFILE", filename, VAR_GLOBAL, 0); Var_Set(".PARSEFILE", pf = filename, VAR_GLOBAL, 0);
dirname= NULL;
} else { } else {
len = slash - filename; len = slash - filename;
dirname = bmake_malloc(len + 1); dirname = bmake_malloc(len + 1);
memcpy(dirname, filename, len); memcpy(dirname, filename, len);
dirname[len] = 0; dirname[len] = '\0';
Var_Set(".PARSEDIR", dirname, VAR_GLOBAL, 0); Var_Set(".PARSEDIR", pd = dirname, VAR_GLOBAL, 0);
Var_Set(".PARSEFILE", slash+1, VAR_GLOBAL, 0); Var_Set(".PARSEFILE", pf = slash + 1, VAR_GLOBAL, 0);
free(dirname);
} }
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 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; char *buf;
size_t len;
if (name == NULL) if (name == NULL)
name = curFile->fname; name = curFile->fname;
@ -2047,33 +2323,22 @@ Parse_SetInput(const char *name, int line, int fd, char *(*nextbuf)(void *), voi
curFile->fname = name; curFile->fname = name;
curFile->lineno = line; curFile->lineno = line;
curFile->first_lineno = line; curFile->first_lineno = line;
curFile->fd = fd;
curFile->nextbuf = nextbuf; curFile->nextbuf = nextbuf;
curFile->nextbuf_arg = arg; curFile->nextbuf_arg = arg;
curFile->lf = NULL;
if (nextbuf == NULL) { assert(nextbuf != NULL);
/*
* Allocate a 32k data buffer (as stdio seems to). /* Get first block of input data */
* Set pointers so that first ParseReadc has to do a file read. buf = curFile->nextbuf(curFile->nextbuf_arg, &len);
*/ if (buf == NULL) {
buf = bmake_malloc(IFILE_BUFLEN); /* Was all a waste of time ... */
buf[0] = 0; free(curFile);
curFile->P_str = buf; return;
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;
} }
curFile->P_str = buf;
curFile->P_ptr = buf;
curFile->P_end = buf+len;
curFile->cond_depth = Cond_save_depth(); curFile->cond_depth = Cond_save_depth();
ParseSetParseFile(name); ParseSetParseFile(name);
@ -2143,6 +2408,55 @@ ParseTraditionalInclude(char *line)
} }
#endif #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 -- * ParseEOF --
@ -2162,26 +2476,31 @@ static int
ParseEOF(void) ParseEOF(void)
{ {
char *ptr; char *ptr;
size_t len;
if (curFile->nextbuf != NULL) { assert(curFile->nextbuf != NULL);
/* eg .for loop data, get next iteration */
ptr = curFile->nextbuf(curFile->nextbuf_arg); /* get next input buffer, if any */
curFile->P_ptr = ptr; ptr = curFile->nextbuf(curFile->nextbuf_arg, &len);
curFile->P_str = ptr; curFile->P_ptr = ptr;
curFile->lineno = curFile->first_lineno; curFile->P_str = ptr;
if (ptr != NULL) { curFile->P_end = ptr + len;
/* Iterate again */ curFile->lineno = curFile->first_lineno;
return CONTINUE; if (ptr != NULL) {
} /* Iterate again */
return CONTINUE;
} }
/* Ensure the makefile (or loop) didn't have mismatched conditionals */ /* Ensure the makefile (or loop) didn't have mismatched conditionals */
Cond_restore_depth(curFile->cond_depth); Cond_restore_depth(curFile->cond_depth);
if (curFile->lf != NULL) {
loadedfile_destroy(curFile->lf);
curFile->lf = NULL;
}
/* Dispose of curFile info */ /* Dispose of curFile info */
/* Leak curFile->fname because all the gnodes have pointers to it */ /* Leak curFile->fname because all the gnodes have pointers to it */
if (curFile->fd != -1)
close(curFile->fd);
free(curFile->P_str); free(curFile->P_str);
free(curFile); free(curFile);
@ -2195,8 +2514,8 @@ ParseEOF(void)
} }
if (DEBUG(PARSE)) if (DEBUG(PARSE))
fprintf(debug_file, "ParseEOF: returning to file %s, line %d, fd %d\n", fprintf(debug_file, "ParseEOF: returning to file %s, line %d\n",
curFile->fname, curFile->lineno, curFile->fd); curFile->fname, curFile->lineno);
/* Restore the PARSEDIR/PARSEFILE variables */ /* Restore the PARSEDIR/PARSEFILE variables */
ParseSetParseFile(curFile->fname); ParseSetParseFile(curFile->fname);
@ -2217,7 +2536,6 @@ ParseGetLine(int flags, int *length)
char *escaped; char *escaped;
char *comment; char *comment;
char *tp; char *tp;
int len, dist;
/* Loop through blank lines and comment lines */ /* Loop through blank lines and comment lines */
for (;;) { for (;;) {
@ -2228,67 +2546,25 @@ ParseGetLine(int flags, int *length)
escaped = NULL; escaped = NULL;
comment = NULL; comment = NULL;
for (;;) { for (;;) {
if (cf->P_end != NULL && ptr == cf->P_end) {
/* end of buffer */
ch = 0;
break;
}
ch = *ptr; ch = *ptr;
if (ch == 0 || (ch == '\\' && ptr[1] == 0)) { if (ch == 0 || (ch == '\\' && ptr[1] == 0)) {
if (cf->P_end == NULL) if (cf->P_end == NULL)
/* End of string (aka for loop) data */ /* End of string (aka for loop) data */
break; break;
/* End of data read from file, read more data */ if (cf->nextbuf != NULL) {
if (ptr != cf->P_end && (ch != '\\' || ptr + 1 != cf->P_end)) { /*
Parse_Error(PARSE_FATAL, "Zero byte read from file"); * End of this buffer; return EOF and outer logic
return NULL; * will get the next one. (eww)
} */
/* 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 */
break; break;
} }
/* 0 terminate the data, and update end pointer */ Parse_Error(PARSE_FATAL, "Zero byte read from file");
tp += len; return NULL;
cf->P_end = tp;
*tp = 0;
/* Process newly read characters */
continue;
} }
if (ch == '\\') { if (ch == '\\') {
@ -2303,7 +2579,9 @@ ParseGetLine(int flags, int *length)
} }
if (ch == '#' && comment == NULL) { if (ch == '#' && comment == NULL) {
/* Remember first '#' for comment stripping */ /* Remember first '#' for comment stripping */
comment = line_end; /* Unless previous char was '[', as in modifier :[#] */
if (!(ptr > line && ptr[-1] == '['))
comment = line_end;
} }
ptr++; ptr++;
if (ch == '\n') if (ch == '\n')
@ -2459,7 +2737,7 @@ ParseReadLine(void)
line = ParseGetLine(PARSE_RAW, &lineLength); line = ParseGetLine(PARSE_RAW, &lineLength);
if (line == NULL) { if (line == NULL) {
Parse_Error(PARSE_FATAL, Parse_Error(PARSE_FATAL,
"Unexpected end of file in for loop.\n"); "Unexpected end of file in for loop.");
break; break;
} }
} while (For_Accum(line)); } while (For_Accum(line));
@ -2522,11 +2800,19 @@ Parse_File(const char *name, int fd)
{ {
char *cp; /* pointer into the line */ char *cp; /* pointer into the line */
char *line; /* the line we're working on */ char *line; /* the line we're working on */
struct loadedfile *lf;
lf = loadfile(name, fd);
inLine = FALSE; inLine = FALSE;
fatals = 0; 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 { do {
for (; (line = ParseReadLine()) != NULL; ) { for (; (line = ParseReadLine()) != NULL; ) {
@ -2619,6 +2905,17 @@ Parse_File(const char *name, int fd)
ParseTraditionalInclude(line); ParseTraditionalInclude(line);
continue; 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 #endif
if (Parse_IsVar(line)) { if (Parse_IsVar(line)) {
ParseFinishLine(); ParseFinishLine();
@ -2719,7 +3016,7 @@ Parse_File(const char *name, int fd)
if (fatals) { if (fatals) {
(void)fflush(stdout); (void)fflush(stdout);
(void)fprintf(stderr, (void)fprintf(stderr,
"%s: Fatal errors encountered -- cannot continue\n", "%s: Fatal errors encountered -- cannot continue",
progname); progname);
PrintOnError(NULL, NULL); PrintOnError(NULL, NULL);
exit(1); exit(1);

View 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 * Copyright (c) 1988, 1989, 1990, 1993
@ -69,14 +69,14 @@
*/ */
#ifndef MAKE_NATIVE #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 #else
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
#if 0 #if 0
static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90"; static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90";
#else #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
#endif /* not lint */ #endif /* not lint */
#endif #endif
@ -319,6 +319,8 @@ Str_FindSubstring(const char *string, const char *substring)
* matching operation permits the following special characters in the * matching operation permits the following special characters in the
* pattern: *?\[] (see the man page for details on what these mean). * pattern: *?\[] (see the man page for details on what these mean).
* *
* XXX this function does not detect or report malformed patterns.
*
* Side effects: None. * Side effects: None.
*/ */
int int

View 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 * Copyright (c) 1988, 1989, 1990, 1993
@ -69,14 +69,14 @@
*/ */
#ifndef MAKE_NATIVE #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 #else
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
#if 0 #if 0
static char sccsid[] = "@(#)suff.c 8.4 (Berkeley) 3/21/94"; static char sccsid[] = "@(#)suff.c 8.4 (Berkeley) 3/21/94";
#else #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
#endif /* not lint */ #endif /* not lint */
#endif #endif
@ -136,7 +136,6 @@ __RCSID("$NetBSD: suff.c,v 1.67 2009/01/23 21:58:28 dsl Exp $");
*/ */
#include <stdio.h> #include <stdio.h>
#include <strings.h>
#include "make.h" #include "make.h"
#include "hash.h" #include "hash.h"
#include "dir.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 * We haven't looked to see if .OPTIONAL files exist yet, so
* don't use one as the implicit source. * don't use one as the implicit source.
* This allows us to use .OPTIONAL in .depend files so make won't * 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. * has been moved/deleted.
*/ */
continue; continue;
@ -2407,16 +2406,25 @@ Suff_FindDeps(GNode *gn)
static void static void
SuffFindDeps(GNode *gn, Lst slst) 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 dependencies already found, no need to do it again...
* If this is a .PHONY target, we do not apply suffix rules.
*/ */
return; return;
} else { } else {
gn->type |= OP_DEPS_FOUND; 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)) { if (DEBUG(SUFF)) {
fprintf(debug_file, "SuffFindDeps (%s)\n", gn->name); fprintf(debug_file, "SuffFindDeps (%s)\n", gn->name);
} }

View 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 * Copyright (c) 1988, 1989, 1990, 1993
@ -69,14 +69,14 @@
*/ */
#ifndef MAKE_NATIVE #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 #else
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
#if 0 #if 0
static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94"; static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94";
#else #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
#endif /* not lint */ #endif /* not lint */
#endif #endif
@ -130,7 +130,6 @@ __RCSID("$NetBSD: targ.c,v 1.55 2009/01/23 21:26:30 dsl Exp $");
*/ */
#include <stdio.h> #include <stdio.h>
#include <strings.h>
#include <time.h> #include <time.h>
#include "make.h" #include "make.h"
@ -249,8 +248,9 @@ Targ_NewGN(const char *name)
gn->centurion = NULL; gn->centurion = NULL;
gn->made = UNMADE; gn->made = UNMADE;
gn->flags = 0; gn->flags = 0;
gn->checked = 0; gn->checked = 0;
gn->mtime = gn->cmtime = 0; gn->mtime = 0;
gn->cmgn = NULL;
gn->iParents = Lst_Init(FALSE); gn->iParents = Lst_Init(FALSE);
gn->cohorts = Lst_Init(FALSE); gn->cohorts = Lst_Init(FALSE);
gn->parents = Lst_Init(FALSE); gn->parents = Lst_Init(FALSE);

View file

@ -96,17 +96,10 @@ Trace_Log(TrEvent event, Job *job)
gettimeofday(&rightnow, NULL); 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", fprintf(trfile, "%lld.%06ld %d %s %d %s",
(long long)rightnow.tv_sec, (long)rightnow.tv_usec, (long long)rightnow.tv_sec, (long)rightnow.tv_usec,
jobTokensRunning, jobTokensRunning,
evname[event], trpid, trwd); evname[event], trpid, trwd);
#endif
if (job != NULL) { if (job != NULL) {
fprintf(trfile, " %s %d %x %x", job->node->name, fprintf(trfile, " %s %d %x %x", job->node->name,
job->pid, job->flags, job->node->type); job->pid, job->flags, job->node->type);

View 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) # Unit tests for make(1)
# The main targets are: # The main targets are:
@ -21,18 +21,24 @@ UNIT_TESTS:= ${.PARSEDIR}
SUBFILES= \ SUBFILES= \
comment \ comment \
cond1 \ cond1 \
error \
export \ export \
export-all \ export-all \
doterror \
dotwait \ dotwait \
forsubst \ forsubst \
hash \
misc \
moderrs \ moderrs \
modmatch \ modmatch \
modmisc \ modmisc \
modorder \ modorder \
modts \ modts \
modword \ modword \
phony-end \
posix \ posix \
qequals \ qequals \
sysv \
ternary \ ternary \
unexport \ unexport \
unexport-env \ unexport-env \
@ -40,18 +46,26 @@ SUBFILES= \
all: ${SUBFILES} all: ${SUBFILES}
flags.doterror=
# the tests are actually done with sub-makes. # the tests are actually done with sub-makes.
.PHONY: ${SUBFILES} .PHONY: ${SUBFILES}
.PRECIOUS: ${SUBFILES} .PRECIOUS: ${SUBFILES}
${SUBFILES}: ${SUBFILES}:
-@${.MAKE} -k -f ${UNIT_TESTS}/$@ -@${.MAKE} ${flags.$@:U-k} -f ${UNIT_TESTS}/$@
clean: clean:
rm -f *.out *.fail *.core rm -f *.out *.fail *.core
.include <bsd.obj.mk> .-include <bsd.obj.mk>
TEST_MAKE?= ${.MAKE} TEST_MAKE?= ${.MAKE}
TOOL_SED?= sed
# ensure consistent results from sort(1)
LC_ALL= C
LANG= C
.export LANG LC_ALL
# The driver. # The driver.
# We always pretend .MAKE was called 'make' # We always pretend .MAKE was called 'make'

View 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! # hard code these!
TEST_UNAME_S= NetBSD TEST_UNAME_S= NetBSD
@ -95,6 +95,11 @@ C=clever
C=dim C=dim
.endif .endif
.if defined(nosuch) && ${nosuch:Mx} != ""
# this should not happen
.info nosuch is x
.endif
all: all:
@echo "$n is $X prime" @echo "$n is $X prime"
@echo "A='$A' B='$B' C='$C' o='$o,${o2}'" @echo "A='$A' B='$B' C='$C' o='$o,${o2}'"

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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}

View file

@ -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

View 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 # 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. # strip cwd from path.
MOD_NODOT=S/:/ /g:N.:ts: MOD_NODOT=S/:/ /g:N.:ts:
# and decorate, note that $'s need to be doubled. Also note that # 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_OPT=@d@$${exists($$d):?$$d:$${d:S,/usr,/opt,}}@
MOD_SEP=S,:, ,g MOD_SEP=S,:, ,g
all: modvar modvarloop all: modvar modvarloop modsysv
modsysv:
@echo "The answer is ${libfoo.a:L:libfoo.a=42}"
modvar: modvar:
@echo "path='${path}'" @echo "path='${path}'"

View file

@ -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?'

View file

@ -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

View file

@ -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}}

View 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 make: Bad conditional expression `"0" > 0' in "0" > 0?OK:No
OK 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_DOLLAR=This is $UT_FU
UT_FOO=foobar is fubar UT_FOO=foobar is fubar
UT_FU=fubar UT_FU=fubar
UT_TEST=export UT_TEST=export
UT_ZOO=hoopie UT_ZOO=hoopie
UT_ALL=even this gets exported UT_ALL=even this gets exported
UT_BADDIR=unit-tests
UT_DOLLAR=This is $UT_FU UT_DOLLAR=This is $UT_FU
UT_F=fine UT_F=fine
UT_FOO=foobar is fubar UT_FOO=foobar is fubar
UT_FU=fubar UT_FU=fubar
UT_NO=all UT_NO=all
UT_OK=good UT_OK=good
UT_OKDIR=unit-tests
UT_TEST=export-all UT_TEST=export-all
UT_ZOO=hoopie 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.1 simple.1
simple.2 simple.2
@ -68,6 +81,14 @@ make: Graph cycles through `cycle.2.97'
cycle.1.99 cycle.1.99
cycle.1.99 cycle.1.99
.for with :S;... OK .for with :S;... OK
b2af338b
3360ac65
7747f046
9ca87054
880fe816
208fcbd3
d5d376eb
de41416c
Expect: Unknown modifier 'Z' Expect: Unknown modifier 'Z'
make: Unknown modifier 'Z' make: Unknown modifier 'Z'
VAR: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 is "/tmp/libe.a"
LIB=e X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBE.A" LIB=e X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBE.A"
Mscanner=OK Mscanner=OK
path=':/bin:/usr/bin::/sbin:/usr/sbin:.:/home/user/bin:.' path=':/bin:/tmp::/:.:/no/such/dir:.'
path='/bin:/usr/bin:/sbin:/usr/sbin:/home/user/bin' path='/bin:/tmp:/:/no/such/dir'
path='/bin:/usr/bin:/sbin:/usr/sbin:/homes/user/bin' path='/bin:/tmp:/:/no/such/dir'
path='/bin':'/usr/bin':'/sbin':'/usr/sbin':'/home/user/bin' path='/bin':'/tmp':'/':'/no/such/dir'
path='/bin':'/usr/bin':'/sbin':'/usr/sbin':'/homes/user/bin' path='/bin':'/tmp':'/':'/no/such/dir'
path_/usr/xbin=/opt/xbin/ path_/usr/xbin=/opt/xbin/
paths=/bin /usr/bin /sbin /usr/sbin /homes/user/bin /opt/xbin paths=/bin /tmp / /no/such/dir /opt/xbin
PATHS=/BIN /USR/BIN /SBIN /USR/SBIN /HOMES/USER/BIN /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 = one two three four five six seven eight nine ten
LIST:O = eight five four nine one seven six ten three two LIST:O = eight five four nine one seven six ten three two
LIST:Ox = Ok 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: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"
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) Posix says we should execute the command as if run by system(3)
Expect 'Hello,' and 'World!' Expect 'Hello,' and 'World!'
Hello, Hello,
@ -293,6 +320,12 @@ Now we expect an error...
*** Error code 1 (continuing) *** Error code 1 (continuing)
`all' not remade because of errors. `all' not remade because of errors.
V.i386 ?= OK V.i386 ?= OK
FOOBAR =
FOOBAR = foobar fubar
fun
fun
fun
In the Sun
The answer is unknown The answer is unknown
The answer is unknown The answer is unknown
The answer is empty 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 five v=is x k=is x
six v=is y k=is y six v=is y k=is y
show-v v=override k=override show-v v=override k=override
*** Error code 1 (ignored)
*** Error code 1 (ignored)

View 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 * Missing stuff from OS's
*/ */
#ifndef MAKE_NATIVE #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 #else
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #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
#endif #endif
@ -49,7 +49,7 @@ findenv(const char *name, int *offset)
char *p, *q; char *p, *q;
for (i = 0; (q = environ[i]); i++) { for (i = 0; (q = environ[i]); i++) {
char *p = strchr(q, '='); p = strchr(q, '=');
if (p == NULL) if (p == NULL)
continue; continue;
if (strncmp(name, q, len = p - q) == 0) { if (strncmp(name, q, len = p - q) == 0) {

View 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 * Copyright (c) 1988, 1989, 1990, 1993
@ -69,14 +69,14 @@
*/ */
#ifndef MAKE_NATIVE #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 #else
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
#if 0 #if 0
static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
#else #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
#endif /* not lint */ #endif /* not lint */
#endif #endif
@ -129,8 +129,10 @@ __RCSID("$NetBSD: var.c,v 1.159 2010/06/06 01:13:12 sjg Exp $");
#include <regex.h> #include <regex.h>
#endif #endif
#include <ctype.h> #include <ctype.h>
#include <inttypes.h>
#include <stdlib.h> #include <stdlib.h>
#include <limits.h> #include <limits.h>
#include <time.h>
#include "make.h" #include "make.h"
#include "buf.h" #include "buf.h"
@ -302,6 +304,7 @@ static char *VarGetPattern(GNode *, Var_Parse_State *,
VarPattern *); VarPattern *);
static char *VarQuote(char *); static char *VarQuote(char *);
static char *VarChangeCase(char *, int); static char *VarChangeCase(char *, int);
static char *VarHash(char *);
static char *VarModify(GNode *, Var_Parse_State *, static char *VarModify(GNode *, Var_Parse_State *,
const char *, const char *,
Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *), Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *),
@ -379,6 +382,12 @@ VarFind(const char *name, GNode *ctxt, int flags)
name = TARGET; name = TARGET;
break; 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, * 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, * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
@ -2254,6 +2263,79 @@ VarQuote(char *str)
return 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 -- * VarChangeCase --
@ -2285,6 +2367,21 @@ VarChangeCase(char *str, int upper)
return Buf_Destroy(&buf, FALSE); 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. * Now we need to apply any modifiers the user wants applied.
* These are: * These are:
@ -2370,6 +2467,10 @@ VarChangeCase(char *str, int upper)
* variable. * 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 * static char *
ApplyModifiers(char *nstr, const char *tstr, ApplyModifiers(char *nstr, const char *tstr,
int startc, int endc, int startc, int endc,
@ -2397,14 +2498,28 @@ ApplyModifiers(char *nstr, const char *tstr,
if (*tstr == '$') { if (*tstr == '$') {
/* /*
* We have some complex modifiers in a variable. * We may have some complex modifiers in a variable.
*/ */
void *freeIt; void *freeIt;
char *rval; char *rval;
int rlen; int rlen;
int c;
rval = Var_Parse(tstr, ctxt, errnum, &rlen, &freeIt); 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)) { if (DEBUG(VAR)) {
fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n", fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n",
rval, rlen, tstr, rlen, tstr + rlen); rval, rlen, tstr, rlen, tstr + rlen);
@ -2436,6 +2551,7 @@ ApplyModifiers(char *nstr, const char *tstr,
} }
continue; continue;
} }
apply_mods:
if (DEBUG(VAR)) { if (DEBUG(VAR)) {
fprintf(debug_file, "Applying :%c to \"%s\"\n", *tstr, nstr); fprintf(debug_file, "Applying :%c to \"%s\"\n", *tstr, nstr);
} }
@ -2486,7 +2602,7 @@ ApplyModifiers(char *nstr, const char *tstr,
cp = ++tstr; cp = ++tstr;
break; break;
} }
delim = BRCLOSE; delim = startc == PROPEN ? PRCLOSE : BRCLOSE;
pattern.flags = 0; pattern.flags = 0;
pattern.rhs = VarGetPattern(ctxt, &parsestate, errnum, 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': case 't':
{ {
cp = tstr + 1; /* make sure it is set */ cp = tstr + 1; /* make sure it is set */
@ -3340,9 +3486,13 @@ ApplyModifiers(char *nstr, const char *tstr,
*/ */
termc = *--cp; termc = *--cp;
delim = '\0'; delim = '\0';
newStr = VarModify(ctxt, &parsestate, nstr, if (pattern.leftLen == 0 && *nstr == '\0') {
VarSYSVMatch, newStr = nstr; /* special case */
&pattern); } else {
newStr = VarModify(ctxt, &parsestate, nstr,
VarSYSVMatch,
&pattern);
}
free(UNCONST(pattern.lhs)); free(UNCONST(pattern.lhs));
free(UNCONST(pattern.rhs)); free(UNCONST(pattern.rhs));
} else } else
@ -3740,7 +3890,7 @@ Var_Parse(const char *str, GNode *ctxt, Boolean errnum, int *lengthPtr,
nstr = bmake_strndup(start, *lengthPtr); nstr = bmake_strndup(start, *lengthPtr);
*freePtr = nstr; *freePtr = nstr;
} else { } else {
nstr = var_Error; nstr = errnum ? var_Error : varNoError;
} }
} }
if (nstr != Buf_GetAll(&v->val, NULL)) if (nstr != Buf_GetAll(&v->val, NULL))