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 \
intr ipcrm ipcs irdpd isoread join kill last \
less loadkeys loadramdisk logger look lp \
lpd ls lspci mail make MAKEDEV \
lpd ls lspci mail MAKEDEV \
mdb mesg mined mkfifo mkfs.mfs mknod \
mkproto mount mt netconf nice acknm nohup \
nonamed od paste patch pax \

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>
# NetBSD imports
SUBDIR= login indent m4 stat tic sed mkdep uniq seq du man \
SUBDIR= login indent m4 make stat tic sed mkdep uniq seq du man \
apropos chpass newgrp passwd bzip2 bzip2recover gzip su genassym \
ldd/elf32 .WAIT ldd

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
PROG= make
@ -13,10 +13,28 @@ SRCS+= lstAppend.c lstAtEnd.c lstAtFront.c lstClose.c lstConcat.c \
lstMember.c lstNext.c lstOpen.c lstRemove.c lstReplace.c lstSucc.c
SRCS += lstPrev.c
.PATH: ${.CURDIR}/lst.lib
.if make(install)
SUBDIR= PSD.doc
# let people experiment for a bit
USE_META ?= no
.if ${USE_META:tl} != "no"
SRCS+= meta.c
CPPFLAGS+= -DUSE_META
FILEMON_H ?= ${.CURDIR:H:H}/sys/dev/filemon/filemon.h
.if exists(${FILEMON_H}) && ${FILEMON_H:T} == "filemon.h"
COPTS.meta.c += -DHAVE_FILEMON_H -I${FILEMON_H:H}
.endif
.endif
# For MINIX
CPPFLAGS+= -DHAVE_SETENV -DHAVE_STRERROR -DHAVE_STRDUP \
-DHAVE_STRFTIME -DHAVE_VSNPRINTF -DUSE_SELECT
CPPFLAGS+= -DMAKE_MACHINE=\"${MACHINE}\" -DMAKE_MACHINE_ARCH=\"${MACHINE_ARCH}\"
.PATH: ${.CURDIR}/lst.lib
#.if make(install)
#SUBDIR= PSD.doc
#.endif
.if make(obj) || make(clean)
SUBDIR+= unit-tests
.endif
@ -24,10 +42,13 @@ SUBDIR+= unit-tests
.include <bsd.prog.mk>
.include <bsd.subdir.mk>
CPPFLAGS+= -DMAKE_NATIVE
COPTS.var.c+= -Wno-cast-qual
.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

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

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
.\" The Regents of the University of California. All rights reserved.
.\"
@ -114,14 +114,15 @@
.nr g4 \\n(.s
.sp -1
.\" .st cf
\D's -1u'\D't 5u'
\D't 5u'
.sp -1
\h'50u'\D'l 71u 0u'\D'l 50u 50u'\D'l 0u 71u'\D'l -50u 50u'\D'l -71u 0u'\D'l -50u -50u'\D'l 0u -71u'\D'l 50u -50u'
\h'50u'
.sp -1
\D't 3u'
.sp -1
.sp 7u
\h'53u'\D'p 14 68u 0u 46u 46u 0u 68u -46u 46u -68u 0u -47u -46u 0u -68u 47u -46u'
\h'53u'
\d\D'p -0.19i 0.0i 0.0i -0.13i 0.30i 0.0i 0.0i 0.13i'
.sp -1
.ft R
.ps 6
@ -131,7 +132,7 @@
\h'85u'\v'0.85n'\h-\w\\*(g9u/2u\&\\*(g9
.sp |\\n(g8u
.sp 166u
\D't 3u'\D's -1u'
\D't 3u'
.br
.po
.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
@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
static char rcsid[] = "$NetBSD: arch.c,v 1.59 2009/01/23 21:58:27 dsl Exp $";
static char rcsid[] = "$NetBSD: arch.c,v 1.62 2010/11/27 16:00:09 christos Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)arch.c 8.2 (Berkeley) 1/2/94";
#else
__RCSID("$NetBSD: arch.c,v 1.59 2009/01/23 21:58:27 dsl Exp $");
__RCSID("$NetBSD: arch.c,v 1.62 2010/11/27 16:00:09 christos Exp $");
#endif
#endif /* not lint */
#endif
@ -1212,7 +1212,7 @@ Arch_FindLib(GNode *gn, Lst path)
* A library will be considered out-of-date for any of these reasons,
* given that it is a target on a dependency line somewhere:
* Its modification time is less than that of one of its
* sources (gn->mtime < gn->cmtime).
* sources (gn->mtime < gn->cmgn->mtime).
* Its modification time is greater than the time at which the
* make began (i.e. it's been modified in the course
* of the make, probably by archiving).
@ -1245,8 +1245,9 @@ Arch_LibOODate(GNode *gn)
oodate = TRUE;
} else if (OP_NOP(gn->type) && Lst_IsEmpty(gn->children)) {
oodate = FALSE;
} else if ((!Lst_IsEmpty(gn->children) && gn->cmtime == 0) ||
(gn->mtime > now) || (gn->mtime < gn->cmtime)) {
} else if ((!Lst_IsEmpty(gn->children) && gn->cmgn == NULL) ||
(gn->mtime > now) ||
(gn->cmgn != NULL && gn->mtime < gn->cmgn->mtime)) {
oodate = TRUE;
} else {
#ifdef RANLIBMAG
@ -1261,7 +1262,7 @@ Arch_LibOODate(GNode *gn)
if (DEBUG(ARCH) || DEBUG(MAKE)) {
fprintf(debug_file, "%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC));
}
oodate = (gn->cmtime > modTimeTOC);
oodate = (gn->cmgn == NULL || gn->cmgn->mtime > modTimeTOC);
} else {
/*
* A library w/o a table of contents is out-of-date

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

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.
@ -70,14 +70,14 @@
*/
#ifndef MAKE_NATIVE
static char rcsid[] = "$NetBSD: cond.c,v 1.60 2009/11/06 19:44:06 dsl Exp $";
static char rcsid[] = "$NetBSD: cond.c,v 1.62 2011/03/29 17:19:22 sjg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)cond.c 8.2 (Berkeley) 1/2/94";
#else
__RCSID("$NetBSD: cond.c,v 1.60 2009/11/06 19:44:06 dsl Exp $");
__RCSID("$NetBSD: cond.c,v 1.62 2011/03/29 17:19:22 sjg Exp $");
#endif
#endif /* not lint */
#endif
@ -327,7 +327,7 @@ CondGetArg(char **linePtr, char **argPtr, const char *func)
*-----------------------------------------------------------------------
*/
static Boolean
CondDoDefined(int argLen, const char *arg)
CondDoDefined(int argLen __unused, const char *arg)
{
char *p1;
Boolean result;
@ -376,7 +376,7 @@ CondStrMatch(const void *string, const void *pattern)
*-----------------------------------------------------------------------
*/
static Boolean
CondDoMake(int argLen, const char *arg)
CondDoMake(int argLen __unused, const char *arg)
{
return Lst_Find(create, arg, CondStrMatch) != NULL;
}
@ -395,22 +395,22 @@ CondDoMake(int argLen, const char *arg)
*-----------------------------------------------------------------------
*/
static Boolean
CondDoExists(int argLen, const char *arg)
CondDoExists(int argLen __unused, const char *arg)
{
Boolean result;
char *path;
path = Dir_FindFile(arg, dirSearchPath);
if (DEBUG(COND)) {
fprintf(debug_file, "exists(%s) result is \"%s\"\n",
arg, path ? path : "");
}
if (path != NULL) {
result = TRUE;
free(path);
} else {
result = FALSE;
}
if (DEBUG(COND)) {
fprintf(debug_file, "exists(%s) result is \"%s\"\n",
arg, path ? path : "");
}
return (result);
}
@ -428,7 +428,7 @@ CondDoExists(int argLen, const char *arg)
*-----------------------------------------------------------------------
*/
static Boolean
CondDoTarget(int argLen, const char *arg)
CondDoTarget(int argLen __unused, const char *arg)
{
GNode *gn;
@ -452,7 +452,7 @@ CondDoTarget(int argLen, const char *arg)
*-----------------------------------------------------------------------
*/
static Boolean
CondDoCommands(int argLen, const char *arg)
CondDoCommands(int argLen __unused, const char *arg)
{
GNode *gn;
@ -790,7 +790,7 @@ done:
}
static int
get_mpt_arg(char **linePtr, char **argPtr, const char *func)
get_mpt_arg(char **linePtr, char **argPtr, const char *func __unused)
{
/*
* Use Var_Parse to parse the spec in parens and return
@ -831,7 +831,7 @@ get_mpt_arg(char **linePtr, char **argPtr, const char *func)
}
static Boolean
CondDoEmpty(int arglen, const char *arg)
CondDoEmpty(int arglen, const char *arg __unused)
{
return arglen == 1;
}

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.
@ -132,6 +132,12 @@
#define SYSVINCLUDE
#define SYSVVARSUB
/*
* GMAKEEXPORT
* Recognize gmake like variable export directives [export <VAR>=<VALUE>]
*/
#define GMAKEEXPORT
/*
* SUNSHCMD
* 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.
@ -70,14 +70,14 @@
*/
#ifndef MAKE_NATIVE
static char rcsid[] = "$NetBSD: dir.c,v 1.61 2009/01/24 10:59:09 dsl Exp $";
static char rcsid[] = "$NetBSD: dir.c,v 1.64 2012/04/07 18:29:08 christos Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94";
#else
__RCSID("$NetBSD: dir.c,v 1.61 2009/01/24 10:59:09 dsl Exp $");
__RCSID("$NetBSD: dir.c,v 1.64 2012/04/07 18:29:08 christos Exp $");
#endif
#endif /* not lint */
#endif
@ -1061,6 +1061,7 @@ Dir_FindFile(const char *name, Lst path)
Boolean hasSlash; /* true if 'name' contains a / */
struct stat stb; /* Buffer for stat, if necessary */
Hash_Entry *entry; /* Entry for mtimes table */
const char *trailing_dot = ".";
/*
* Find the final component of the name and note whether it has a
@ -1165,6 +1166,11 @@ Dir_FindFile(const char *name, Lst path)
return NULL;
}
if (*cp == '\0') {
/* we were given a trailing "/" */
cp = trailing_dot;
}
if (name[0] != '/') {
Boolean checkedDot = FALSE;
@ -1272,6 +1278,10 @@ Dir_FindFile(const char *name, Lst path)
* b/c we added it here. This is not good...
*/
#ifdef notdef
if (cp == traling_dot) {
cp = strrchr(name, '/');
cp += 1;
}
cp[-1] = '\0';
(void)Dir_AddDir(path, name);
cp[-1] = '/';
@ -1418,7 +1428,7 @@ Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen) {
*-----------------------------------------------------------------------
*/
int
Dir_MTime(GNode *gn)
Dir_MTime(GNode *gn, Boolean recheck)
{
char *fullName; /* the full pathname of name */
struct stat stb; /* buffer for finding the mod time */
@ -1434,6 +1444,31 @@ Dir_MTime(GNode *gn)
fullName = NULL;
else {
fullName = Dir_FindFile(gn->name, Suff_FindPath(gn));
if (fullName == NULL && gn->flags & FROM_DEPEND &&
!Lst_IsEmpty(gn->iParents)) {
char *cp;
cp = strrchr(gn->name, '/');
if (cp) {
/*
* This is an implied source, and it may have moved,
* see if we can find it via the current .PATH
*/
cp++;
fullName = Dir_FindFile(cp, Suff_FindPath(gn));
if (fullName) {
/*
* Put the found file in gn->path
* so that we give that to the compiler.
*/
gn->path = bmake_strdup(fullName);
fprintf(stdout,
"%s: ignoring stale %s for %s, found %s\n",
progname, makeDependfile, gn->name, fullName);
}
}
}
if (DEBUG(DIR))
fprintf(debug_file, "Found '%s' as '%s'\n",
gn->name, fullName ? fullName : "(not found)" );
@ -1446,19 +1481,16 @@ Dir_MTime(GNode *gn)
fullName = bmake_strdup(gn->name);
}
entry = Hash_FindEntry(&mtimes, fullName);
if (!recheck)
entry = Hash_FindEntry(&mtimes, fullName);
else
entry = NULL;
if (entry != NULL) {
/*
* Only do this once -- the second time folks are checking to
* see if the file was actually updated, so we need to actually go
* to the file system.
*/
if (DEBUG(DIR)) {
fprintf(debug_file, "Using cached time %s for %s\n",
Targ_FmtTime(Hash_GetTimeValue(entry)), fullName);
}
stb.st_mtime = Hash_GetTimeValue(entry);
Hash_DeleteEntry(&mtimes, entry);
} else if (stat(fullName, &stb) < 0) {
if (gn->type & OP_MEMBER) {
if (fullName != gn->path)
@ -1467,12 +1499,16 @@ Dir_MTime(GNode *gn)
} else {
stb.st_mtime = 0;
}
} else if (stb.st_mtime == 0) {
/*
* 0 handled specially by the code, if the time is really 0, return
* something else instead
*/
stb.st_mtime = 1;
} else {
if (stb.st_mtime == 0) {
/*
* 0 handled specially by the code, if the time is really 0,
* return something else instead
*/
stb.st_mtime = 1;
}
entry = Hash_CreateEntry(&mtimes, fullName, NULL);
Hash_SetTimeValue(entry, stb.st_mtime);
}
if (fullName && gn->path == NULL) {

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

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.
@ -30,14 +30,14 @@
*/
#ifndef MAKE_NATIVE
static char rcsid[] = "$NetBSD: for.c,v 1.47 2010/02/06 20:37:13 dholland Exp $";
static char rcsid[] = "$NetBSD: for.c,v 1.48 2010/12/25 04:57:07 dholland Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93";
#else
__RCSID("$NetBSD: for.c,v 1.47 2010/02/06 20:37:13 dholland Exp $");
__RCSID("$NetBSD: for.c,v 1.48 2010/12/25 04:57:07 dholland Exp $");
#endif
#endif /* not lint */
#endif
@ -366,7 +366,7 @@ for_substitute(Buffer *cmds, strlist_t *items, unsigned int item_no, char ech)
}
static char *
For_Iterate(void *v_arg)
For_Iterate(void *v_arg, size_t *ret_len)
{
For *arg = v_arg;
int i, len;
@ -451,6 +451,7 @@ For_Iterate(void *v_arg)
arg->sub_next += strlist_num(&arg->vars);
arg->parse_buf = cp;
*ret_len = strlen(cp);
return cp;
}

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

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

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
@ -69,7 +69,7 @@
*/
#ifndef MAKE_NATIVE
static char rcsid[] = "$NetBSD: main.c,v 1.188 2010/06/03 15:40:16 sjg Exp $";
static char rcsid[] = "$NetBSD: main.c,v 1.198 2011/09/16 15:38:04 joerg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
@ -81,7 +81,7 @@ __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\
#if 0
static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94";
#else
__RCSID("$NetBSD: main.c,v 1.188 2010/06/03 15:40:16 sjg Exp $");
__RCSID("$NetBSD: main.c,v 1.198 2011/09/16 15:38:04 joerg Exp $");
#endif
#endif /* not lint */
#endif
@ -178,11 +178,11 @@ static const char * tracefile;
static char * Check_Cwd_av(int, char **, int);
static void MainParseArgs(int, char **);
static int ReadMakefile(const void *, const void *);
static void usage(void);
static void usage(void) __dead;
static Boolean ignorePWD; /* if we use -C, PWD is meaningless */
static char curdir[MAXPATHLEN + 1]; /* startup directory */
static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */
char curdir[MAXPATHLEN + 1]; /* Startup directory */
char *progname; /* the program name */
char *makeDependfile;
pid_t myPid;
@ -242,6 +242,9 @@ parse_debug_options(const char *argvalue)
case 'l':
debug |= DEBUG_LOUD;
break;
case 'M':
debug |= DEBUG_META;
break;
case 'm':
debug |= DEBUG_MAKE;
break;
@ -684,7 +687,7 @@ ReadAllMakefiles(const void *p, const void *q)
return (ReadMakefile(p, q) == 0);
}
static int
int
str2Lst_Append(Lst lp, char *str, const char *sep)
{
char *cp;
@ -703,7 +706,7 @@ str2Lst_Append(Lst lp, char *str, const char *sep)
#ifdef SIGINFO
/*ARGSUSED*/
static void
siginfo(int signo)
siginfo(int signo __unused)
{
char dir[MAXPATHLEN];
char str[2 * MAXPATHLEN];
@ -732,6 +735,10 @@ MakeMode(const char *mode)
compatMake = TRUE;
forceJobs = FALSE;
}
#if USE_META
if (strstr(mode, "meta"))
meta_init(mode);
#endif
}
if (mp)
free(mp);
@ -762,7 +769,7 @@ main(int argc, char **argv)
struct stat sb, sa;
char *p1, *path, *pwd;
char mdpath[MAXPATHLEN];
char *machine = getenv("MACHINE");
const char *machine = getenv("MACHINE");
const char *machine_arch = getenv("MACHINE_ARCH");
char *syspath = getenv("MAKESYSPATH");
Lst sysMkPath; /* Path of sys.mk */
@ -957,7 +964,8 @@ main(int argc, char **argv)
* We take care of PWD for the automounter below...
*/
if (getcwd(curdir, MAXPATHLEN) == NULL) {
(void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno));
(void)fprintf(stderr, "%s: getcwd: %s.\n",
progname, strerror(errno));
exit(2);
}
@ -1300,7 +1308,7 @@ ReadMakefile(const void *p, const void *q __unused)
char *name, *path = bmake_malloc(len);
if (!strcmp(fname, "-")) {
Parse_File("(stdin)", dup(fileno(stdin)));
Parse_File(NULL /*stdin*/, -1);
Var_Set("MAKEFILE", "", VAR_GLOBAL, 0);
} else {
/* if we've chdir'd, rebuild the path name */
@ -1641,9 +1649,10 @@ Cmd_Exec(const char *cmd, const char **errnum)
/*
* Wait for the process to exit.
*/
while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0))
while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) {
JobReapChild(pid, status, FALSE);
continue;
}
cc = Buf_Size(&buf);
res = Buf_Destroy(&buf, FALSE);
@ -1958,20 +1967,10 @@ Main_ExportMAKEFLAGS(Boolean first)
}
}
/*
* Create and open a temp file using "pattern".
* If "fnamep" is provided set it to a copy of the filename created.
* Otherwise unlink the file once open.
*/
int
mkTempFile(const char *pattern, char **fnamep)
char *
getTmpdir(void)
{
static char *tmpdir = NULL;
char tfile[MAXPATHLEN];
int fd;
if (!pattern)
pattern = TMPPAT;
if (!tmpdir) {
struct stat st;
@ -1986,6 +1985,25 @@ mkTempFile(const char *pattern, char **fnamep)
tmpdir = bmake_strdup(_PATH_TMP);
}
}
return tmpdir;
}
/*
* Create and open a temp file using "pattern".
* If "fnamep" is provided set it to a copy of the filename created.
* Otherwise unlink the file once open.
*/
int
mkTempFile(const char *pattern, char **fnamep)
{
static char *tmpdir = NULL;
char tfile[MAXPATHLEN];
int fd;
if (!pattern)
pattern = TMPPAT;
if (!tmpdir)
tmpdir = getTmpdir();
if (pattern[0] == '/') {
snprintf(tfile, sizeof(tfile), "%s", pattern);
} else {

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
.\" The Regents of the University of California. All rights reserved.
@ -29,7 +29,7 @@
.\"
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
.\"
.Dd June 9, 2010
.Dd March 31, 2012
.Dt MAKE 1
.Os
.Sh NAME
@ -38,40 +38,18 @@
.Sh SYNOPSIS
.Nm
.Op Fl BeikNnqrstWX
.Bk -words
.Op Fl C Ar directory
.Ek
.Bk -words
.Op Fl D Ar variable
.Ek
.Bk -words
.Op Fl d Ar flags
.Ek
.Bk -words
.Op Fl f Ar makefile
.Ek
.Bk -words
.Op Fl I Ar directory
.Ek
.Bk -words
.Op Fl J Ar private
.Ek
.Bk -words
.Op Fl j Ar max_jobs
.Ek
.Bk -words
.Op Fl m Ar directory
.Ek
.Bk -words
.Op Fl T Ar file
.Ek
.Bk -words
.Op Fl V Ar variable
.Ek
.Op Ar variable=value
.Bk -words
.Op Ar target ...
.Ek
.Sh DESCRIPTION
.Nm
is a program designed to simplify the maintenance of other programs.
@ -95,7 +73,7 @@ This manual page is intended as a reference document only.
For a more thorough description of
.Nm
and makefiles, please refer to
.%T "Make \- A Tutorial" .
.%T "PMake \- A Tutorial" .
.Pp
.Nm
will prepend the contents of the
@ -126,7 +104,7 @@ Turn on debugging, and specify which portions of
.Nm
are to print debugging information.
Unless the flags are preceded by
.Ql -
.Ql \-
they are added to the
.Va MAKEFLAGS
environment variable and will be processed by any child make processes.
@ -194,6 +172,8 @@ Print commands in Makefiles regardless of whether or not they are prefixed by
.Ql @
or other "quiet" flags.
Also known as "loud" behavior.
.It Ar M
Print debugging information about "meta" mode decisions about targets.
.It Ar m
Print debugging information about making targets, including modification
dates.
@ -266,6 +246,8 @@ cooperate to avoid overloading the system.
Specify the maximum number of jobs that
.Nm
may have running at any one time.
The value is saved in
.Va .MAKE.JOBS .
Turns compatibility mode off, unless the
.Ar B
flag is also specified.
@ -613,7 +595,7 @@ The list of sources for this target that were deemed out-of-date; also
known as
.Ql Va \&? .
.It Va .PREFIX
The file prefix of the file, containing only the file portion, no suffix
The file prefix of the target, containing only the file portion, no suffix
or preceding directory components; also known as
.Ql Va * .
.It Va .TARGET
@ -759,9 +741,73 @@ Processed after reading all makefiles.
Can affect the mode that
.Nm
runs in.
Currently just
.Ql Pa compat
mode.
It can contain a number of keywords:
.Bl -hang -width ignore-cmd
.It Pa compat
Like
.Fl B ,
puts
.Nm
into "compat" mode.
.It Pa meta
Puts
.Nm
into "meta" mode, where meta files are created for each target
to capture the command run, the output generated and if
.Xr filemon 4
is available, the system calls which are of interest to
.Nm .
The captured output can be very useful when diagnosing errors.
.It Pa curdirOk= Ar bf
Normally
.Nm
will not create .meta files in
.Ql Va .CURDIR .
This can be overridden by setting
.Va bf
to a value which represents True.
.It Pa env
For debugging, it can be useful to inlcude the environment
in the .meta file.
.It Pa verbose
If in "meta" mode, print a clue about the target being built.
This is useful if the build is otherwise running silently.
The message printed the value of:
.Va .MAKE.META.PREFIX .
.It Pa ignore-cmd
Some makefiles have commands which are simply not stable.
This keyword causes them to be ignored for
determining whether a target is out of date in "meta" mode.
See also
.Ic .NOMETA_CMP .
.It Pa silent= Ar bf
If
.Va bf
is True, when a .meta file is created, mark the target
.Ic .SILENT .
.El
.It Va .MAKE.META.BAILIWICK
In "meta" mode, provides a list of prefixes which
match the directories controlled by
.Nm .
If a file that was generated outside of
.Va .OBJDIR
but within said bailiwick is missing,
the current target is considered out-of-date.
.It Va .MAKE.META.CREATED
In "meta" mode, this variable contains a list of all the meta files
updated.
If not empty, it can be used to trigger processing of
.Va .MAKE.META.FILES .
.It Va .MAKE.META.FILES
In "meta" mode, this variable contains a list of all the meta files
used (updated or not).
This list can be used to process the meta files to extract dependency
information.
.It Va .MAKE.META.PREFIX
Defines the message printed for each meta file updated in "meta verbose" mode.
The default value is:
.Dl Building ${.TARGET:H:tA}/${.TARGET:T}
.It Va .MAKEOVERRIDES
This variable is used to record the names of variables assigned to
on the command line, so that they may be exported as part of
@ -858,6 +904,9 @@ This variable and
are both set only while the
.Ql Pa Makefiles
are being parsed.
If you want to retain their current values, assign them to a variable
using assignment with expansion:
.Pq Ql Cm \&:= .
.It Va .PATH
A variable that represents the list of directories that
.Nm
@ -892,6 +941,8 @@ is set to the value of
for all programs which
.Nm
executes.
.It Ev .TARGETS
The list of targets explicitly specified on the command line, if any.
.It Ev VPATH
Colon-separated
.Pq Dq \&:
@ -988,6 +1039,18 @@ safely through recursive invocations of
.Nm .
.It Cm \&:R
Replaces each word in the variable with everything but its suffix.
.It Cm \&:gmtime
The value is a format string for
.Xr strftime 3 ,
using the current
.Xr gmtime 3 .
.It Cm \&:hash
Compute a 32bit hash of the value and encode it as hex digits.
.It Cm \&:localtime
The value is a format string for
.Xr strftime 3 ,
using the current
.Xr localtime 3 .
.It Cm \&:tA
Attempt to convert variable to an absolute path using
.Xr realpath 3 ,
@ -1127,7 +1190,7 @@ A common error is trying to use expressions like
.Dl ${NUMBERS:M42:?match:no}
which actually tests defined(NUMBERS),
to determine is any words match "42" you need to use something like:
.Dl ${${NUMBERS:M42} != "":?match:no} .
.Dl ${"${NUMBERS:M42}" != \&"\&":?match:no} .
.It Ar :old_string=new_string
This is the
.At V
@ -1175,6 +1238,9 @@ The ODE convention is that
should start and end with a period.
For example.
.Dl ${LINKS:@.LINK.@${LN} ${TARGET} ${.LINK.}@}
.Pp
However a single character varaiable is often more readable:
.Dl ${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'${.newline}@}
.It Cm \&:U Ns Ar newval
If the variable is undefined
.Ar newval
@ -1196,6 +1262,8 @@ The path of the node which has the same name as the variable
is the value.
If no such node exists or its path is null, then the
name of the variable is used.
In order for this modifier to work, the name (node) must at least have
appeared on the rhs of a dependency.
.Sm off
.It Cm \&:\&! Ar cmd Cm \&!
.Sm on
@ -1256,7 +1324,7 @@ For the purposes of the
modifier, the words are indexed both forwards using positive integers
(where index 1 represents the first word),
and backwards using negative integers
(where index -1 represents the last word).
(where index \-1 represents the last word).
.Pp
The
.Ar range
@ -1355,6 +1423,11 @@ except for internal variables (those that start with
This is not affected by the
.Fl X
flag, so should be used with caution.
For compatibility with other
.Nm
programs
.Ql export variable=value
is also accepted.
.Pp
Appending a variable name to
.Va .MAKE.EXPORTED
@ -1610,6 +1683,28 @@ or
options were specified.
Normally used to mark recursive
.Nm Ns 's .
.It Ic .META
Create a meta file for the target, even if it is flagged as
.Ic .PHONY ,
.Ic .MAKE ,
or
.Ic .SPECIAL .
Usage in conjunction with
.Ic .MAKE
is the most likely case.
In "meta" mode, the target is out-of-date if the meta file is missing.
.It Ic .NOMETA
Do not create a meta file for the target.
Meta files are also not created for
.Ic .PHONY ,
.Ic .MAKE ,
or
.Ic .SPECIAL
targets.
.It Ic .NOMETA_CMP
Ignore differences in commands when deciding if target is out of date.
This is useful if the command contains a value which always changes.
If the number of commands change, though, the target will still be out of date.
.It Ic .NOPATH
Do not search for the target in the directories specified by
.Ic .PATH .
@ -1630,6 +1725,9 @@ correspond to an actual file; it is always considered to be out of date,
and will not be created with the
.Fl t
option.
Suffix-transformation rules are not applied to
.Ic .PHONY
targets.
.It Ic .PRECIOUS
When
.Nm
@ -1769,7 +1867,7 @@ could be built, unless
is built by another part of the dependency graph,
the following is a dependency loop:
.Bd -literal
\&.ORDER: a b
\&.ORDER: b a
b: a
.Ed
.Pp
@ -1846,8 +1944,8 @@ character when used outside of any quoting characters.
Example:
.Bd -literal
\&.SHELL: name=ksh path=/bin/ksh hasErrCtl=true \e
check="set -e" ignore="set +e" \e
echo="set -v" quiet="set +v" filter="set +v" \e
check="set \-e" ignore="set +e" \e
echo="set \-v" quiet="set +v" filter="set +v" \e
echoFlag=v errFlag=e newline="'\en'"
.Ed
.It Ic .SILENT
@ -1868,7 +1966,7 @@ Example:
.Bd -literal
\&.SUFFIXES: .o
\&.c.o:
cc -o ${.TARGET} -c ${.IMPSRC}
cc \-o ${.TARGET} \-c ${.IMPSRC}
.Ed
.El
.Sh ENVIRONMENT
@ -1913,7 +2011,7 @@ however the special variables, variable modifiers and conditionals are not.
.Pp
The way that parallel makes are scheduled changed in
.Nx 4.0
so that .ORDER and .WAIT apply recursively to the dependant nodes.
so that .ORDER and .WAIT apply recursively to the dependent nodes.
The algorithms used may change again in the future.
.Pp
The way that .for loop variables are substituted changed after
@ -1921,6 +2019,21 @@ The way that .for loop variables are substituted changed after
so that they still appear to be variable expansions.
In particular this stops them being treated as syntax, and removes some
obscure problems using them in .if statements.
.Pp
Unlike other
.Nm
programs, this implementation by default executes all commands for a given
target using a single shell invocation.
This is done for both efficiency and to simplify error handling in remote
command invocations.
Typically this is transparent to the user, unless the target commands change
the current working directory using
.Dq cd
or
.Dq chdir .
To be compatible with Makefiles that do this, one can use
.Fl B
to disable this behavior.
.Sh SEE ALSO
.Xr mkdep 1
.Sh HISTORY
@ -1928,6 +2041,13 @@ A
.Nm
command appeared in
.At v7 .
This
.Nm
implementation is based on Adam De Boor's pmake program which was written
for Sprint at Berkeley.
It was designed to be a parallel distributed make running jobs on different
machines using a daemon called
.Dq customs .
.Sh BUGS
The
.Nm

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

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

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.
@ -28,7 +28,7 @@
#ifdef MAKE_NATIVE
#include <sys/cdefs.h>
__RCSID("$NetBSD: make_malloc.c,v 1.5 2009/01/24 23:19:50 dsl Exp $");
__RCSID("$NetBSD: make_malloc.c,v 1.6 2010/12/25 20:35:25 dholland Exp $");
#endif
#include <stdio.h>
@ -48,7 +48,7 @@ enomem(void)
{
extern char *progname;
(void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno));
(void)fprintf(stderr, "%s: %s.\n", progname, strerror(ENOMEM));
exit(2);
}

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

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
@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
static char rcsid[] = "$NetBSD: parse.c,v 1.164 2010/05/24 21:04:49 sjg Exp $";
static char rcsid[] = "$NetBSD: parse.c,v 1.182 2012/03/31 00:12:24 christos Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94";
#else
__RCSID("$NetBSD: parse.c,v 1.164 2010/05/24 21:04:49 sjg Exp $");
__RCSID("$NetBSD: parse.c,v 1.182 2012/03/31 00:12:24 christos Exp $");
#endif
#endif /* not lint */
#endif
@ -123,12 +123,23 @@ __RCSID("$NetBSD: parse.c,v 1.164 2010/05/24 21:04:49 sjg Exp $");
* Parse_MainName Returns a Lst of the main target to create.
*/
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#ifndef MAP_FILE
#define MAP_FILE 0
#endif
#ifndef MAP_COPY
#define MAP_COPY MAP_PRIVATE
#endif
#include "make.h"
#include "hash.h"
#include "dir.h"
@ -136,56 +147,36 @@ __RCSID("$NetBSD: parse.c,v 1.164 2010/05/24 21:04:49 sjg Exp $");
#include "buf.h"
#include "pathnames.h"
////////////////////////////////////////////////////////////
// types and constants
/*
* 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
* CONTINUE parsing, i.e. it had only reached the end of an include file,
* or if it's DONE.
*/
#define CONTINUE 1
#define DONE 0
static Lst 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;
#define CONTINUE 1
#define DONE 0
/*
* Definitions for handling #include specifications
*/
static Lst includes; /* stack of IFiles generated by .includes */
Lst parseIncPath; /* list of directories for "..." includes */
Lst sysIncPath; /* list of directories for <...> includes */
Lst defIncPath; /* default directories for <...> includes */
/*-
* specType contains the SPECial TYPE of the current target. It is
* Not if the target is unspecial. If it *is* special, however, the children
* are linked as children of the parent but not vice versa. This variable is
* set in ParseDoDependency
* Tokens for target attributes
*/
typedef enum {
Begin, /* .BEGIN */
@ -196,10 +187,13 @@ typedef enum {
Includes, /* .INCLUDES */
Interrupt, /* .INTERRUPT */
Libs, /* .LIBS */
Meta, /* .META */
MFlags, /* .MFLAGS or .MAKEFLAGS */
Main, /* .MAIN and we don't have anything user-specified to
* make */
NoExport, /* .NOEXPORT */
NoMeta, /* .NOMETA */
NoMetaCmp, /* .NOMETA_CMP */
NoPath, /* .NOPATH */
Not, /* Not special */
NotParallel, /* .NOTPARALLEL */
@ -221,16 +215,74 @@ typedef enum {
Attribute /* Generic attribute */
} ParseSpecial;
/*
* Other tokens
*/
#define LPAREN '('
#define RPAREN ')'
////////////////////////////////////////////////////////////
// result data
/*
* The main target to create. This is the first target on the first
* dependency line in the first makefile.
*/
static GNode *mainNode;
////////////////////////////////////////////////////////////
// eval state
/* targets we're working on */
static Lst targets;
#ifdef CLEANUP
/* command lines for targets */
static Lst targCmds;
#endif
/*
* specType contains the SPECial TYPE of the current target. It is
* Not if the target is unspecial. If it *is* special, however, the children
* are linked as children of the parent but not vice versa. This variable is
* set in ParseDoDependency
*/
static ParseSpecial specType;
#define LPAREN '('
#define RPAREN ')'
/*
* Predecessor node for handling .ORDER. Initialized to NULL when .ORDER
* seen, then set to each successive source on the line.
*/
static GNode *predecessor;
////////////////////////////////////////////////////////////
// parser state
/* true if currently in a dependency line or its commands */
static Boolean inLine;
/* number of fatal errors */
static int fatals = 0;
/*
* Variables for doing includes
*/
/* current file being read */
static IFile *curFile;
/* stack of IFiles generated by .includes */
static Lst includes;
/* include paths (lists of directories) */
Lst parseIncPath; /* dirs for "..." includes */
Lst sysIncPath; /* dirs for <...> includes */
Lst defIncPath; /* default for sysIncPath */
////////////////////////////////////////////////////////////
// parser tables
/*
* The parseKeywords table is searched using binary search when deciding
* if a target or source is special. The 'spec' field is the ParseSpecial
@ -238,7 +290,7 @@ static GNode *predecessor;
* the 'op' field is the operator to apply to the list of targets if the
* keyword is used as a source ("0" if the keyword isn't special as a source)
*/
static struct {
static const struct {
const char *name; /* Name of keyword */
ParseSpecial spec; /* Type when used as a target */
int op; /* Operator when used as a source */
@ -258,7 +310,10 @@ static struct {
{ ".MAIN", Main, 0 },
{ ".MAKE", Attribute, OP_MAKE },
{ ".MAKEFLAGS", MFlags, 0 },
{ ".META", Meta, OP_META },
{ ".MFLAGS", MFlags, 0 },
{ ".NOMETA", NoMeta, OP_NOMETA },
{ ".NOMETA_CMP", NoMetaCmp, OP_NOMETA_CMP },
{ ".NOPATH", NoPath, OP_NOPATH },
{ ".NOTMAIN", Attribute, OP_NOTMAIN },
{ ".NOTPARALLEL", NotParallel, 0 },
@ -284,6 +339,9 @@ static struct {
{ ".WAIT", Wait, 0 },
};
////////////////////////////////////////////////////////////
// local functions
static int ParseIsEscaped(const char *, const char *);
static void ParseErrorInternal(const char *, size_t, int, const char *, ...)
__attribute__((__format__(__printf__, 4, 5)));
@ -304,13 +362,220 @@ static void ParseSetParseFile(const char *);
#ifdef SYSVINCLUDE
static void ParseTraditionalInclude(char *);
#endif
#ifdef GMAKEEXPORT
static void ParseGmakeExport(char *);
#endif
static int ParseEOF(void);
static char *ParseReadLine(void);
static void ParseFinishLine(void);
static void ParseMark(GNode *);
extern int maxJobs;
////////////////////////////////////////////////////////////
// file loader
struct loadedfile {
const char *path; /* name, for error reports */
char *buf; /* contents buffer */
size_t len; /* length of contents */
size_t maplen; /* length of mmap area, or 0 */
Boolean used; /* XXX: have we used the data yet */
};
/*
* Constructor/destructor for loadedfile
*/
static struct loadedfile *
loadedfile_create(const char *path)
{
struct loadedfile *lf;
lf = bmake_malloc(sizeof(*lf));
lf->path = (path == NULL ? "(stdin)" : path);
lf->buf = NULL;
lf->len = 0;
lf->maplen = 0;
lf->used = FALSE;
return lf;
}
static void
loadedfile_destroy(struct loadedfile *lf)
{
if (lf->buf != NULL) {
if (lf->maplen > 0) {
#ifndef __minix
munmap(lf->buf, lf->maplen);
#endif
} else {
free(lf->buf);
}
}
free(lf);
}
/*
* nextbuf() operation for loadedfile, as needed by the weird and twisted
* logic below. Once that's cleaned up, we can get rid of lf->used...
*/
static char *
loadedfile_nextbuf(void *x, size_t *len)
{
struct loadedfile *lf = x;
if (lf->used) {
return NULL;
}
lf->used = TRUE;
*len = lf->len;
return lf->buf;
}
/*
* Try to get the size of a file.
*/
static ReturnStatus
load_getsize(int fd, size_t *ret)
{
struct stat st;
if (fstat(fd, &st) < 0) {
return FAILURE;
}
if (!S_ISREG(st.st_mode)) {
return FAILURE;
}
/*
* st_size is an off_t, which is 64 bits signed; *ret is
* size_t, which might be 32 bits unsigned or 64 bits
* unsigned. Rather than being elaborate, just punt on
* files that are more than 2^31 bytes. We should never
* see a makefile that size in practice...
*
* While we're at it reject negative sizes too, just in case.
*/
if (st.st_size < 0 || st.st_size > 0x7fffffff) {
return FAILURE;
}
*ret = (size_t) st.st_size;
return SUCCESS;
}
/*
* Read in a file.
*
* Until the path search logic can be moved under here instead of
* being in the caller in another source file, we need to have the fd
* passed in already open. Bleh.
*
* If the path is NULL use stdin and (to insure against fd leaks)
* assert that the caller passed in -1.
*/
static struct loadedfile *
loadfile(const char *path, int fd)
{
struct loadedfile *lf;
long pagesize;
ssize_t result;
size_t bufpos;
lf = loadedfile_create(path);
if (path == NULL) {
assert(fd == -1);
fd = STDIN_FILENO;
} else {
#if 0 /* notyet */
fd = open(path, O_RDONLY);
if (fd < 0) {
...
Error("%s: %s", path, strerror(errno));
exit(1);
}
#endif
}
#ifndef __minix
if (load_getsize(fd, &lf->len) == SUCCESS) {
/* found a size, try mmap */
pagesize = sysconf(_SC_PAGESIZE);
if (pagesize <= 0) {
pagesize = 0x1000;
}
/* round size up to a page */
lf->maplen = pagesize * ((lf->len + pagesize - 1)/pagesize);
/*
* XXX hack for dealing with empty files; remove when
* we're no longer limited by interfacing to the old
* logic elsewhere in this file.
*/
if (lf->maplen == 0) {
lf->maplen = pagesize;
}
/*
* FUTURE: remove PROT_WRITE when the parser no longer
* needs to scribble on the input.
*/
lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE,
MAP_FILE|MAP_COPY, fd, 0);
if (lf->buf != MAP_FAILED) {
/* succeeded */
if (lf->len == lf->maplen && lf->buf[lf->len - 1] != '\n') {
char *b = malloc(lf->len + 1);
b[lf->len] = '\n';
memcpy(b, lf->buf, lf->len++);
munmap(lf->buf, lf->maplen);
lf->maplen = 0;
lf->buf = b;
}
goto done;
}
}
#endif
/* cannot mmap; load the traditional way */
lf->maplen = 0;
lf->len = 1024;
lf->buf = bmake_malloc(lf->len);
bufpos = 0;
while (1) {
assert(bufpos <= lf->len);
if (bufpos == lf->len) {
lf->len *= 2;
lf->buf = bmake_realloc(lf->buf, lf->len);
}
result = read(fd, lf->buf + bufpos, lf->len - bufpos);
if (result < 0) {
Error("%s: read error: %s", path, strerror(errno));
exit(1);
}
if (result == 0) {
break;
}
bufpos += result;
}
assert(bufpos <= lf->len);
lf->len = bufpos;
/* truncate malloc region to actual length (maybe not useful) */
if (lf->len > 0) {
lf->buf = bmake_realloc(lf->buf, lf->len);
}
done:
if (path != NULL) {
close(fd);
}
return lf;
}
////////////////////////////////////////////////////////////
// old code
/*-
*----------------------------------------------------------------------
@ -404,7 +669,7 @@ ParseVErrorInternal(FILE *f, const char *cfname, size_t clineno, int type,
const char *dir;
/*
* Nothing is more anoying than not knowing
* Nothing is more annoying than not knowing
* which Makefile is the culprit.
*/
dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &cp);
@ -915,7 +1180,7 @@ ParseDoDependency(char *line)
tOp = 0;
specType = Not;
paths = (Lst)NULL;
paths = NULL;
curTargs = Lst_Init(FALSE);
@ -1085,7 +1350,7 @@ ParseDoDependency(char *line)
&line[5]);
goto out;
} else {
if (paths == (Lst)NULL) {
if (paths == NULL) {
paths = Lst_Init(FALSE);
}
(void)Lst_AtEnd(paths, path);
@ -1786,6 +2051,7 @@ Parse_AddIncludeDir(char *dir)
static void
Parse_include_file(char *file, Boolean isSystem, int silent)
{
struct loadedfile *lf;
char *fullname; /* full pathname of file */
char *newName;
char *prefEnd, *incdir;
@ -1876,8 +2142,12 @@ Parse_include_file(char *file, Boolean isSystem, int silent)
return;
}
/* load it */
lf = loadfile(fullname, fd);
/* Start reading from this file next */
Parse_SetInput(fullname, 0, fd, NULL, NULL);
Parse_SetInput(fullname, 0, -1, loadedfile_nextbuf, lf);
curFile->lf = lf;
}
static void
@ -1949,23 +2219,27 @@ ParseDoInclude(char *line)
static void
ParseSetParseFile(const char *filename)
{
char *slash;
char *dirname;
char *slash, *dirname;
const char *pd, *pf;
int len;
slash = strrchr(filename, '/');
if (slash == NULL) {
Var_Set(".PARSEDIR", ".", VAR_GLOBAL, 0);
Var_Set(".PARSEFILE", filename, VAR_GLOBAL, 0);
Var_Set(".PARSEDIR", pd = curdir, VAR_GLOBAL, 0);
Var_Set(".PARSEFILE", pf = filename, VAR_GLOBAL, 0);
dirname= NULL;
} else {
len = slash - filename;
dirname = bmake_malloc(len + 1);
memcpy(dirname, filename, len);
dirname[len] = 0;
Var_Set(".PARSEDIR", dirname, VAR_GLOBAL, 0);
Var_Set(".PARSEFILE", slash+1, VAR_GLOBAL, 0);
free(dirname);
dirname[len] = '\0';
Var_Set(".PARSEDIR", pd = dirname, VAR_GLOBAL, 0);
Var_Set(".PARSEFILE", pf = slash + 1, VAR_GLOBAL, 0);
}
if (DEBUG(PARSE))
fprintf(debug_file, "ParseSetParseFile: ${.PARSEDIR} = `%s' "
"${.PARSEFILE} = `%s'\n", pd, pf);
free(dirname);
}
/*
@ -2014,9 +2288,11 @@ ParseTrackInput(const char *name)
*---------------------------------------------------------------------
*/
void
Parse_SetInput(const char *name, int line, int fd, char *(*nextbuf)(void *), void *arg)
Parse_SetInput(const char *name, int line, int fd,
char *(*nextbuf)(void *, size_t *), void *arg)
{
char *buf;
size_t len;
if (name == NULL)
name = curFile->fname;
@ -2047,33 +2323,22 @@ Parse_SetInput(const char *name, int line, int fd, char *(*nextbuf)(void *), voi
curFile->fname = name;
curFile->lineno = line;
curFile->first_lineno = line;
curFile->fd = fd;
curFile->nextbuf = nextbuf;
curFile->nextbuf_arg = arg;
curFile->lf = NULL;
if (nextbuf == NULL) {
/*
* Allocate a 32k data buffer (as stdio seems to).
* Set pointers so that first ParseReadc has to do a file read.
*/
buf = bmake_malloc(IFILE_BUFLEN);
buf[0] = 0;
curFile->P_str = buf;
curFile->P_ptr = buf;
curFile->P_end = buf;
curFile->P_buflen = IFILE_BUFLEN;
} else {
/* Get first block of input data */
buf = curFile->nextbuf(curFile->nextbuf_arg);
if (buf == NULL) {
/* Was all a waste of time ... */
free(curFile);
return;
}
curFile->P_str = buf;
curFile->P_ptr = buf;
curFile->P_end = NULL;
assert(nextbuf != NULL);
/* Get first block of input data */
buf = curFile->nextbuf(curFile->nextbuf_arg, &len);
if (buf == NULL) {
/* Was all a waste of time ... */
free(curFile);
return;
}
curFile->P_str = buf;
curFile->P_ptr = buf;
curFile->P_end = buf+len;
curFile->cond_depth = Cond_save_depth();
ParseSetParseFile(name);
@ -2143,6 +2408,55 @@ ParseTraditionalInclude(char *line)
}
#endif
#ifdef SYSVINCLUDE
/*-
*---------------------------------------------------------------------
* ParseGmakeExport --
* Parse export <variable>=<value>
*
* And set the environment with it.
*
* Results:
* None
*
* Side Effects:
* None
*---------------------------------------------------------------------
*/
static void
ParseGmakeExport(char *line)
{
char *variable = &line[6];
char *value;
if (DEBUG(PARSE)) {
fprintf(debug_file, "ParseTraditionalInclude: %s\n", variable);
}
/*
* Skip over whitespace
*/
while (isspace((unsigned char)*variable))
variable++;
for (value = variable; *value && *value != '='; value++)
continue;
if (*value != '=') {
Parse_Error(PARSE_FATAL,
"Variable/Value missing from \"include\"");
return;
}
/*
* Substitute for any variables in the file name before trying to
* find the thing.
*/
value = Var_Subst(NULL, value, VAR_CMD, FALSE);
setenv(variable, value, 1);
}
#endif
/*-
*---------------------------------------------------------------------
* ParseEOF --
@ -2162,26 +2476,31 @@ static int
ParseEOF(void)
{
char *ptr;
size_t len;
if (curFile->nextbuf != NULL) {
/* eg .for loop data, get next iteration */
ptr = curFile->nextbuf(curFile->nextbuf_arg);
curFile->P_ptr = ptr;
curFile->P_str = ptr;
curFile->lineno = curFile->first_lineno;
if (ptr != NULL) {
/* Iterate again */
return CONTINUE;
}
assert(curFile->nextbuf != NULL);
/* get next input buffer, if any */
ptr = curFile->nextbuf(curFile->nextbuf_arg, &len);
curFile->P_ptr = ptr;
curFile->P_str = ptr;
curFile->P_end = ptr + len;
curFile->lineno = curFile->first_lineno;
if (ptr != NULL) {
/* Iterate again */
return CONTINUE;
}
/* Ensure the makefile (or loop) didn't have mismatched conditionals */
Cond_restore_depth(curFile->cond_depth);
if (curFile->lf != NULL) {
loadedfile_destroy(curFile->lf);
curFile->lf = NULL;
}
/* Dispose of curFile info */
/* Leak curFile->fname because all the gnodes have pointers to it */
if (curFile->fd != -1)
close(curFile->fd);
free(curFile->P_str);
free(curFile);
@ -2195,8 +2514,8 @@ ParseEOF(void)
}
if (DEBUG(PARSE))
fprintf(debug_file, "ParseEOF: returning to file %s, line %d, fd %d\n",
curFile->fname, curFile->lineno, curFile->fd);
fprintf(debug_file, "ParseEOF: returning to file %s, line %d\n",
curFile->fname, curFile->lineno);
/* Restore the PARSEDIR/PARSEFILE variables */
ParseSetParseFile(curFile->fname);
@ -2217,7 +2536,6 @@ ParseGetLine(int flags, int *length)
char *escaped;
char *comment;
char *tp;
int len, dist;
/* Loop through blank lines and comment lines */
for (;;) {
@ -2228,67 +2546,25 @@ ParseGetLine(int flags, int *length)
escaped = NULL;
comment = NULL;
for (;;) {
if (cf->P_end != NULL && ptr == cf->P_end) {
/* end of buffer */
ch = 0;
break;
}
ch = *ptr;
if (ch == 0 || (ch == '\\' && ptr[1] == 0)) {
if (cf->P_end == NULL)
/* End of string (aka for loop) data */
break;
/* End of data read from file, read more data */
if (ptr != cf->P_end && (ch != '\\' || ptr + 1 != cf->P_end)) {
Parse_Error(PARSE_FATAL, "Zero byte read from file");
return NULL;
}
/* Move existing data to (near) start of file buffer */
len = cf->P_end - cf->P_ptr;
tp = cf->P_str + 32;
memmove(tp, cf->P_ptr, len);
dist = cf->P_ptr - tp;
/* Update all pointers to reflect moved data */
ptr -= dist;
line -= dist;
line_end -= dist;
if (escaped)
escaped -= dist;
if (comment)
comment -= dist;
cf->P_ptr = tp;
tp += len;
cf->P_end = tp;
/* Try to read more data from file into buffer space */
len = cf->P_str + cf->P_buflen - tp - 32;
if (len <= 0) {
/* We need a bigger buffer to hold this line */
tp = bmake_realloc(cf->P_str, cf->P_buflen + IFILE_BUFLEN);
cf->P_ptr = cf->P_ptr - cf->P_str + tp;
cf->P_end = cf->P_end - cf->P_str + tp;
ptr = ptr - cf->P_str + tp;
line = line - cf->P_str + tp;
line_end = line_end - cf->P_str + tp;
if (escaped)
escaped = escaped - cf->P_str + tp;
if (comment)
comment = comment - cf->P_str + tp;
cf->P_str = tp;
tp = cf->P_end;
len += IFILE_BUFLEN;
cf->P_buflen += IFILE_BUFLEN;
}
len = read(cf->fd, tp, len);
if (len <= 0) {
if (len < 0) {
Parse_Error(PARSE_FATAL, "Makefile read error: %s",
strerror(errno));
return NULL;
}
/* End of file */
if (cf->nextbuf != NULL) {
/*
* End of this buffer; return EOF and outer logic
* will get the next one. (eww)
*/
break;
}
/* 0 terminate the data, and update end pointer */
tp += len;
cf->P_end = tp;
*tp = 0;
/* Process newly read characters */
continue;
Parse_Error(PARSE_FATAL, "Zero byte read from file");
return NULL;
}
if (ch == '\\') {
@ -2303,7 +2579,9 @@ ParseGetLine(int flags, int *length)
}
if (ch == '#' && comment == NULL) {
/* Remember first '#' for comment stripping */
comment = line_end;
/* Unless previous char was '[', as in modifier :[#] */
if (!(ptr > line && ptr[-1] == '['))
comment = line_end;
}
ptr++;
if (ch == '\n')
@ -2459,7 +2737,7 @@ ParseReadLine(void)
line = ParseGetLine(PARSE_RAW, &lineLength);
if (line == NULL) {
Parse_Error(PARSE_FATAL,
"Unexpected end of file in for loop.\n");
"Unexpected end of file in for loop.");
break;
}
} while (For_Accum(line));
@ -2522,11 +2800,19 @@ Parse_File(const char *name, int fd)
{
char *cp; /* pointer into the line */
char *line; /* the line we're working on */
struct loadedfile *lf;
lf = loadfile(name, fd);
inLine = FALSE;
fatals = 0;
Parse_SetInput(name, 0, fd, NULL, NULL);
if (name == NULL) {
name = "(stdin)";
}
Parse_SetInput(name, 0, -1, loadedfile_nextbuf, lf);
curFile->lf = lf;
do {
for (; (line = ParseReadLine()) != NULL; ) {
@ -2619,6 +2905,17 @@ Parse_File(const char *name, int fd)
ParseTraditionalInclude(line);
continue;
}
#endif
#ifdef GMAKEEXPORT
if (strncmp(line, "export", 6) == 0 &&
isspace((unsigned char) line[6]) &&
strchr(line, ':') == NULL) {
/*
* It's an Gmake"export".
*/
ParseGmakeExport(line);
continue;
}
#endif
if (Parse_IsVar(line)) {
ParseFinishLine();
@ -2719,7 +3016,7 @@ Parse_File(const char *name, int fd)
if (fatals) {
(void)fflush(stdout);
(void)fprintf(stderr,
"%s: Fatal errors encountered -- cannot continue\n",
"%s: Fatal errors encountered -- cannot continue",
progname);
PrintOnError(NULL, NULL);
exit(1);

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
@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
static char rcsid[] = "$NetBSD: str.c,v 1.33 2009/02/25 21:17:21 sno Exp $";
static char rcsid[] = "$NetBSD: str.c,v 1.34 2012/03/03 23:16:47 dholland Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90";
#else
__RCSID("$NetBSD: str.c,v 1.33 2009/02/25 21:17:21 sno Exp $");
__RCSID("$NetBSD: str.c,v 1.34 2012/03/03 23:16:47 dholland Exp $");
#endif
#endif /* not lint */
#endif
@ -319,6 +319,8 @@ Str_FindSubstring(const char *string, const char *substring)
* matching operation permits the following special characters in the
* pattern: *?\[] (see the man page for details on what these mean).
*
* XXX this function does not detect or report malformed patterns.
*
* Side effects: None.
*/
int

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
@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
static char rcsid[] = "$NetBSD: suff.c,v 1.67 2009/01/23 21:58:28 dsl Exp $";
static char rcsid[] = "$NetBSD: suff.c,v 1.69 2011/09/29 23:38:04 sjg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)suff.c 8.4 (Berkeley) 3/21/94";
#else
__RCSID("$NetBSD: suff.c,v 1.67 2009/01/23 21:58:28 dsl Exp $");
__RCSID("$NetBSD: suff.c,v 1.69 2011/09/29 23:38:04 sjg Exp $");
#endif
#endif /* not lint */
#endif
@ -136,7 +136,6 @@ __RCSID("$NetBSD: suff.c,v 1.67 2009/01/23 21:58:28 dsl Exp $");
*/
#include <stdio.h>
#include <strings.h>
#include "make.h"
#include "hash.h"
#include "dir.h"
@ -1435,7 +1434,7 @@ SuffFindCmds(Src *targ, Lst slst)
* We haven't looked to see if .OPTIONAL files exist yet, so
* don't use one as the implicit source.
* This allows us to use .OPTIONAL in .depend files so make won't
* complain "don't know how to make xxx.h' when a dependant file
* complain "don't know how to make xxx.h' when a dependent file
* has been moved/deleted.
*/
continue;
@ -2407,16 +2406,25 @@ Suff_FindDeps(GNode *gn)
static void
SuffFindDeps(GNode *gn, Lst slst)
{
if (gn->type & (OP_DEPS_FOUND|OP_PHONY)) {
if (gn->type & OP_DEPS_FOUND) {
/*
* If dependencies already found, no need to do it again...
* If this is a .PHONY target, we do not apply suffix rules.
*/
return;
} else {
gn->type |= OP_DEPS_FOUND;
}
/*
* Make sure we have these set, may get revised below.
*/
Var_Set(TARGET, gn->path ? gn->path : gn->name, gn, 0);
Var_Set(PREFIX, gn->name, gn, 0);
if (gn->type & OP_PHONY) {
/*
* If this is a .PHONY target, we do not apply suffix rules.
*/
return;
}
if (DEBUG(SUFF)) {
fprintf(debug_file, "SuffFindDeps (%s)\n", gn->name);
}

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

View file

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

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

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

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
path=:/bin:/usr/bin::/sbin:/usr/sbin:.:/home/user/bin:.
# do not put any dirs in this list which exist on some
# but not all target systems - an exists() check is below.
path=:/bin:/tmp::/:.:/no/such/dir:.
# strip cwd from path.
MOD_NODOT=S/:/ /g:N.:ts:
# and decorate, note that $'s need to be doubled. Also note that
@ -13,7 +15,10 @@ MOD_HOMES=S,/home/,/homes/,
MOD_OPT=@d@$${exists($$d):?$$d:$${d:S,/usr,/opt,}}@
MOD_SEP=S,:, ,g
all: modvar modvarloop
all: modvar modvarloop modsysv
modsysv:
@echo "The answer is ${libfoo.a:L:libfoo.a=42}"
modvar:
@echo "path='${path}'"

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
OK
make: "error" line 3: just FYI
make: "error" line 4: warning: this could be serious
make: "error" line 5: this is fatal
UT_DOLLAR=This is $UT_FU
UT_FOO=foobar is fubar
UT_FU=fubar
UT_TEST=export
UT_ZOO=hoopie
UT_ALL=even this gets exported
UT_BADDIR=unit-tests
UT_DOLLAR=This is $UT_FU
UT_F=fine
UT_FOO=foobar is fubar
UT_FU=fubar
UT_NO=all
UT_OK=good
UT_OKDIR=unit-tests
UT_TEST=export-all
UT_ZOO=hoopie
At first, I am
happy
and now: sad
.ERROR: Looks like 'sad' is upset.
*** Error code 1
Stop.
make: stopped in unit-tests
simple.1
simple.1
simple.2
@ -68,6 +81,14 @@ make: Graph cycles through `cycle.2.97'
cycle.1.99
cycle.1.99
.for with :S;... OK
b2af338b
3360ac65
7747f046
9ca87054
880fe816
208fcbd3
d5d376eb
de41416c
Expect: Unknown modifier 'Z'
make: Unknown modifier 'Z'
VAR:Z=
@ -99,14 +120,15 @@ LIB=e X_LIBS:M${LIB${LIB:tu}} is "/tmp/libe.a"
LIB=e X_LIBS:M*/lib${LIB}.a is "/tmp/libe.a"
LIB=e X_LIBS:M*/lib${LIB}.a:tu is "/TMP/LIBE.A"
Mscanner=OK
path=':/bin:/usr/bin::/sbin:/usr/sbin:.:/home/user/bin:.'
path='/bin:/usr/bin:/sbin:/usr/sbin:/home/user/bin'
path='/bin:/usr/bin:/sbin:/usr/sbin:/homes/user/bin'
path='/bin':'/usr/bin':'/sbin':'/usr/sbin':'/home/user/bin'
path='/bin':'/usr/bin':'/sbin':'/usr/sbin':'/homes/user/bin'
path=':/bin:/tmp::/:.:/no/such/dir:.'
path='/bin:/tmp:/:/no/such/dir'
path='/bin:/tmp:/:/no/such/dir'
path='/bin':'/tmp':'/':'/no/such/dir'
path='/bin':'/tmp':'/':'/no/such/dir'
path_/usr/xbin=/opt/xbin/
paths=/bin /usr/bin /sbin /usr/sbin /homes/user/bin /opt/xbin
PATHS=/BIN /USR/BIN /SBIN /USR/SBIN /HOMES/USER/BIN /OPT/XBIN
paths=/bin /tmp / /no/such/dir /opt/xbin
PATHS=/BIN /TMP / /NO/SUCH/DIR /OPT/XBIN
The answer is 42
LIST = one two three four five six seven eight nine ten
LIST:O = eight five four nine one seven six ten three two
LIST:Ox = Ok
@ -270,6 +292,11 @@ LIST:tw:C/ /,/g="one two three four five six"
LIST:tw:C/ /,/1g="one two three four five six"
LIST:tw:tW:C/ /,/="one,two three four five six"
LIST:tW:tw:C/ /,/="one two three four five six"
.TARGET="phony" .PREFIX="phony" .IMPSRC=""
.TARGET="all" .PREFIX="all" .IMPSRC=""
.TARGET="ok" .PREFIX="ok" .IMPSRC=""
.TARGET="also.ok" .PREFIX="also.ok" .IMPSRC=""
.TARGET="bug" .PREFIX="bug" .IMPSRC=""
Posix says we should execute the command as if run by system(3)
Expect 'Hello,' and 'World!'
Hello,
@ -293,6 +320,12 @@ Now we expect an error...
*** Error code 1 (continuing)
`all' not remade because of errors.
V.i386 ?= OK
FOOBAR =
FOOBAR = foobar fubar
fun
fun
fun
In the Sun
The answer is unknown
The answer is unknown
The answer is empty
@ -314,3 +347,5 @@ five FU=<v>bar</v> FOO=<v>goo</v> VAR=<v>Internal</v>
five v=is x k=is x
six v=is y k=is y
show-v v=override k=override
*** Error code 1 (ignored)
*** Error code 1 (ignored)

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
*/
#ifndef MAKE_NATIVE
static char rcsid[] = "$NetBSD: util.c,v 1.50 2010/06/03 15:40:16 sjg Exp $";
static char rcsid[] = "$NetBSD: util.c,v 1.51 2011/04/02 07:58:30 mbalmer Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: util.c,v 1.50 2010/06/03 15:40:16 sjg Exp $");
__RCSID("$NetBSD: util.c,v 1.51 2011/04/02 07:58:30 mbalmer Exp $");
#endif
#endif
@ -49,7 +49,7 @@ findenv(const char *name, int *offset)
char *p, *q;
for (i = 0; (q = environ[i]); i++) {
char *p = strchr(q, '=');
p = strchr(q, '=');
if (p == NULL)
continue;
if (strncmp(name, q, len = p - q) == 0) {

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
@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
static char rcsid[] = "$NetBSD: var.c,v 1.159 2010/06/06 01:13:12 sjg Exp $";
static char rcsid[] = "$NetBSD: var.c,v 1.167 2011/06/03 21:10:42 sjg Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
#else
__RCSID("$NetBSD: var.c,v 1.159 2010/06/06 01:13:12 sjg Exp $");
__RCSID("$NetBSD: var.c,v 1.167 2011/06/03 21:10:42 sjg Exp $");
#endif
#endif /* not lint */
#endif
@ -129,8 +129,10 @@ __RCSID("$NetBSD: var.c,v 1.159 2010/06/06 01:13:12 sjg Exp $");
#include <regex.h>
#endif
#include <ctype.h>
#include <inttypes.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#include "make.h"
#include "buf.h"
@ -302,6 +304,7 @@ static char *VarGetPattern(GNode *, Var_Parse_State *,
VarPattern *);
static char *VarQuote(char *);
static char *VarChangeCase(char *, int);
static char *VarHash(char *);
static char *VarModify(GNode *, Var_Parse_State *,
const char *,
Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *),
@ -379,6 +382,12 @@ VarFind(const char *name, GNode *ctxt, int flags)
name = TARGET;
break;
}
#ifdef notyet
/* for compatibility with gmake */
if (name[0] == '^' && name[1] == '\0')
name = ALLSRC;
#endif
/*
* First look for the variable in the given context. If it's not there,
* look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
@ -2254,6 +2263,79 @@ VarQuote(char *str)
return str;
}
/*-
*-----------------------------------------------------------------------
* VarHash --
* Hash the string using the MurmurHash3 algorithm.
* Output is computed using 32bit Little Endian arithmetic.
*
* Input:
* str String to modify
*
* Results:
* Hash value of str, encoded as 8 hex digits.
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
static char *
VarHash(char *str)
{
static const char hexdigits[16] = "0123456789abcdef";
Buffer buf;
size_t len, len2;
unsigned char *ustr = (unsigned char *)str;
uint32_t h, k, c1, c2;
int done;
done = 1;
h = 0x971e137bU;
c1 = 0x95543787U;
c2 = 0x2ad7eb25U;
len2 = strlen(str);
for (len = len2; len; ) {
k = 0;
switch (len) {
default:
k = (ustr[3] << 24) | (ustr[2] << 16) | (ustr[1] << 8) | ustr[0];
len -= 4;
ustr += 4;
break;
case 3:
k |= (ustr[2] << 16);
case 2:
k |= (ustr[1] << 8);
case 1:
k |= ustr[0];
len = 0;
}
c1 = c1 * 5 + 0x7b7d159cU;
c2 = c2 * 5 + 0x6bce6396U;
k *= c1;
k = (k << 11) ^ (k >> 21);
k *= c2;
h = (h << 13) ^ (h >> 19);
h = h * 5 + 0x52dce729U;
h ^= k;
} while (!done);
h ^= len2;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
Buf_Init(&buf, 0);
for (len = 0; len < 8; ++len) {
Buf_AddByte(&buf, hexdigits[h & 15]);
h >>= 4;
}
return Buf_Destroy(&buf, FALSE);
}
/*-
*-----------------------------------------------------------------------
* VarChangeCase --
@ -2285,6 +2367,21 @@ VarChangeCase(char *str, int upper)
return Buf_Destroy(&buf, FALSE);
}
static char *
VarStrftime(const char *fmt, int zulu)
{
char buf[BUFSIZ];
time_t utc;
time(&utc);
if (!*fmt)
fmt = "%c";
strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc));
buf[sizeof(buf) - 1] = '\0';
return bmake_strdup(buf);
}
/*
* Now we need to apply any modifiers the user wants applied.
* These are:
@ -2370,6 +2467,10 @@ VarChangeCase(char *str, int upper)
* variable.
*/
/* we now have some modifiers with long names */
#define STRMOD_MATCH(s, want, n) \
(strncmp(s, want, n) == 0 && (s[n] == endc || s[n] == ':'))
static char *
ApplyModifiers(char *nstr, const char *tstr,
int startc, int endc,
@ -2397,14 +2498,28 @@ ApplyModifiers(char *nstr, const char *tstr,
if (*tstr == '$') {
/*
* We have some complex modifiers in a variable.
* We may have some complex modifiers in a variable.
*/
void *freeIt;
char *rval;
int rlen;
int c;
rval = Var_Parse(tstr, ctxt, errnum, &rlen, &freeIt);
/*
* If we have not parsed up to endc or ':',
* we are not interested.
*/
if (rval != NULL && *rval &&
(c = tstr[rlen]) != '\0' &&
c != ':' &&
c != endc) {
if (freeIt)
free(freeIt);
goto apply_mods;
}
if (DEBUG(VAR)) {
fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n",
rval, rlen, tstr, rlen, tstr + rlen);
@ -2436,6 +2551,7 @@ ApplyModifiers(char *nstr, const char *tstr,
}
continue;
}
apply_mods:
if (DEBUG(VAR)) {
fprintf(debug_file, "Applying :%c to \"%s\"\n", *tstr, nstr);
}
@ -2486,7 +2602,7 @@ ApplyModifiers(char *nstr, const char *tstr,
cp = ++tstr;
break;
}
delim = BRCLOSE;
delim = startc == PROPEN ? PRCLOSE : BRCLOSE;
pattern.flags = 0;
pattern.rhs = VarGetPattern(ctxt, &parsestate, errnum,
@ -2815,6 +2931,36 @@ ApplyModifiers(char *nstr, const char *tstr,
}
}
case 'g':
cp = tstr + 1; /* make sure it is set */
if (STRMOD_MATCH(tstr, "gmtime", 6)) {
newStr = VarStrftime(nstr, 1);
cp = tstr + 6;
termc = *cp;
} else {
goto default_case;
}
break;
case 'h':
cp = tstr + 1; /* make sure it is set */
if (STRMOD_MATCH(tstr, "hash", 4)) {
newStr = VarHash(nstr);
cp = tstr + 4;
termc = *cp;
} else {
goto default_case;
}
break;
case 'l':
cp = tstr + 1; /* make sure it is set */
if (STRMOD_MATCH(tstr, "localtime", 9)) {
newStr = VarStrftime(nstr, 0);
cp = tstr + 9;
termc = *cp;
} else {
goto default_case;
}
break;
case 't':
{
cp = tstr + 1; /* make sure it is set */
@ -3340,9 +3486,13 @@ ApplyModifiers(char *nstr, const char *tstr,
*/
termc = *--cp;
delim = '\0';
newStr = VarModify(ctxt, &parsestate, nstr,
VarSYSVMatch,
&pattern);
if (pattern.leftLen == 0 && *nstr == '\0') {
newStr = nstr; /* special case */
} else {
newStr = VarModify(ctxt, &parsestate, nstr,
VarSYSVMatch,
&pattern);
}
free(UNCONST(pattern.lhs));
free(UNCONST(pattern.rhs));
} else
@ -3740,7 +3890,7 @@ Var_Parse(const char *str, GNode *ctxt, Boolean errnum, int *lengthPtr,
nstr = bmake_strndup(start, *lengthPtr);
*freePtr = nstr;
} else {
nstr = var_Error;
nstr = errnum ? var_Error : varNoError;
}
}
if (nstr != Buf_GetAll(&v->val, NULL))