Merge bmake-20220204
This commit is contained in:
commit
9f45a3c8c8
@ -1,3 +1,158 @@
|
|||||||
|
2022-02-04 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20220204
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o use unsigned consistently for line numbers, avoid the need for %z
|
||||||
|
o parse.c: do not step off end of input in Parse_IsVar
|
||||||
|
when checking for target local variable assignments
|
||||||
|
|
||||||
|
2022-02-02 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20220202
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o remove redundant declaration of HashIter_Init
|
||||||
|
o make DEBUG0 simpler
|
||||||
|
|
||||||
|
2022-01-30 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* cast gn->lineno to avoid %z
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20220130
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o more unit tests
|
||||||
|
o make GNode lineno unsigned to please lint
|
||||||
|
o print location of recursive variable references in commands
|
||||||
|
o print "stack trace" (makefile includes) on fatal errors
|
||||||
|
o make.1: refine documentation for target local assignments
|
||||||
|
|
||||||
|
2022-01-28 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20220128
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o inline functions called only once
|
||||||
|
o for.c: clean up AddEscape for building the body of a .for loop
|
||||||
|
o hash.c: merge duplicate code for finding an entry in a hash table
|
||||||
|
replace HashEntry_KeyEquals with strncmp
|
||||||
|
o make.1: document quirks of target local variable assignments.
|
||||||
|
o parse.c: cleanup white-space
|
||||||
|
|
||||||
|
2022-01-26 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20220126
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o allow setting target local variables
|
||||||
|
o more unit tests
|
||||||
|
o add missing newline after "cannot continue" message
|
||||||
|
o meta.c: clean up eat_dots
|
||||||
|
o parse.c: fix filename in warning about duplicate script
|
||||||
|
o var.c: when expanding nested variables, check simple things first
|
||||||
|
|
||||||
|
2022-01-16 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20220116
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o fix for unit-tests/varname-makeflags on non-BSD systems
|
||||||
|
o use Var_Exists rather than Var_Value where appropriate
|
||||||
|
o remove unnecessary functions for expanding variable names
|
||||||
|
o cond.c: inline EvalBare
|
||||||
|
o main.c: lint cleanup
|
||||||
|
o parse.c: condense code in Parse_IsVar
|
||||||
|
use islower for parsing directives (none have upper case)
|
||||||
|
|
||||||
|
2022-01-12 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20220112
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o meta.c: add .MAKE.META.CMP_FILTER for filtering commands before
|
||||||
|
comparion, rarely needed but useful when it is.
|
||||||
|
|
||||||
|
2022-01-10 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20220110
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o inline Buf_Clear
|
||||||
|
o remove redundant braces
|
||||||
|
o rename and inline Targ_Precious
|
||||||
|
o cond.c: remove redundant initializer in CondParser_ComparisonOrLeaf
|
||||||
|
o for.c: clean up handling of .for loops
|
||||||
|
fix reported line numbers of continuation lines
|
||||||
|
add details about .for loop variables to stack traces
|
||||||
|
o job.c: reduce code for initializing error handling in shell
|
||||||
|
o main.c: in Cmd_Exec, return error message instead of format string
|
||||||
|
have as few statements as possible between va_start and va_end
|
||||||
|
add debug logging for capturing the output of external commands
|
||||||
|
o make.c: use consistent variable names for varargs
|
||||||
|
o make_malloc.c: remove duplicate code from bmake_strdup
|
||||||
|
o parse.c: add missing printflike annotations
|
||||||
|
remove redundant lines from stack traces
|
||||||
|
fix stack traces in -dp mode
|
||||||
|
reduce confusing code in ParseForLoop
|
||||||
|
fix line number in debug log after returning from a file
|
||||||
|
rename IFile and its fields to match their actual content
|
||||||
|
clean up ParseDependencySources
|
||||||
|
o var.c: shorten ApplyModifier_Assign
|
||||||
|
rename is_shell_metachar, fix character conversion warning
|
||||||
|
merge calls to ApplyModifier_Time
|
||||||
|
merge duplicate code for modifiers 'gmtime' and 'localtime'
|
||||||
|
|
||||||
|
2022-01-04 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* parse.c: loadfile restore extra byte in buffer.
|
||||||
|
|
||||||
|
2022-01-01 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20220101
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o more unit-tests
|
||||||
|
o remove unnecessary words from command line options in CmdOpts
|
||||||
|
o rename eunlink to unlink_file
|
||||||
|
o cond.c: make ParseWord in condition parser simpler
|
||||||
|
internally return false for irrelevant leaves in conditions
|
||||||
|
replace table for function lookup in conditions with simple code
|
||||||
|
merge duplicate types CondEvalResult and CondResult
|
||||||
|
o for.c: clean up handling of .for loops and .include directives
|
||||||
|
o main.c: constify cached_realpath
|
||||||
|
clean up Cmd_Exec
|
||||||
|
o parse.c: sync API documentation
|
||||||
|
fix error message when reading more than 1 GB from stdin
|
||||||
|
clean up parsing of makefiles
|
||||||
|
fix line number in error message about open conditionals
|
||||||
|
unexport types VarAssignOp and VarAssign
|
||||||
|
clean up function names
|
||||||
|
remove redundant parameters in dependency parsing functions
|
||||||
|
reduce scope of the list of wildcard target names
|
||||||
|
extract OP_NOTARGET into separate function
|
||||||
|
clean up variable names for parsing dependency lines
|
||||||
|
make debug logging a bit more human-friendly
|
||||||
|
o var.c: condense code in ApplyModifier_Assign
|
||||||
|
|
||||||
|
2021-12-21 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20211221
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o more unit-tests
|
||||||
|
o style cleanup
|
||||||
|
o in CLEANUP mode, free interned strings at the very end
|
||||||
|
o fix memory leak for filenames in .for loops
|
||||||
|
o buf.c: avoid memory leak
|
||||||
|
o cond.c: condense CondParser_ComparisonOp
|
||||||
|
o hash.c: change return type of HashTable_Set to void
|
||||||
|
o job.c: change return type of Compat_RunCommand from int to bool
|
||||||
|
o main.c: remove bmake_free
|
||||||
|
o parse.c: condense repetetive code in ParseDirective
|
||||||
|
remove dead code for handling traditional include directives
|
||||||
|
clean up parsing of variable assignments
|
||||||
|
remove unreachable code for parsing the dependency operator
|
||||||
|
clean up loading of files
|
||||||
|
fix memory leak in IncludeFile
|
||||||
|
o var.c: fix memory leak when parsing a variable name
|
||||||
|
fix memory leak from ${.SUFFIXES}
|
||||||
|
reduce memory allocation in modifier ':?' and ':C'
|
||||||
|
condense RegexReplace for the modifier ':C' and avoid strlen
|
||||||
|
merge duplicate code for memory handling in Var_Parse
|
||||||
|
distinguish between short-lived and environment variables
|
||||||
|
rename VarFreeEnv to VarFreeShortLived
|
||||||
|
|
||||||
2021-12-15 Simon J Gerraty <sjg@beast.crufty.net>
|
2021-12-15 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
* cond.c: fix mem leak in CondParser_Leaf
|
* cond.c: fix mem leak in CondParser_Leaf
|
||||||
|
@ -53,7 +53,6 @@ metachar.c
|
|||||||
metachar.h
|
metachar.h
|
||||||
missing/sys/cdefs.h
|
missing/sys/cdefs.h
|
||||||
mkdeps.sh
|
mkdeps.sh
|
||||||
nonints.h
|
|
||||||
os.sh
|
os.sh
|
||||||
parse.c
|
parse.c
|
||||||
pathnames.h
|
pathnames.h
|
||||||
@ -173,10 +172,14 @@ unit-tests/dep-double-colon-indep.exp
|
|||||||
unit-tests/dep-double-colon-indep.mk
|
unit-tests/dep-double-colon-indep.mk
|
||||||
unit-tests/dep-double-colon.exp
|
unit-tests/dep-double-colon.exp
|
||||||
unit-tests/dep-double-colon.mk
|
unit-tests/dep-double-colon.mk
|
||||||
|
unit-tests/dep-duplicate.exp
|
||||||
|
unit-tests/dep-duplicate.mk
|
||||||
unit-tests/dep-exclam.exp
|
unit-tests/dep-exclam.exp
|
||||||
unit-tests/dep-exclam.mk
|
unit-tests/dep-exclam.mk
|
||||||
unit-tests/dep-none.exp
|
unit-tests/dep-none.exp
|
||||||
unit-tests/dep-none.mk
|
unit-tests/dep-none.mk
|
||||||
|
unit-tests/dep-op-missing.exp
|
||||||
|
unit-tests/dep-op-missing.mk
|
||||||
unit-tests/dep-percent.exp
|
unit-tests/dep-percent.exp
|
||||||
unit-tests/dep-percent.mk
|
unit-tests/dep-percent.mk
|
||||||
unit-tests/dep-var.exp
|
unit-tests/dep-var.exp
|
||||||
@ -371,8 +374,6 @@ unit-tests/doterror.exp
|
|||||||
unit-tests/doterror.mk
|
unit-tests/doterror.mk
|
||||||
unit-tests/dotwait.exp
|
unit-tests/dotwait.exp
|
||||||
unit-tests/dotwait.mk
|
unit-tests/dotwait.mk
|
||||||
unit-tests/envfirst.exp
|
|
||||||
unit-tests/envfirst.mk
|
|
||||||
unit-tests/error.exp
|
unit-tests/error.exp
|
||||||
unit-tests/error.mk
|
unit-tests/error.mk
|
||||||
unit-tests/escape.exp
|
unit-tests/escape.exp
|
||||||
@ -427,10 +428,6 @@ unit-tests/modmatch.exp
|
|||||||
unit-tests/modmatch.mk
|
unit-tests/modmatch.mk
|
||||||
unit-tests/modmisc.exp
|
unit-tests/modmisc.exp
|
||||||
unit-tests/modmisc.mk
|
unit-tests/modmisc.mk
|
||||||
unit-tests/modts.exp
|
|
||||||
unit-tests/modts.mk
|
|
||||||
unit-tests/modword.exp
|
|
||||||
unit-tests/modword.mk
|
|
||||||
unit-tests/objdir-writable.exp
|
unit-tests/objdir-writable.exp
|
||||||
unit-tests/objdir-writable.mk
|
unit-tests/objdir-writable.mk
|
||||||
unit-tests/opt-backwards.exp
|
unit-tests/opt-backwards.exp
|
||||||
@ -535,6 +532,8 @@ unit-tests/opt-var-expanded.exp
|
|||||||
unit-tests/opt-var-expanded.mk
|
unit-tests/opt-var-expanded.mk
|
||||||
unit-tests/opt-var-literal.exp
|
unit-tests/opt-var-literal.exp
|
||||||
unit-tests/opt-var-literal.mk
|
unit-tests/opt-var-literal.mk
|
||||||
|
unit-tests/opt-version.exp
|
||||||
|
unit-tests/opt-version.mk
|
||||||
unit-tests/opt-warnings-as-errors.exp
|
unit-tests/opt-warnings-as-errors.exp
|
||||||
unit-tests/opt-warnings-as-errors.mk
|
unit-tests/opt-warnings-as-errors.mk
|
||||||
unit-tests/opt-where-am-i.exp
|
unit-tests/opt-where-am-i.exp
|
||||||
@ -547,6 +546,8 @@ unit-tests/order.exp
|
|||||||
unit-tests/order.mk
|
unit-tests/order.mk
|
||||||
unit-tests/parse-var.exp
|
unit-tests/parse-var.exp
|
||||||
unit-tests/parse-var.mk
|
unit-tests/parse-var.mk
|
||||||
|
unit-tests/parse.exp
|
||||||
|
unit-tests/parse.mk
|
||||||
unit-tests/phony-end.exp
|
unit-tests/phony-end.exp
|
||||||
unit-tests/phony-end.mk
|
unit-tests/phony-end.mk
|
||||||
unit-tests/posix.exp
|
unit-tests/posix.exp
|
||||||
@ -625,18 +626,6 @@ unit-tests/unexport.exp
|
|||||||
unit-tests/unexport.mk
|
unit-tests/unexport.mk
|
||||||
unit-tests/use-inference.exp
|
unit-tests/use-inference.exp
|
||||||
unit-tests/use-inference.mk
|
unit-tests/use-inference.mk
|
||||||
unit-tests/var-class-cmdline.exp
|
|
||||||
unit-tests/var-class-cmdline.mk
|
|
||||||
unit-tests/var-class-env.exp
|
|
||||||
unit-tests/var-class-env.mk
|
|
||||||
unit-tests/var-class-global.exp
|
|
||||||
unit-tests/var-class-global.mk
|
|
||||||
unit-tests/var-class-local-legacy.exp
|
|
||||||
unit-tests/var-class-local-legacy.mk
|
|
||||||
unit-tests/var-class-local.exp
|
|
||||||
unit-tests/var-class-local.mk
|
|
||||||
unit-tests/var-class.exp
|
|
||||||
unit-tests/var-class.mk
|
|
||||||
unit-tests/var-eval-short.exp
|
unit-tests/var-eval-short.exp
|
||||||
unit-tests/var-eval-short.mk
|
unit-tests/var-eval-short.mk
|
||||||
unit-tests/var-op-append.exp
|
unit-tests/var-op-append.exp
|
||||||
@ -655,6 +644,18 @@ unit-tests/var-op.exp
|
|||||||
unit-tests/var-op.mk
|
unit-tests/var-op.mk
|
||||||
unit-tests/var-recursive.exp
|
unit-tests/var-recursive.exp
|
||||||
unit-tests/var-recursive.mk
|
unit-tests/var-recursive.mk
|
||||||
|
unit-tests/var-scope-cmdline.exp
|
||||||
|
unit-tests/var-scope-cmdline.mk
|
||||||
|
unit-tests/var-scope-env.exp
|
||||||
|
unit-tests/var-scope-env.mk
|
||||||
|
unit-tests/var-scope-global.exp
|
||||||
|
unit-tests/var-scope-global.mk
|
||||||
|
unit-tests/var-scope-local-legacy.exp
|
||||||
|
unit-tests/var-scope-local-legacy.mk
|
||||||
|
unit-tests/var-scope-local.exp
|
||||||
|
unit-tests/var-scope-local.mk
|
||||||
|
unit-tests/var-scope.exp
|
||||||
|
unit-tests/var-scope.mk
|
||||||
unit-tests/varcmd.exp
|
unit-tests/varcmd.exp
|
||||||
unit-tests/varcmd.mk
|
unit-tests/varcmd.mk
|
||||||
unit-tests/vardebug.exp
|
unit-tests/vardebug.exp
|
||||||
@ -663,6 +664,8 @@ unit-tests/varfind.exp
|
|||||||
unit-tests/varfind.mk
|
unit-tests/varfind.mk
|
||||||
unit-tests/varmisc.exp
|
unit-tests/varmisc.exp
|
||||||
unit-tests/varmisc.mk
|
unit-tests/varmisc.mk
|
||||||
|
unit-tests/varmod-assign-shell.exp
|
||||||
|
unit-tests/varmod-assign-shell.mk
|
||||||
unit-tests/varmod-assign.exp
|
unit-tests/varmod-assign.exp
|
||||||
unit-tests/varmod-assign.mk
|
unit-tests/varmod-assign.mk
|
||||||
unit-tests/varmod-defined.exp
|
unit-tests/varmod-defined.exp
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
# keep this compatible with sh and make
|
# keep this compatible with sh and make
|
||||||
_MAKE_VERSION=20211212
|
_MAKE_VERSION=20220204
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: arch.c,v 1.205 2021/12/12 22:41:47 rillig Exp $ */
|
/* $NetBSD: arch.c,v 1.210 2022/01/15 18:34:41 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
* Copyright (c) 1988, 1989, 1990, 1993
|
||||||
@ -147,7 +147,7 @@ struct ar_hdr {
|
|||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
|
|
||||||
/* "@(#)arch.c 8.2 (Berkeley) 1/2/94" */
|
/* "@(#)arch.c 8.2 (Berkeley) 1/2/94" */
|
||||||
MAKE_RCSID("$NetBSD: arch.c,v 1.205 2021/12/12 22:41:47 rillig Exp $");
|
MAKE_RCSID("$NetBSD: arch.c,v 1.210 2022/01/15 18:34:41 rillig Exp $");
|
||||||
|
|
||||||
typedef struct List ArchList;
|
typedef struct List ArchList;
|
||||||
typedef struct ListNode ArchListNode;
|
typedef struct ListNode ArchListNode;
|
||||||
@ -247,19 +247,20 @@ FullName(const char *archive, const char *member)
|
|||||||
bool
|
bool
|
||||||
Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
|
Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
|
||||||
{
|
{
|
||||||
char *cp; /* Pointer into line */
|
char *spec; /* For modifying some bytes of *pp */
|
||||||
|
const char *cp; /* Pointer into line */
|
||||||
GNode *gn; /* New node */
|
GNode *gn; /* New node */
|
||||||
MFStr libName; /* Library-part of specification */
|
FStr lib; /* Library-part of specification */
|
||||||
FStr mem; /* Member-part of specification */
|
FStr mem; /* Member-part of specification */
|
||||||
char saveChar; /* Ending delimiter of member-name */
|
char saveChar; /* Ending delimiter of member-name */
|
||||||
bool expandLibName; /* Whether the parsed libName contains
|
bool expandLib; /* Whether the parsed lib contains variable
|
||||||
* variable expressions that need to be
|
* expressions that need to be expanded */
|
||||||
* expanded */
|
|
||||||
|
|
||||||
libName = MFStr_InitRefer(*pp);
|
spec = *pp;
|
||||||
expandLibName = false;
|
lib = FStr_InitRefer(spec);
|
||||||
|
expandLib = false;
|
||||||
|
|
||||||
for (cp = libName.str; *cp != '(' && *cp != '\0';) {
|
for (cp = lib.str; *cp != '(' && *cp != '\0';) {
|
||||||
if (*cp == '$') {
|
if (*cp == '$') {
|
||||||
/* Expand nested variable expressions. */
|
/* Expand nested variable expressions. */
|
||||||
/* XXX: This code can probably be shortened. */
|
/* XXX: This code can probably be shortened. */
|
||||||
@ -276,20 +277,15 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
|
|||||||
if (isError)
|
if (isError)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
expandLibName = true;
|
expandLib = true;
|
||||||
cp += nested_p - cp;
|
cp += nested_p - cp;
|
||||||
} else
|
} else
|
||||||
cp++;
|
cp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*cp++ = '\0';
|
spec[cp++ - spec] = '\0';
|
||||||
if (expandLibName) {
|
if (expandLib)
|
||||||
char *expanded;
|
Var_Expand(&lib, scope, VARE_UNDEFERR);
|
||||||
(void)Var_Subst(libName.str, scope, VARE_UNDEFERR, &expanded);
|
|
||||||
/* TODO: handle errors */
|
|
||||||
libName = MFStr_InitOwn(expanded);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/*
|
/*
|
||||||
@ -299,13 +295,15 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
|
|||||||
*/
|
*/
|
||||||
bool doSubst = false;
|
bool doSubst = false;
|
||||||
|
|
||||||
pp_skip_whitespace(&cp);
|
cpp_skip_whitespace(&cp);
|
||||||
|
|
||||||
mem = FStr_InitRefer(cp);
|
mem = FStr_InitRefer(cp);
|
||||||
while (*cp != '\0' && *cp != ')' && !ch_isspace(*cp)) {
|
while (*cp != '\0' && *cp != ')' && !ch_isspace(*cp)) {
|
||||||
if (*cp == '$') {
|
if (*cp == '$') {
|
||||||
/* Expand nested variable expressions. */
|
/* Expand nested variable expressions. */
|
||||||
/* XXX: This code can probably be shortened. */
|
/*
|
||||||
|
* XXX: This code can probably be shortened.
|
||||||
|
*/
|
||||||
FStr result;
|
FStr result;
|
||||||
bool isError;
|
bool isError;
|
||||||
const char *nested_p = cp;
|
const char *nested_p = cp;
|
||||||
@ -334,8 +332,8 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
|
|||||||
*/
|
*/
|
||||||
if (*cp == '\0') {
|
if (*cp == '\0') {
|
||||||
Parse_Error(PARSE_FATAL,
|
Parse_Error(PARSE_FATAL,
|
||||||
"No closing parenthesis "
|
"No closing parenthesis "
|
||||||
"in archive specification");
|
"in archive specification");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,7 +344,7 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
saveChar = *cp;
|
saveChar = *cp;
|
||||||
*cp = '\0';
|
spec[cp - spec] = '\0';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX: This should be taken care of intelligently by
|
* XXX: This should be taken care of intelligently by
|
||||||
@ -363,19 +361,16 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
|
|||||||
*/
|
*/
|
||||||
if (doSubst) {
|
if (doSubst) {
|
||||||
char *fullName;
|
char *fullName;
|
||||||
char *p, *expandedMem;
|
char *p;
|
||||||
const char *unexpandedMem = mem.str;
|
const char *unexpandedMem = mem.str;
|
||||||
|
|
||||||
(void)Var_Subst(mem.str, scope, VARE_UNDEFERR,
|
Var_Expand(&mem, scope, VARE_UNDEFERR);
|
||||||
&expandedMem);
|
|
||||||
/* TODO: handle errors */
|
|
||||||
mem = FStr_InitOwn(expandedMem);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now form an archive spec and recurse to deal with
|
* Now form an archive spec and recurse to deal with
|
||||||
* nested variables and multi-word variable values.
|
* nested variables and multi-word variable values.
|
||||||
*/
|
*/
|
||||||
fullName = FullName(libName.str, mem.str);
|
fullName = FullName(lib.str, mem.str);
|
||||||
p = fullName;
|
p = fullName;
|
||||||
|
|
||||||
if (strcmp(mem.str, unexpandedMem) == 0) {
|
if (strcmp(mem.str, unexpandedMem) == 0) {
|
||||||
@ -404,7 +399,7 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
|
|||||||
|
|
||||||
while (!Lst_IsEmpty(&members)) {
|
while (!Lst_IsEmpty(&members)) {
|
||||||
char *member = Lst_Dequeue(&members);
|
char *member = Lst_Dequeue(&members);
|
||||||
char *fullname = FullName(libName.str, member);
|
char *fullname = FullName(lib.str, member);
|
||||||
free(member);
|
free(member);
|
||||||
|
|
||||||
gn = Targ_GetNode(fullname);
|
gn = Targ_GetNode(fullname);
|
||||||
@ -416,7 +411,7 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
|
|||||||
Lst_Done(&members);
|
Lst_Done(&members);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
char *fullname = FullName(libName.str, mem.str);
|
char *fullname = FullName(lib.str, mem.str);
|
||||||
gn = Targ_GetNode(fullname);
|
gn = Targ_GetNode(fullname);
|
||||||
free(fullname);
|
free(fullname);
|
||||||
|
|
||||||
@ -432,15 +427,15 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
|
|||||||
}
|
}
|
||||||
FStr_Done(&mem);
|
FStr_Done(&mem);
|
||||||
|
|
||||||
*cp = saveChar;
|
spec[cp - spec] = saveChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
MFStr_Done(&libName);
|
FStr_Done(&lib);
|
||||||
|
|
||||||
cp++; /* skip the ')' */
|
cp++; /* skip the ')' */
|
||||||
/* We promised that pp would be set up at the next non-space. */
|
/* We promised that pp would be set up at the next non-space. */
|
||||||
pp_skip_whitespace(&cp);
|
cpp_skip_whitespace(&cp);
|
||||||
*pp = cp;
|
*pp += cp - *pp;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -672,7 +667,7 @@ ArchSVR4Entry(Arch *ar, char *inout_name, size_t size, FILE *arch)
|
|||||||
|
|
||||||
if (ar->fnametab != NULL) {
|
if (ar->fnametab != NULL) {
|
||||||
DEBUG0(ARCH,
|
DEBUG0(ARCH,
|
||||||
"Attempted to redefine an SVR4 name table\n");
|
"Attempted to redefine an SVR4 name table\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -693,8 +688,9 @@ ArchSVR4Entry(Arch *ar, char *inout_name, size_t size, FILE *arch)
|
|||||||
entry++;
|
entry++;
|
||||||
*ptr = '\0';
|
*ptr = '\0';
|
||||||
}
|
}
|
||||||
DEBUG1(ARCH, "Found svr4 archive name table with %lu entries\n",
|
DEBUG1(ARCH,
|
||||||
(unsigned long)entry);
|
"Found svr4 archive name table with %lu entries\n",
|
||||||
|
(unsigned long)entry);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,7 +704,7 @@ ArchSVR4Entry(Arch *ar, char *inout_name, size_t size, FILE *arch)
|
|||||||
}
|
}
|
||||||
if (entry >= ar->fnamesize) {
|
if (entry >= ar->fnamesize) {
|
||||||
DEBUG2(ARCH, "SVR4 entry offset %s is greater than %lu\n",
|
DEBUG2(ARCH, "SVR4 entry offset %s is greater than %lu\n",
|
||||||
inout_name, (unsigned long)ar->fnamesize);
|
inout_name, (unsigned long)ar->fnamesize);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -737,8 +733,10 @@ ArchiveMember_HasName(const struct ar_hdr *hdr,
|
|||||||
if (ar_name[namelen] == ' ')
|
if (ar_name[namelen] == ' ')
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* In archives created by GNU binutils 2.27, the member names end with
|
/*
|
||||||
* a slash. */
|
* In archives created by GNU binutils 2.27, the member names end
|
||||||
|
* with a slash.
|
||||||
|
*/
|
||||||
if (ar_name[namelen] == '/' &&
|
if (ar_name[namelen] == '/' &&
|
||||||
(namelen == ar_name_len || ar_name[namelen + 1] == ' '))
|
(namelen == ar_name_len || ar_name[namelen + 1] == ' '))
|
||||||
return true;
|
return true;
|
||||||
@ -809,9 +807,9 @@ ArchFindMember(const char *archive, const char *member, struct ar_hdr *out_arh,
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEBUG5(ARCH, "Reading archive %s member %.*s mtime %.*s\n",
|
DEBUG5(ARCH, "Reading archive %s member %.*s mtime %.*s\n",
|
||||||
archive,
|
archive,
|
||||||
(int)sizeof out_arh->AR_NAME, out_arh->AR_NAME,
|
(int)sizeof out_arh->AR_NAME, out_arh->AR_NAME,
|
||||||
(int)sizeof out_arh->ar_date, out_arh->ar_date);
|
(int)sizeof out_arh->ar_date, out_arh->ar_date);
|
||||||
|
|
||||||
if (ArchiveMember_HasName(out_arh, member, len)) {
|
if (ArchiveMember_HasName(out_arh, member, len)) {
|
||||||
/*
|
/*
|
||||||
@ -912,7 +910,7 @@ Arch_Touch(GNode *gn)
|
|||||||
struct ar_hdr arh;
|
struct ar_hdr arh;
|
||||||
|
|
||||||
f = ArchFindMember(GNode_VarArchive(gn), GNode_VarMember(gn), &arh,
|
f = ArchFindMember(GNode_VarArchive(gn), GNode_VarMember(gn), &arh,
|
||||||
"r+");
|
"r+");
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.\" $NetBSD: make.1,v 1.300 2021/12/12 20:45:48 sjg Exp $
|
.\" $NetBSD: make.1,v 1.304 2022/01/29 20:54:58 sjg Exp $
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 1990, 1993
|
.\" Copyright (c) 1990, 1993
|
||||||
.\" The Regents of the University of California. All rights reserved.
|
.\" The Regents of the University of California. All rights reserved.
|
||||||
@ -29,7 +29,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
|
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
|
||||||
.\"
|
.\"
|
||||||
.Dd December 12, 2021
|
.Dd January 28, 2022
|
||||||
.Dt BMAKE 1
|
.Dt BMAKE 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -691,10 +691,38 @@ Variables defined as part of the command line.
|
|||||||
Variables that are defined specific to a certain target.
|
Variables that are defined specific to a certain target.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
Local variables are all built in and their values vary magically from
|
Local variables can be set on a dependency line, if
|
||||||
target to target.
|
.Va .MAKE.TARGET_LOCAL_VARIABLES ,
|
||||||
It is not currently possible to define new local variables.
|
is not set to
|
||||||
The seven local variables are as follows:
|
.Ql false .
|
||||||
|
The rest of the line
|
||||||
|
(which will already have had Global variables expanded),
|
||||||
|
is the variable value.
|
||||||
|
For example:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
COMPILER_WRAPPERS+= ccache distcc icecc
|
||||||
|
|
||||||
|
${OBJS}: .MAKE.META.CMP_FILTER=${COMPILER_WRAPPERS:S,^,N,}
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Only the targets
|
||||||
|
.Ql ${OBJS}
|
||||||
|
will be impacted by that filter (in "meta" mode) and
|
||||||
|
simply enabling/disabling any of the wrappers will not render all
|
||||||
|
of those targets out-of-date.
|
||||||
|
.Pp
|
||||||
|
.Em NOTE :
|
||||||
|
target local variable assignments behave differently in that;
|
||||||
|
.Bl -tag -width Ds -offset indent
|
||||||
|
.It Ic \&+=
|
||||||
|
Only appends to a previous local assignment
|
||||||
|
for the same target and variable.
|
||||||
|
.It Ic \&:=
|
||||||
|
Is redundant with respect to Global variables,
|
||||||
|
which have already been expanded.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The seven built-in local variables are as follows:
|
||||||
.Bl -tag -width ".ARCHIVE" -offset indent
|
.Bl -tag -width ".ARCHIVE" -offset indent
|
||||||
.It Va .ALLSRC
|
.It Va .ALLSRC
|
||||||
The list of all sources for this target; also known as
|
The list of all sources for this target; also known as
|
||||||
@ -846,6 +874,11 @@ For example:
|
|||||||
would produce tokens like
|
would produce tokens like
|
||||||
.Ql ---make[1234] target ---
|
.Ql ---make[1234] target ---
|
||||||
making it easier to track the degree of parallelism being achieved.
|
making it easier to track the degree of parallelism being achieved.
|
||||||
|
.It .MAKE.TARGET_LOCAL_VARIABLES
|
||||||
|
If set to
|
||||||
|
.Ql false ,
|
||||||
|
apparent variable assignments in dependency lines are
|
||||||
|
treated as normal sources.
|
||||||
.It Ev MAKEFLAGS
|
.It Ev MAKEFLAGS
|
||||||
The environment variable
|
The environment variable
|
||||||
.Ql Ev MAKEFLAGS
|
.Ql Ev MAKEFLAGS
|
||||||
@ -954,6 +987,12 @@ If a file that was generated outside of
|
|||||||
.Va .OBJDIR
|
.Va .OBJDIR
|
||||||
but within said bailiwick is missing,
|
but within said bailiwick is missing,
|
||||||
the current target is considered out-of-date.
|
the current target is considered out-of-date.
|
||||||
|
.It Va .MAKE.META.CMP_FILTER
|
||||||
|
In "meta" mode, it can (very rarely!) be useful to filter command
|
||||||
|
lines before comparison.
|
||||||
|
This variable can be set to a set of modifiers that will be applied to
|
||||||
|
each line of the old and new command that differ, if the filtered
|
||||||
|
commands still differ, the target is considered out-of-date.
|
||||||
.It Va .MAKE.META.CREATED
|
.It Va .MAKE.META.CREATED
|
||||||
In "meta" mode, this variable contains a list of all the meta files
|
In "meta" mode, this variable contains a list of all the meta files
|
||||||
updated.
|
updated.
|
||||||
|
@ -443,9 +443,28 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1)
|
|||||||
Local variables
|
Local variables
|
||||||
Variables that are defined specific to a certain target.
|
Variables that are defined specific to a certain target.
|
||||||
|
|
||||||
Local variables are all built in and their values vary magically from
|
Local variables can be set on a dependency line, if
|
||||||
target to target. It is not currently possible to define new local vari-
|
[4m.MAKE.TARGET_LOCAL_VARIABLES[24m, is not set to `false'. The rest of the
|
||||||
ables. The seven local variables are as follows:
|
line (which will already have had Global variables expanded), is the
|
||||||
|
variable value. For example:
|
||||||
|
|
||||||
|
COMPILER_WRAPPERS+= ccache distcc icecc
|
||||||
|
|
||||||
|
${OBJS}: .MAKE.META.CMP_FILTER=${COMPILER_WRAPPERS:S,^,N,}
|
||||||
|
|
||||||
|
Only the targets `${OBJS}' will be impacted by that filter (in "meta"
|
||||||
|
mode) and simply enabling/disabling any of the wrappers will not render
|
||||||
|
all of those targets out-of-date.
|
||||||
|
|
||||||
|
[4mNOTE[24m: target local variable assignments behave differently in that;
|
||||||
|
|
||||||
|
[1m+= [22mOnly appends to a previous local assignment for the same
|
||||||
|
target and variable.
|
||||||
|
|
||||||
|
[1m:= [22mIs redundant with respect to Global variables, which have
|
||||||
|
already been expanded.
|
||||||
|
|
||||||
|
The seven built-in local variables are as follows:
|
||||||
|
|
||||||
[4m.ALLSRC[24m The list of all sources for this target; also known as
|
[4m.ALLSRC[24m The list of all sources for this target; also known as
|
||||||
`[4m>[24m'.
|
`[4m>[24m'.
|
||||||
@ -538,6 +557,10 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1)
|
|||||||
ing it easier to track the degree of parallelism being
|
ing it easier to track the degree of parallelism being
|
||||||
achieved.
|
achieved.
|
||||||
|
|
||||||
|
.MAKE.TARGET_LOCAL_VARIABLES
|
||||||
|
If set to `false', apparent variable assignments in de-
|
||||||
|
pendency lines are treated as normal sources.
|
||||||
|
|
||||||
MAKEFLAGS The environment variable `MAKEFLAGS' may contain anything
|
MAKEFLAGS The environment variable `MAKEFLAGS' may contain anything
|
||||||
that may be specified on [1mbmake[22m's command line. Anything
|
that may be specified on [1mbmake[22m's command line. Anything
|
||||||
specified on [1mbmake[22m's command line is appended to the
|
specified on [1mbmake[22m's command line is appended to the
|
||||||
@ -616,6 +639,14 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1)
|
|||||||
generated outside of [4m.OBJDIR[24m but within said bailiwick is
|
generated outside of [4m.OBJDIR[24m but within said bailiwick is
|
||||||
missing, the current target is considered out-of-date.
|
missing, the current target is considered out-of-date.
|
||||||
|
|
||||||
|
[4m.MAKE.META.CMP_FILTER[0m
|
||||||
|
In "meta" mode, it can (very rarely!) be useful to filter
|
||||||
|
command lines before comparison. This variable can be
|
||||||
|
set to a set of modifiers that will be applied to each
|
||||||
|
line of the old and new command that differ, if the fil-
|
||||||
|
tered commands still differ, the target is considered
|
||||||
|
out-of-date.
|
||||||
|
|
||||||
[4m.MAKE.META.CREATED[0m
|
[4m.MAKE.META.CREATED[0m
|
||||||
In "meta" mode, this variable contains a list of all the
|
In "meta" mode, this variable contains a list of all the
|
||||||
meta files updated. If not empty, it can be used to
|
meta files updated. If not empty, it can be used to
|
||||||
@ -1591,4 +1622,4 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1)
|
|||||||
|
|
||||||
There is no way of escaping a space character in a filename.
|
There is no way of escaping a space character in a filename.
|
||||||
|
|
||||||
FreeBSD 13.0 December 12, 2021 FreeBSD 13.0
|
FreeBSD 13.0 January 28, 2022 FreeBSD 13.0
|
||||||
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 82 KiB |
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: buf.c,v 1.53 2021/11/28 22:48:06 rillig Exp $ */
|
/* $NetBSD: buf.c,v 1.55 2022/01/08 17:25:19 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
@ -75,7 +75,7 @@
|
|||||||
#include "make.h"
|
#include "make.h"
|
||||||
|
|
||||||
/* "@(#)buf.c 8.1 (Berkeley) 6/6/93" */
|
/* "@(#)buf.c 8.1 (Berkeley) 6/6/93" */
|
||||||
MAKE_RCSID("$NetBSD: buf.c,v 1.53 2021/11/28 22:48:06 rillig Exp $");
|
MAKE_RCSID("$NetBSD: buf.c,v 1.55 2022/01/08 17:25:19 rillig Exp $");
|
||||||
|
|
||||||
/* Make space in the buffer for adding at least 16 more bytes. */
|
/* Make space in the buffer for adding at least 16 more bytes. */
|
||||||
void
|
void
|
||||||
@ -138,14 +138,6 @@ Buf_AddFlag(Buffer *buf, bool flag, const char *name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark the buffer as empty, so it can be filled with data again. */
|
|
||||||
void
|
|
||||||
Buf_Empty(Buffer *buf)
|
|
||||||
{
|
|
||||||
buf->len = 0;
|
|
||||||
buf->data[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize a buffer. */
|
/* Initialize a buffer. */
|
||||||
void
|
void
|
||||||
Buf_InitSize(Buffer *buf, size_t cap)
|
Buf_InitSize(Buffer *buf, size_t cap)
|
||||||
@ -214,8 +206,9 @@ Buf_DoneDataCompact(Buffer *buf)
|
|||||||
if (buf->cap - buf->len >= BUF_COMPACT_LIMIT) {
|
if (buf->cap - buf->len >= BUF_COMPACT_LIMIT) {
|
||||||
/* We trust realloc to be smart */
|
/* We trust realloc to be smart */
|
||||||
char *data = bmake_realloc(buf->data, buf->len + 1);
|
char *data = bmake_realloc(buf->data, buf->len + 1);
|
||||||
|
buf->data = NULL;
|
||||||
data[buf->len] = '\0'; /* XXX: unnecessary */
|
data[buf->len] = '\0'; /* XXX: unnecessary */
|
||||||
Buf_DoneData(buf);
|
Buf_Done(buf);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: buf.h,v 1.44 2021/11/28 22:48:06 rillig Exp $ */
|
/* $NetBSD: buf.h,v 1.47 2022/01/08 17:25:19 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
@ -88,6 +88,14 @@ typedef struct Buffer {
|
|||||||
|
|
||||||
void Buf_Expand(Buffer *);
|
void Buf_Expand(Buffer *);
|
||||||
|
|
||||||
|
/* Mark the buffer as empty, so it can be filled with data again. */
|
||||||
|
MAKE_INLINE void
|
||||||
|
Buf_Clear(Buffer *buf)
|
||||||
|
{
|
||||||
|
buf->len = 0;
|
||||||
|
buf->data[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
/* Buf_AddByte adds a single byte to a buffer. */
|
/* Buf_AddByte adds a single byte to a buffer. */
|
||||||
MAKE_INLINE void
|
MAKE_INLINE void
|
||||||
Buf_AddByte(Buffer *buf, char byte)
|
Buf_AddByte(Buffer *buf, char byte)
|
||||||
@ -101,7 +109,7 @@ Buf_AddByte(Buffer *buf, char byte)
|
|||||||
end[1] = '\0';
|
end[1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
Buf_EndsWith(const Buffer *buf, char ch)
|
Buf_EndsWith(const Buffer *buf, char ch)
|
||||||
{
|
{
|
||||||
return buf->len > 0 && buf->data[buf->len - 1] == ch;
|
return buf->len > 0 && buf->data[buf->len - 1] == ch;
|
||||||
@ -112,11 +120,10 @@ void Buf_AddBytesBetween(Buffer *, const char *, const char *);
|
|||||||
void Buf_AddStr(Buffer *, const char *);
|
void Buf_AddStr(Buffer *, const char *);
|
||||||
void Buf_AddInt(Buffer *, int);
|
void Buf_AddInt(Buffer *, int);
|
||||||
void Buf_AddFlag(Buffer *, bool, const char *);
|
void Buf_AddFlag(Buffer *, bool, const char *);
|
||||||
void Buf_Empty(Buffer *);
|
|
||||||
void Buf_Init(Buffer *);
|
void Buf_Init(Buffer *);
|
||||||
void Buf_InitSize(Buffer *, size_t);
|
void Buf_InitSize(Buffer *, size_t);
|
||||||
void Buf_Done(Buffer *);
|
void Buf_Done(Buffer *);
|
||||||
char *Buf_DoneData(Buffer *);
|
char *Buf_DoneData(Buffer *) MAKE_ATTR_USE;
|
||||||
char *Buf_DoneDataCompact(Buffer *);
|
char *Buf_DoneDataCompact(Buffer *) MAKE_ATTR_USE;
|
||||||
|
|
||||||
#endif /* MAKE_BUF_H */
|
#endif
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: compat.c,v 1.229 2021/11/28 23:12:51 rillig Exp $ */
|
/* $NetBSD: compat.c,v 1.238 2022/01/22 18:59:23 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
@ -99,7 +99,7 @@
|
|||||||
#include "pathnames.h"
|
#include "pathnames.h"
|
||||||
|
|
||||||
/* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */
|
/* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */
|
||||||
MAKE_RCSID("$NetBSD: compat.c,v 1.229 2021/11/28 23:12:51 rillig Exp $");
|
MAKE_RCSID("$NetBSD: compat.c,v 1.238 2022/01/22 18:59:23 rillig Exp $");
|
||||||
|
|
||||||
static GNode *curTarg = NULL;
|
static GNode *curTarg = NULL;
|
||||||
static pid_t compatChild;
|
static pid_t compatChild;
|
||||||
@ -112,10 +112,10 @@ static int compatSigno;
|
|||||||
static void
|
static void
|
||||||
CompatDeleteTarget(GNode *gn)
|
CompatDeleteTarget(GNode *gn)
|
||||||
{
|
{
|
||||||
if (gn != NULL && !Targ_Precious(gn)) {
|
if (gn != NULL && !GNode_IsPrecious(gn)) {
|
||||||
const char *file = GNode_VarTarget(gn);
|
const char *file = GNode_VarTarget(gn);
|
||||||
|
|
||||||
if (!opts.noExecute && eunlink(file) != -1) {
|
if (!opts.noExecute && unlink_file(file)) {
|
||||||
Error("*** %s removed", file);
|
Error("*** %s removed", file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ CompatInterrupt(int signo)
|
|||||||
{
|
{
|
||||||
CompatDeleteTarget(curTarg);
|
CompatDeleteTarget(curTarg);
|
||||||
|
|
||||||
if (curTarg != NULL && !Targ_Precious(curTarg)) {
|
if (curTarg != NULL && !GNode_IsPrecious(curTarg)) {
|
||||||
/*
|
/*
|
||||||
* Run .INTERRUPT only if hit with interrupt signal
|
* Run .INTERRUPT only if hit with interrupt signal
|
||||||
*/
|
*/
|
||||||
@ -168,10 +168,12 @@ DebugFailedTarget(const char *cmd, const GNode *gn)
|
|||||||
{
|
{
|
||||||
const char *p = cmd;
|
const char *p = cmd;
|
||||||
debug_printf("\n*** Failed target: %s\n*** Failed command: ",
|
debug_printf("\n*** Failed target: %s\n*** Failed command: ",
|
||||||
gn->name);
|
gn->name);
|
||||||
|
|
||||||
/* Replace runs of whitespace with a single space, to reduce
|
/*
|
||||||
* the amount of whitespace for multi-line command lines. */
|
* Replace runs of whitespace with a single space, to reduce the
|
||||||
|
* amount of whitespace for multi-line command lines.
|
||||||
|
*/
|
||||||
while (*p != '\0') {
|
while (*p != '\0') {
|
||||||
if (ch_isspace(*p)) {
|
if (ch_isspace(*p)) {
|
||||||
debug_printf(" ");
|
debug_printf(" ");
|
||||||
@ -220,24 +222,24 @@ UseShell(const char *cmd MAKE_ATTR_UNUSED)
|
|||||||
* ln List node that contains the command
|
* ln List node that contains the command
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* 0 if the command succeeded, 1 if an error occurred.
|
* true if the command succeeded.
|
||||||
*/
|
*/
|
||||||
int
|
bool
|
||||||
Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
||||||
{
|
{
|
||||||
char *cmdStart; /* Start of expanded command */
|
char *cmdStart; /* Start of expanded command */
|
||||||
char *bp;
|
char *bp;
|
||||||
bool silent; /* Don't print command */
|
bool silent; /* Don't print command */
|
||||||
bool doIt; /* Execute even if -n */
|
bool doIt; /* Execute even if -n */
|
||||||
volatile bool errCheck; /* Check errors */
|
volatile bool errCheck; /* Check errors */
|
||||||
WAIT_T reason; /* Reason for child's death */
|
WAIT_T reason; /* Reason for child's death */
|
||||||
WAIT_T status; /* Description of child's death */
|
WAIT_T status; /* Description of child's death */
|
||||||
pid_t cpid; /* Child actually found */
|
pid_t cpid; /* Child actually found */
|
||||||
pid_t retstat; /* Result of wait */
|
pid_t retstat; /* Result of wait */
|
||||||
const char **volatile av; /* Argument vector for thing to exec */
|
const char **volatile av; /* Argument vector for thing to exec */
|
||||||
char **volatile mav; /* Copy of the argument vector for freeing */
|
char **volatile mav; /* Copy of the argument vector for freeing */
|
||||||
bool useShell; /* True if command should be executed
|
bool useShell; /* True if command should be executed using a
|
||||||
* using a shell */
|
* shell */
|
||||||
const char *volatile cmd = cmdp;
|
const char *volatile cmd = cmdp;
|
||||||
|
|
||||||
silent = (gn->type & OP_SILENT) != OP_NONE;
|
silent = (gn->type & OP_SILENT) != OP_NONE;
|
||||||
@ -249,7 +251,7 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
|||||||
|
|
||||||
if (cmdStart[0] == '\0') {
|
if (cmdStart[0] == '\0') {
|
||||||
free(cmdStart);
|
free(cmdStart);
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
cmd = cmdStart;
|
cmd = cmdStart;
|
||||||
LstNode_Set(ln, cmdStart);
|
LstNode_Set(ln, cmdStart);
|
||||||
@ -269,12 +271,12 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
|||||||
* usual '$$'.
|
* usual '$$'.
|
||||||
*/
|
*/
|
||||||
Lst_Append(&endNode->commands, cmdStart);
|
Lst_Append(&endNode->commands, cmdStart);
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (strcmp(cmdStart, "...") == 0) {
|
if (strcmp(cmdStart, "...") == 0) {
|
||||||
gn->type |= OP_SAVE_CMDS;
|
gn->type |= OP_SAVE_CMDS;
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -298,7 +300,7 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
|||||||
* If we did not end up with a command, just skip it.
|
* If we did not end up with a command, just skip it.
|
||||||
*/
|
*/
|
||||||
if (cmd[0] == '\0')
|
if (cmd[0] == '\0')
|
||||||
return 0;
|
return true;
|
||||||
|
|
||||||
useShell = UseShell(cmd);
|
useShell = UseShell(cmd);
|
||||||
/*
|
/*
|
||||||
@ -315,7 +317,7 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
|||||||
* we go...
|
* we go...
|
||||||
*/
|
*/
|
||||||
if (!doIt && !GNode_ShouldExecute(gn))
|
if (!doIt && !GNode_ShouldExecute(gn))
|
||||||
return 0;
|
return true;
|
||||||
|
|
||||||
DEBUG1(JOB, "Execute: '%s'\n", cmd);
|
DEBUG1(JOB, "Execute: '%s'\n", cmd);
|
||||||
|
|
||||||
@ -350,25 +352,20 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_META
|
#ifdef USE_META
|
||||||
if (useMeta) {
|
if (useMeta)
|
||||||
meta_compat_start();
|
meta_compat_start();
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Var_ReexportVars();
|
Var_ReexportVars();
|
||||||
|
|
||||||
/*
|
|
||||||
* Fork and execute the single command. If the fork fails, we abort.
|
|
||||||
*/
|
|
||||||
compatChild = cpid = vfork();
|
compatChild = cpid = vfork();
|
||||||
if (cpid < 0) {
|
if (cpid < 0)
|
||||||
Fatal("Could not fork");
|
Fatal("Could not fork");
|
||||||
}
|
|
||||||
if (cpid == 0) {
|
if (cpid == 0) {
|
||||||
#ifdef USE_META
|
#ifdef USE_META
|
||||||
if (useMeta) {
|
if (useMeta)
|
||||||
meta_compat_child();
|
meta_compat_child();
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
(void)execvp(av[0], (char *const *)UNCONST(av));
|
(void)execvp(av[0], (char *const *)UNCONST(av));
|
||||||
execDie("exec", av[0]);
|
execDie("exec", av[0]);
|
||||||
@ -382,9 +379,8 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
|||||||
LstNode_SetNull(ln);
|
LstNode_SetNull(ln);
|
||||||
|
|
||||||
#ifdef USE_META
|
#ifdef USE_META
|
||||||
if (useMeta) {
|
if (useMeta)
|
||||||
meta_compat_parent(cpid);
|
meta_compat_parent(cpid);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -406,9 +402,8 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
|||||||
} else if (WIFEXITED(reason)) {
|
} else if (WIFEXITED(reason)) {
|
||||||
status = WEXITSTATUS(reason); /* exited */
|
status = WEXITSTATUS(reason); /* exited */
|
||||||
#if defined(USE_META) && defined(USE_FILEMON_ONCE)
|
#if defined(USE_META) && defined(USE_FILEMON_ONCE)
|
||||||
if (useMeta) {
|
if (useMeta)
|
||||||
meta_cmd_finish(NULL);
|
meta_cmd_finish(NULL);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
if (DEBUG(ERROR))
|
if (DEBUG(ERROR))
|
||||||
@ -424,9 +419,8 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
|||||||
if (!WIFEXITED(reason) || status != 0) {
|
if (!WIFEXITED(reason) || status != 0) {
|
||||||
if (errCheck) {
|
if (errCheck) {
|
||||||
#ifdef USE_META
|
#ifdef USE_META
|
||||||
if (useMeta) {
|
if (useMeta)
|
||||||
meta_job_error(NULL, gn, false, status);
|
meta_job_error(NULL, gn, false, status);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
gn->made = ERROR;
|
gn->made = ERROR;
|
||||||
if (opts.keepgoing) {
|
if (opts.keepgoing) {
|
||||||
@ -457,7 +451,7 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
|||||||
kill(myPid, compatSigno);
|
kill(myPid, compatSigno);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -467,7 +461,7 @@ RunCommands(GNode *gn)
|
|||||||
|
|
||||||
for (ln = gn->commands.first; ln != NULL; ln = ln->next) {
|
for (ln = gn->commands.first; ln != NULL; ln = ln->next) {
|
||||||
const char *cmd = ln->datum;
|
const char *cmd = ln->datum;
|
||||||
if (Compat_RunCommand(cmd, gn, ln) != 0)
|
if (!Compat_RunCommand(cmd, gn, ln))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -532,7 +526,7 @@ MakeUnmade(GNode *gn, GNode *pgn)
|
|||||||
* to tell him/her "yes".
|
* to tell him/her "yes".
|
||||||
*/
|
*/
|
||||||
DEBUG0(MAKE, "out-of-date.\n");
|
DEBUG0(MAKE, "out-of-date.\n");
|
||||||
if (opts.queryFlag)
|
if (opts.query)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -547,7 +541,7 @@ MakeUnmade(GNode *gn, GNode *pgn)
|
|||||||
*/
|
*/
|
||||||
if (opts.ignoreErrors)
|
if (opts.ignoreErrors)
|
||||||
gn->type |= OP_IGNORE;
|
gn->type |= OP_IGNORE;
|
||||||
if (opts.beSilent)
|
if (opts.silent)
|
||||||
gn->type |= OP_SILENT;
|
gn->type |= OP_SILENT;
|
||||||
|
|
||||||
if (Job_CheckCommands(gn, Fatal)) {
|
if (Job_CheckCommands(gn, Fatal)) {
|
||||||
@ -555,12 +549,11 @@ MakeUnmade(GNode *gn, GNode *pgn)
|
|||||||
* Our commands are ok, but we still have to worry about
|
* Our commands are ok, but we still have to worry about
|
||||||
* the -t flag.
|
* the -t flag.
|
||||||
*/
|
*/
|
||||||
if (!opts.touchFlag || (gn->type & OP_MAKE)) {
|
if (!opts.touch || (gn->type & OP_MAKE)) {
|
||||||
curTarg = gn;
|
curTarg = gn;
|
||||||
#ifdef USE_META
|
#ifdef USE_META
|
||||||
if (useMeta && GNode_ShouldExecute(gn)) {
|
if (useMeta && GNode_ShouldExecute(gn))
|
||||||
meta_job_start(NULL, gn);
|
meta_job_start(NULL, gn);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
RunCommands(gn);
|
RunCommands(gn);
|
||||||
curTarg = NULL;
|
curTarg = NULL;
|
||||||
@ -593,7 +586,7 @@ MakeUnmade(GNode *gn, GNode *pgn)
|
|||||||
} else if (opts.keepgoing) {
|
} else if (opts.keepgoing) {
|
||||||
pgn->flags.remake = false;
|
pgn->flags.remake = false;
|
||||||
} else {
|
} else {
|
||||||
PrintOnError(gn, "\nStop.");
|
PrintOnError(gn, "\nStop.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -681,7 +674,7 @@ MakeBeginNode(void)
|
|||||||
|
|
||||||
Compat_Make(gn, gn);
|
Compat_Make(gn, gn);
|
||||||
if (GNode_IsError(gn)) {
|
if (GNode_IsError(gn)) {
|
||||||
PrintOnError(gn, "\nStop.");
|
PrintOnError(gn, "\nStop.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -715,12 +708,14 @@ Compat_Run(GNodeList *targs)
|
|||||||
|
|
||||||
InitSignals();
|
InitSignals();
|
||||||
|
|
||||||
/* Create the .END node now, to keep the (debug) output of the
|
/*
|
||||||
* counter.mk test the same as before 2020-09-23. This implementation
|
* Create the .END node now, to keep the (debug) output of the
|
||||||
* detail probably doesn't matter though. */
|
* counter.mk test the same as before 2020-09-23. This
|
||||||
|
* implementation detail probably doesn't matter though.
|
||||||
|
*/
|
||||||
(void)Targ_GetEndNode();
|
(void)Targ_GetEndNode();
|
||||||
|
|
||||||
if (!opts.queryFlag)
|
if (!opts.query)
|
||||||
MakeBeginNode();
|
MakeBeginNode();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -737,7 +732,7 @@ Compat_Run(GNodeList *targs)
|
|||||||
printf("`%s' is up to date.\n", gn->name);
|
printf("`%s' is up to date.\n", gn->name);
|
||||||
} else if (gn->made == ABORTED) {
|
} else if (gn->made == ABORTED) {
|
||||||
printf("`%s' not remade because of errors.\n",
|
printf("`%s' not remade because of errors.\n",
|
||||||
gn->name);
|
gn->name);
|
||||||
}
|
}
|
||||||
if (GNode_IsError(gn) && errorNode == NULL)
|
if (GNode_IsError(gn) && errorNode == NULL)
|
||||||
errorNode = gn;
|
errorNode = gn;
|
||||||
@ -756,7 +751,7 @@ Compat_Run(GNodeList *targs)
|
|||||||
Targ_PrintGraph(2);
|
Targ_PrintGraph(2);
|
||||||
else if (DEBUG(GRAPH3))
|
else if (DEBUG(GRAPH3))
|
||||||
Targ_PrintGraph(3);
|
Targ_PrintGraph(3);
|
||||||
PrintOnError(errorNode, "\nStop.");
|
PrintOnError(errorNode, "\nStop.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: cond.c,v 1.302 2021/12/12 09:36:00 rillig Exp $ */
|
/* $NetBSD: cond.c,v 1.327 2022/01/29 01:12:36 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
@ -95,10 +95,10 @@
|
|||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
|
|
||||||
/* "@(#)cond.c 8.2 (Berkeley) 1/2/94" */
|
/* "@(#)cond.c 8.2 (Berkeley) 1/2/94" */
|
||||||
MAKE_RCSID("$NetBSD: cond.c,v 1.302 2021/12/12 09:36:00 rillig Exp $");
|
MAKE_RCSID("$NetBSD: cond.c,v 1.327 2022/01/29 01:12:36 rillig Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The parsing of conditional expressions is based on this grammar:
|
* Conditional expressions conform to this grammar:
|
||||||
* Or -> And ('||' And)*
|
* Or -> And ('||' And)*
|
||||||
* And -> Term ('&&' Term)*
|
* And -> Term ('&&' Term)*
|
||||||
* Term -> Function '(' Argument ')'
|
* Term -> Function '(' Argument ')'
|
||||||
@ -109,13 +109,13 @@ MAKE_RCSID("$NetBSD: cond.c,v 1.302 2021/12/12 09:36:00 rillig Exp $");
|
|||||||
* Leaf -> "string"
|
* Leaf -> "string"
|
||||||
* Leaf -> Number
|
* Leaf -> Number
|
||||||
* Leaf -> VariableExpression
|
* Leaf -> VariableExpression
|
||||||
* Leaf -> Symbol
|
* Leaf -> BareWord
|
||||||
* Operator -> '==' | '!=' | '>' | '<' | '>=' | '<='
|
* Operator -> '==' | '!=' | '>' | '<' | '>=' | '<='
|
||||||
*
|
*
|
||||||
* 'Symbol' is an unquoted string literal to which the default function is
|
* BareWord is an unquoted string literal, its evaluation depends on the kind
|
||||||
* applied.
|
* of '.if' directive.
|
||||||
*
|
*
|
||||||
* The tokens are scanned by CondToken, which returns:
|
* The tokens are scanned by CondParser_Token, which returns:
|
||||||
* TOK_AND for '&&'
|
* TOK_AND for '&&'
|
||||||
* TOK_OR for '||'
|
* TOK_OR for '||'
|
||||||
* TOK_NOT for '!'
|
* TOK_NOT for '!'
|
||||||
@ -123,18 +123,14 @@ MAKE_RCSID("$NetBSD: cond.c,v 1.302 2021/12/12 09:36:00 rillig Exp $");
|
|||||||
* TOK_RPAREN for ')'
|
* TOK_RPAREN for ')'
|
||||||
*
|
*
|
||||||
* Other terminal symbols are evaluated using either the default function or
|
* Other terminal symbols are evaluated using either the default function or
|
||||||
* the function given in the terminal, they return either TOK_TRUE or
|
* the function given in the terminal, they return either TOK_TRUE, TOK_FALSE
|
||||||
* TOK_FALSE.
|
* or TOK_ERROR.
|
||||||
*/
|
*/
|
||||||
typedef enum Token {
|
typedef enum Token {
|
||||||
TOK_FALSE, TOK_TRUE, TOK_AND, TOK_OR, TOK_NOT,
|
TOK_FALSE, TOK_TRUE, TOK_AND, TOK_OR, TOK_NOT,
|
||||||
TOK_LPAREN, TOK_RPAREN, TOK_EOF, TOK_NONE, TOK_ERROR
|
TOK_LPAREN, TOK_RPAREN, TOK_EOF, TOK_NONE, TOK_ERROR
|
||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
typedef enum CondResult {
|
|
||||||
CR_FALSE, CR_TRUE, CR_ERROR
|
|
||||||
} CondResult;
|
|
||||||
|
|
||||||
typedef enum ComparisonOp {
|
typedef enum ComparisonOp {
|
||||||
LT, LE, GT, GE, EQ, NE
|
LT, LE, GT, GE, EQ, NE
|
||||||
} ComparisonOp;
|
} ComparisonOp;
|
||||||
@ -186,10 +182,14 @@ static unsigned int cond_min_depth = 0; /* depth at makefile open */
|
|||||||
/* Names for ComparisonOp. */
|
/* Names for ComparisonOp. */
|
||||||
static const char opname[][3] = { "<", "<=", ">", ">=", "==", "!=" };
|
static const char opname[][3] = { "<", "<=", ">", ">=", "==", "!=" };
|
||||||
|
|
||||||
static bool
|
MAKE_INLINE bool
|
||||||
is_token(const char *str, const char *tok, unsigned char len)
|
skip_string(const char **pp, const char *str)
|
||||||
{
|
{
|
||||||
return strncmp(str, tok, (size_t)len) == 0 && !ch_isalpha(str[len]);
|
size_t len = strlen(str);
|
||||||
|
bool ok = strncmp(*pp, str, len) == 0;
|
||||||
|
if (ok)
|
||||||
|
*pp += len;
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token
|
static Token
|
||||||
@ -208,31 +208,13 @@ CondParser_SkipWhitespace(CondParser *par)
|
|||||||
* Parse a single word, taking into account balanced parentheses as well as
|
* Parse a single word, taking into account balanced parentheses as well as
|
||||||
* embedded expressions. Used for the argument of a built-in function as
|
* embedded expressions. Used for the argument of a built-in function as
|
||||||
* well as for bare words, which are then passed to the default function.
|
* well as for bare words, which are then passed to the default function.
|
||||||
*
|
|
||||||
* Arguments:
|
|
||||||
* *pp initially points at the '(',
|
|
||||||
* upon successful return it points right after the ')'.
|
|
||||||
*
|
|
||||||
* *out_arg receives the argument as string.
|
|
||||||
*
|
|
||||||
* func says whether the argument belongs to an actual function, or
|
|
||||||
* NULL when parsing a bare word.
|
|
||||||
*
|
|
||||||
* Return the length of the argument, or an ambiguous 0 on error.
|
|
||||||
*/
|
*/
|
||||||
static size_t
|
static char *
|
||||||
ParseWord(CondParser *par, const char **pp, bool doEval, const char *func,
|
ParseWord(const char **pp, bool doEval)
|
||||||
char **out_arg)
|
|
||||||
{
|
{
|
||||||
const char *p = *pp;
|
const char *p = *pp;
|
||||||
Buffer argBuf;
|
Buffer argBuf;
|
||||||
int paren_depth;
|
int paren_depth;
|
||||||
size_t argLen;
|
|
||||||
|
|
||||||
if (func != NULL)
|
|
||||||
p++; /* Skip opening '(' - verified by caller */
|
|
||||||
|
|
||||||
cpp_skip_hspace(&p);
|
|
||||||
|
|
||||||
Buf_InitSize(&argBuf, 16);
|
Buf_InitSize(&argBuf, 16);
|
||||||
|
|
||||||
@ -243,7 +225,7 @@ ParseWord(CondParser *par, const char **pp, bool doEval, const char *func,
|
|||||||
break;
|
break;
|
||||||
if ((ch == '&' || ch == '|') && paren_depth == 0)
|
if ((ch == '&' || ch == '|') && paren_depth == 0)
|
||||||
break;
|
break;
|
||||||
if (*p == '$') {
|
if (ch == '$') {
|
||||||
/*
|
/*
|
||||||
* Parse the variable expression and install it as
|
* Parse the variable expression and install it as
|
||||||
* part of the argument if it's valid. We tell
|
* part of the argument if it's valid. We tell
|
||||||
@ -266,58 +248,73 @@ ParseWord(CondParser *par, const char **pp, bool doEval, const char *func,
|
|||||||
paren_depth++;
|
paren_depth++;
|
||||||
else if (ch == ')' && --paren_depth < 0)
|
else if (ch == ')' && --paren_depth < 0)
|
||||||
break;
|
break;
|
||||||
Buf_AddByte(&argBuf, *p);
|
Buf_AddByte(&argBuf, ch);
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
argLen = argBuf.len;
|
cpp_skip_hspace(&p);
|
||||||
*out_arg = Buf_DoneData(&argBuf);
|
*pp = p;
|
||||||
|
|
||||||
|
return Buf_DoneData(&argBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the function argument, including the surrounding parentheses. */
|
||||||
|
static char *
|
||||||
|
ParseFuncArg(CondParser *par, const char **pp, bool doEval, const char *func)
|
||||||
|
{
|
||||||
|
const char *p = *pp;
|
||||||
|
char *res;
|
||||||
|
|
||||||
|
p++; /* Skip opening '(' - verified by caller */
|
||||||
|
cpp_skip_hspace(&p);
|
||||||
|
res = ParseWord(&p, doEval);
|
||||||
cpp_skip_hspace(&p);
|
cpp_skip_hspace(&p);
|
||||||
|
|
||||||
if (func != NULL && *p++ != ')') {
|
if (*p++ != ')') {
|
||||||
|
int len = 0;
|
||||||
|
while (ch_isalpha(func[len]))
|
||||||
|
len++;
|
||||||
|
|
||||||
Parse_Error(PARSE_FATAL,
|
Parse_Error(PARSE_FATAL,
|
||||||
"Missing closing parenthesis for %s()", func);
|
"Missing closing parenthesis for %.*s()", len, func);
|
||||||
par->printedError = true;
|
par->printedError = true;
|
||||||
return 0;
|
free(res);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*pp = p;
|
*pp = p;
|
||||||
return argLen;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test whether the given variable is defined. */
|
/* Test whether the given variable is defined. */
|
||||||
static bool
|
static bool
|
||||||
FuncDefined(const char *arg)
|
FuncDefined(const char *var)
|
||||||
{
|
{
|
||||||
FStr value = Var_Value(SCOPE_CMDLINE, arg);
|
return Var_Exists(SCOPE_CMDLINE, var);
|
||||||
bool result = value.str != NULL;
|
|
||||||
FStr_Done(&value);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if the given target is requested to be made. */
|
/* See if the given target is requested to be made. */
|
||||||
static bool
|
static bool
|
||||||
FuncMake(const char *arg)
|
FuncMake(const char *target)
|
||||||
{
|
{
|
||||||
StringListNode *ln;
|
StringListNode *ln;
|
||||||
|
|
||||||
for (ln = opts.create.first; ln != NULL; ln = ln->next)
|
for (ln = opts.create.first; ln != NULL; ln = ln->next)
|
||||||
if (Str_Match(ln->datum, arg))
|
if (Str_Match(ln->datum, target))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if the given file exists. */
|
/* See if the given file exists. */
|
||||||
static bool
|
static bool
|
||||||
FuncExists(const char *arg)
|
FuncExists(const char *file)
|
||||||
{
|
{
|
||||||
bool result;
|
bool result;
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
path = Dir_FindFile(arg, &dirSearchPath);
|
path = Dir_FindFile(file, &dirSearchPath);
|
||||||
DEBUG2(COND, "exists(%s) result is \"%s\"\n",
|
DEBUG2(COND, "exists(%s) result is \"%s\"\n",
|
||||||
arg, path != NULL ? path : "");
|
file, path != NULL ? path : "");
|
||||||
result = path != NULL;
|
result = path != NULL;
|
||||||
free(path);
|
free(path);
|
||||||
return result;
|
return result;
|
||||||
@ -325,9 +322,9 @@ FuncExists(const char *arg)
|
|||||||
|
|
||||||
/* See if the given node exists and is an actual target. */
|
/* See if the given node exists and is an actual target. */
|
||||||
static bool
|
static bool
|
||||||
FuncTarget(const char *arg)
|
FuncTarget(const char *node)
|
||||||
{
|
{
|
||||||
GNode *gn = Targ_FindNode(arg);
|
GNode *gn = Targ_FindNode(node);
|
||||||
return gn != NULL && GNode_IsTarget(gn);
|
return gn != NULL && GNode_IsTarget(gn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,20 +333,16 @@ FuncTarget(const char *arg)
|
|||||||
* associated with it.
|
* associated with it.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
FuncCommands(const char *arg)
|
FuncCommands(const char *node)
|
||||||
{
|
{
|
||||||
GNode *gn = Targ_FindNode(arg);
|
GNode *gn = Targ_FindNode(node);
|
||||||
return gn != NULL && GNode_IsTarget(gn) && !Lst_IsEmpty(&gn->commands);
|
return gn != NULL && GNode_IsTarget(gn) &&
|
||||||
|
!Lst_IsEmpty(&gn->commands);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert the given number into a double.
|
* Convert the string into a floating-point number. Accepted formats are
|
||||||
* We try a base 10 or 16 integer conversion first, if that fails
|
* base-10 integer, base-16 integer and finite floating point numbers.
|
||||||
* then we try a floating point conversion instead.
|
|
||||||
*
|
|
||||||
* Results:
|
|
||||||
* Returns true if the conversion succeeded.
|
|
||||||
* Sets 'out_value' to the converted number.
|
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
TryParseNumber(const char *str, double *out_value)
|
TryParseNumber(const char *str, double *out_value)
|
||||||
@ -399,7 +392,7 @@ CondParser_StringExpr(CondParser *par, const char *start,
|
|||||||
Buffer *buf, FStr *inout_str)
|
Buffer *buf, FStr *inout_str)
|
||||||
{
|
{
|
||||||
VarEvalMode emode;
|
VarEvalMode emode;
|
||||||
const char *nested_p;
|
const char *p;
|
||||||
bool atStart;
|
bool atStart;
|
||||||
VarParseResult parseResult;
|
VarParseResult parseResult;
|
||||||
|
|
||||||
@ -407,9 +400,9 @@ CondParser_StringExpr(CondParser *par, const char *start,
|
|||||||
: doEval ? VARE_UNDEFERR
|
: doEval ? VARE_UNDEFERR
|
||||||
: VARE_PARSE_ONLY;
|
: VARE_PARSE_ONLY;
|
||||||
|
|
||||||
nested_p = par->p;
|
p = par->p;
|
||||||
atStart = nested_p == start;
|
atStart = p == start;
|
||||||
parseResult = Var_Parse(&nested_p, SCOPE_CMDLINE, emode, inout_str);
|
parseResult = Var_Parse(&p, SCOPE_CMDLINE, emode, inout_str);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
if (inout_str->str == var_Error) {
|
if (inout_str->str == var_Error) {
|
||||||
if (parseResult == VPR_ERR) {
|
if (parseResult == VPR_ERR) {
|
||||||
@ -433,7 +426,7 @@ CondParser_StringExpr(CondParser *par, const char *start,
|
|||||||
*inout_str = FStr_InitRefer(NULL);
|
*inout_str = FStr_InitRefer(NULL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
par->p = nested_p;
|
par->p = p;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the '$' started the string literal (which means no quotes), and
|
* If the '$' started the string literal (which means no quotes), and
|
||||||
@ -445,17 +438,16 @@ CondParser_StringExpr(CondParser *par, const char *start,
|
|||||||
|
|
||||||
Buf_AddStr(buf, inout_str->str);
|
Buf_AddStr(buf, inout_str->str);
|
||||||
FStr_Done(inout_str);
|
FStr_Done(inout_str);
|
||||||
*inout_str = FStr_InitRefer(NULL); /* not finished yet */
|
*inout_str = FStr_InitRefer(NULL); /* not finished yet */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse a string from a variable expression or an optionally quoted
|
* Parse a string from a variable expression or an optionally quoted string,
|
||||||
* string. This is called for the left-hand and right-hand sides of
|
* on the left-hand and right-hand sides of comparisons.
|
||||||
* comparisons.
|
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* Returns the string, absent any quotes, or NULL on error.
|
* Returns the string without any enclosing quotes, or NULL on error.
|
||||||
* Sets out_quoted if the leaf was a quoted string literal.
|
* Sets out_quoted if the leaf was a quoted string literal.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
@ -486,7 +478,7 @@ CondParser_Leaf(CondParser *par, bool doEval, bool unquotedOK,
|
|||||||
case '"':
|
case '"':
|
||||||
par->p++;
|
par->p++;
|
||||||
if (quoted)
|
if (quoted)
|
||||||
goto got_str; /* skip the closing quote */
|
goto return_buf; /* skip the closing quote */
|
||||||
Buf_AddByte(&buf, '"');
|
Buf_AddByte(&buf, '"');
|
||||||
continue;
|
continue;
|
||||||
case ')': /* see is_separator */
|
case ')': /* see is_separator */
|
||||||
@ -497,14 +489,14 @@ CondParser_Leaf(CondParser *par, bool doEval, bool unquotedOK,
|
|||||||
case ' ':
|
case ' ':
|
||||||
case '\t':
|
case '\t':
|
||||||
if (!quoted)
|
if (!quoted)
|
||||||
goto got_str;
|
goto return_buf;
|
||||||
Buf_AddByte(&buf, par->p[0]);
|
Buf_AddByte(&buf, par->p[0]);
|
||||||
par->p++;
|
par->p++;
|
||||||
continue;
|
continue;
|
||||||
case '$':
|
case '$':
|
||||||
if (!CondParser_StringExpr(par,
|
if (!CondParser_StringExpr(par,
|
||||||
start, doEval, quoted, &buf, &str))
|
start, doEval, quoted, &buf, &str))
|
||||||
goto cleanup;
|
goto return_str;
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
if (!unquotedOK && !quoted && *start != '$' &&
|
if (!unquotedOK && !quoted && *start != '$' &&
|
||||||
@ -514,28 +506,21 @@ CondParser_Leaf(CondParser *par, bool doEval, bool unquotedOK,
|
|||||||
* a variable expression or a number.
|
* a variable expression or a number.
|
||||||
*/
|
*/
|
||||||
str = FStr_InitRefer(NULL);
|
str = FStr_InitRefer(NULL);
|
||||||
goto cleanup;
|
goto return_str;
|
||||||
}
|
}
|
||||||
Buf_AddByte(&buf, par->p[0]);
|
Buf_AddByte(&buf, par->p[0]);
|
||||||
par->p++;
|
par->p++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
got_str:
|
return_buf:
|
||||||
str = FStr_InitOwn(buf.data);
|
str = FStr_InitOwn(buf.data);
|
||||||
buf.data = NULL;
|
buf.data = NULL;
|
||||||
cleanup:
|
return_str:
|
||||||
Buf_Done(&buf);
|
Buf_Done(&buf);
|
||||||
*out_str = str;
|
*out_str = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
EvalBare(const CondParser *par, const char *arg)
|
|
||||||
{
|
|
||||||
bool res = par->evalBare(arg);
|
|
||||||
return par->negateEvalBare ? !res : res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Evaluate a "comparison without operator", such as in ".if ${VAR}" or
|
* Evaluate a "comparison without operator", such as in ".if ${VAR}" or
|
||||||
* ".if 0".
|
* ".if 0".
|
||||||
@ -553,9 +538,11 @@ EvalNotEmpty(CondParser *par, const char *value, bool quoted)
|
|||||||
if (TryParseNumber(value, &num))
|
if (TryParseNumber(value, &num))
|
||||||
return num != 0.0;
|
return num != 0.0;
|
||||||
|
|
||||||
/* For .if ${...}, check for non-empty string. This is different from
|
/*
|
||||||
* the evaluation function from that .if variant, which would test
|
* For .if ${...}, check for non-empty string. This is different
|
||||||
* whether a variable of the given name were defined. */
|
* from the evaluation function from that .if variant, which would
|
||||||
|
* test whether a variable of the given name were defined.
|
||||||
|
*/
|
||||||
/*
|
/*
|
||||||
* XXX: Whitespace should count as empty, just as in
|
* XXX: Whitespace should count as empty, just as in
|
||||||
* CondParser_FuncCallEmpty.
|
* CondParser_FuncCallEmpty.
|
||||||
@ -563,7 +550,7 @@ EvalNotEmpty(CondParser *par, const char *value, bool quoted)
|
|||||||
if (par->plain)
|
if (par->plain)
|
||||||
return value[0] != '\0';
|
return value[0] != '\0';
|
||||||
|
|
||||||
return EvalBare(par, value);
|
return par->evalBare(value) != par->negateEvalBare;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Evaluate a numerical comparison, such as in ".if ${VAR} >= 9". */
|
/* Evaluate a numerical comparison, such as in ".if ${VAR} >= 9". */
|
||||||
@ -623,33 +610,19 @@ CondParser_ComparisonOp(CondParser *par, ComparisonOp *out_op)
|
|||||||
{
|
{
|
||||||
const char *p = par->p;
|
const char *p = par->p;
|
||||||
|
|
||||||
if (p[0] == '<' && p[1] == '=') {
|
if (p[0] == '<' && p[1] == '=')
|
||||||
*out_op = LE;
|
return par->p += 2, *out_op = LE, true;
|
||||||
goto length_2;
|
if (p[0] == '<')
|
||||||
} else if (p[0] == '<') {
|
return par->p += 1, *out_op = LT, true;
|
||||||
*out_op = LT;
|
if (p[0] == '>' && p[1] == '=')
|
||||||
goto length_1;
|
return par->p += 2, *out_op = GE, true;
|
||||||
} else if (p[0] == '>' && p[1] == '=') {
|
if (p[0] == '>')
|
||||||
*out_op = GE;
|
return par->p += 1, *out_op = GT, true;
|
||||||
goto length_2;
|
if (p[0] == '=' && p[1] == '=')
|
||||||
} else if (p[0] == '>') {
|
return par->p += 2, *out_op = EQ, true;
|
||||||
*out_op = GT;
|
if (p[0] == '!' && p[1] == '=')
|
||||||
goto length_1;
|
return par->p += 2, *out_op = NE, true;
|
||||||
} else if (p[0] == '=' && p[1] == '=') {
|
|
||||||
*out_op = EQ;
|
|
||||||
goto length_2;
|
|
||||||
} else if (p[0] == '!' && p[1] == '=') {
|
|
||||||
*out_op = NE;
|
|
||||||
goto length_2;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
length_2:
|
|
||||||
par->p = p + 2;
|
|
||||||
return true;
|
|
||||||
length_1:
|
|
||||||
par->p = p + 1;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -718,9 +691,8 @@ CondParser_FuncCallEmpty(CondParser *par, bool doEval, Token *out_token)
|
|||||||
Token tok;
|
Token tok;
|
||||||
FStr val;
|
FStr val;
|
||||||
|
|
||||||
if (!is_token(cp, "empty", 5))
|
if (!skip_string(&cp, "empty"))
|
||||||
return false;
|
return false;
|
||||||
cp += 5;
|
|
||||||
|
|
||||||
cpp_skip_whitespace(&cp);
|
cpp_skip_whitespace(&cp);
|
||||||
if (*cp != '(')
|
if (*cp != '(')
|
||||||
@ -735,7 +707,7 @@ CondParser_FuncCallEmpty(CondParser *par, bool doEval, Token *out_token)
|
|||||||
tok = TOK_ERROR;
|
tok = TOK_ERROR;
|
||||||
else {
|
else {
|
||||||
cpp_skip_whitespace(&val.str);
|
cpp_skip_whitespace(&val.str);
|
||||||
tok = val.str[0] != '\0' && doEval ? TOK_FALSE : TOK_TRUE;
|
tok = ToToken(doEval && val.str[0] == '\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
FStr_Done(&val);
|
FStr_Done(&val);
|
||||||
@ -748,37 +720,34 @@ CondParser_FuncCallEmpty(CondParser *par, bool doEval, Token *out_token)
|
|||||||
static bool
|
static bool
|
||||||
CondParser_FuncCall(CondParser *par, bool doEval, Token *out_token)
|
CondParser_FuncCall(CondParser *par, bool doEval, Token *out_token)
|
||||||
{
|
{
|
||||||
static const struct fn_def {
|
char *arg;
|
||||||
const char fn_name[9];
|
const char *p = par->p;
|
||||||
unsigned char fn_name_len;
|
bool (*fn)(const char *);
|
||||||
bool (*fn_eval)(const char *);
|
const char *fn_name = p;
|
||||||
} fns[] = {
|
|
||||||
{ "defined", 7, FuncDefined },
|
|
||||||
{ "make", 4, FuncMake },
|
|
||||||
{ "exists", 6, FuncExists },
|
|
||||||
{ "target", 6, FuncTarget },
|
|
||||||
{ "commands", 8, FuncCommands }
|
|
||||||
};
|
|
||||||
const struct fn_def *fn;
|
|
||||||
char *arg = NULL;
|
|
||||||
size_t arglen;
|
|
||||||
const char *cp = par->p;
|
|
||||||
const struct fn_def *last_fn = fns + sizeof fns / sizeof fns[0] - 1;
|
|
||||||
|
|
||||||
for (fn = fns; !is_token(cp, fn->fn_name, fn->fn_name_len); fn++)
|
if (skip_string(&p, "defined"))
|
||||||
if (fn == last_fn)
|
fn = FuncDefined;
|
||||||
return false;
|
else if (skip_string(&p, "make"))
|
||||||
|
fn = FuncMake;
|
||||||
cp += fn->fn_name_len;
|
else if (skip_string(&p, "exists"))
|
||||||
cpp_skip_whitespace(&cp);
|
fn = FuncExists;
|
||||||
if (*cp != '(')
|
else if (skip_string(&p, "target"))
|
||||||
|
fn = FuncTarget;
|
||||||
|
else if (skip_string(&p, "commands"))
|
||||||
|
fn = FuncCommands;
|
||||||
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
arglen = ParseWord(par, &cp, doEval, fn->fn_name, &arg);
|
cpp_skip_whitespace(&p);
|
||||||
*out_token = ToToken(arglen != 0 && (!doEval || fn->fn_eval(arg)));
|
if (*p != '(')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
arg = ParseFuncArg(par, &p, doEval, fn_name);
|
||||||
|
*out_token = ToToken(doEval &&
|
||||||
|
arg != NULL && arg[0] != '\0' && fn(arg));
|
||||||
free(arg);
|
free(arg);
|
||||||
par->p = cp;
|
|
||||||
|
par->p = p;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -793,9 +762,8 @@ static Token
|
|||||||
CondParser_ComparisonOrLeaf(CondParser *par, bool doEval)
|
CondParser_ComparisonOrLeaf(CondParser *par, bool doEval)
|
||||||
{
|
{
|
||||||
Token t;
|
Token t;
|
||||||
char *arg = NULL;
|
char *arg;
|
||||||
const char *cp;
|
const char *cp;
|
||||||
const char *cp1;
|
|
||||||
|
|
||||||
/* Push anything numeric through the compare expression */
|
/* Push anything numeric through the compare expression */
|
||||||
cp = par->p;
|
cp = par->p;
|
||||||
@ -811,13 +779,13 @@ CondParser_ComparisonOrLeaf(CondParser *par, bool doEval)
|
|||||||
* as an expression.
|
* as an expression.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* XXX: Is it possible to have a variable expression evaluated twice
|
* XXX: In edge cases, a variable expression may be evaluated twice,
|
||||||
* at this point?
|
* see cond-token-plain.mk, keyword 'twice'.
|
||||||
*/
|
*/
|
||||||
(void)ParseWord(par, &cp, doEval, NULL, &arg);
|
arg = ParseWord(&cp, doEval);
|
||||||
cp1 = cp;
|
assert(arg[0] != '\0');
|
||||||
cpp_skip_whitespace(&cp1);
|
|
||||||
if (*cp1 == '=' || *cp1 == '!' || *cp1 == '<' || *cp1 == '>')
|
if (*cp == '=' || *cp == '!' || *cp == '<' || *cp == '>')
|
||||||
return CondParser_Comparison(par, doEval);
|
return CondParser_Comparison(par, doEval);
|
||||||
par->p = cp;
|
par->p = cp;
|
||||||
|
|
||||||
@ -827,7 +795,7 @@ CondParser_ComparisonOrLeaf(CondParser *par, bool doEval)
|
|||||||
* after .if must have been taken literally, so the argument cannot
|
* after .if must have been taken literally, so the argument cannot
|
||||||
* be empty - even if it contained a variable expansion.
|
* be empty - even if it contained a variable expansion.
|
||||||
*/
|
*/
|
||||||
t = ToToken(!doEval || EvalBare(par, arg));
|
t = ToToken(doEval && par->evalBare(arg) != par->negateEvalBare);
|
||||||
free(arg);
|
free(arg);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
@ -998,42 +966,32 @@ CondParser_Or(CondParser *par, bool doEval)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CondEvalResult
|
static CondResult
|
||||||
CondParser_Eval(CondParser *par, bool *out_value)
|
CondParser_Eval(CondParser *par)
|
||||||
{
|
{
|
||||||
CondResult res;
|
CondResult res;
|
||||||
|
|
||||||
DEBUG1(COND, "CondParser_Eval: %s\n", par->p);
|
DEBUG1(COND, "CondParser_Eval: %s\n", par->p);
|
||||||
|
|
||||||
res = CondParser_Or(par, true);
|
res = CondParser_Or(par, true);
|
||||||
if (res == CR_ERROR)
|
if (res != CR_ERROR && CondParser_Token(par, false) != TOK_EOF)
|
||||||
return COND_INVALID;
|
return CR_ERROR;
|
||||||
|
|
||||||
if (CondParser_Token(par, false) != TOK_EOF)
|
return res;
|
||||||
return COND_INVALID;
|
|
||||||
|
|
||||||
*out_value = res == CR_TRUE;
|
|
||||||
return COND_PARSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Evaluate the condition, including any side effects from the variable
|
* Evaluate the condition, including any side effects from the variable
|
||||||
* expressions in the condition. The condition consists of &&, ||, !,
|
* expressions in the condition. The condition consists of &&, ||, !,
|
||||||
* function(arg), comparisons and parenthetical groupings thereof.
|
* function(arg), comparisons and parenthetical groupings thereof.
|
||||||
*
|
|
||||||
* Results:
|
|
||||||
* COND_PARSE if the condition was valid grammatically
|
|
||||||
* COND_INVALID if not a valid conditional.
|
|
||||||
*
|
|
||||||
* *out_value is set to the boolean value of the condition
|
|
||||||
*/
|
*/
|
||||||
static CondEvalResult
|
static CondResult
|
||||||
CondEvalExpression(const char *cond, bool *out_value, bool plain,
|
CondEvalExpression(const char *cond, bool plain,
|
||||||
bool (*evalBare)(const char *), bool negate,
|
bool (*evalBare)(const char *), bool negate,
|
||||||
bool eprint, bool leftUnquotedOK)
|
bool eprint, bool leftUnquotedOK)
|
||||||
{
|
{
|
||||||
CondParser par;
|
CondParser par;
|
||||||
CondEvalResult rval;
|
CondResult rval;
|
||||||
|
|
||||||
cpp_skip_hspace(&cond);
|
cpp_skip_hspace(&cond);
|
||||||
|
|
||||||
@ -1045,9 +1003,9 @@ CondEvalExpression(const char *cond, bool *out_value, bool plain,
|
|||||||
par.curr = TOK_NONE;
|
par.curr = TOK_NONE;
|
||||||
par.printedError = false;
|
par.printedError = false;
|
||||||
|
|
||||||
rval = CondParser_Eval(&par, out_value);
|
rval = CondParser_Eval(&par);
|
||||||
|
|
||||||
if (rval == COND_INVALID && eprint && !par.printedError)
|
if (rval == CR_ERROR && eprint && !par.printedError)
|
||||||
Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", cond);
|
Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", cond);
|
||||||
|
|
||||||
return rval;
|
return rval;
|
||||||
@ -1057,10 +1015,10 @@ CondEvalExpression(const char *cond, bool *out_value, bool plain,
|
|||||||
* Evaluate a condition in a :? modifier, such as
|
* Evaluate a condition in a :? modifier, such as
|
||||||
* ${"${VAR}" == value:?yes:no}.
|
* ${"${VAR}" == value:?yes:no}.
|
||||||
*/
|
*/
|
||||||
CondEvalResult
|
CondResult
|
||||||
Cond_EvalCondition(const char *cond, bool *out_value)
|
Cond_EvalCondition(const char *cond)
|
||||||
{
|
{
|
||||||
return CondEvalExpression(cond, out_value, true,
|
return CondEvalExpression(cond, true,
|
||||||
FuncDefined, false, false, true);
|
FuncDefined, false, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1076,36 +1034,33 @@ DetermineKindOfConditional(const char **pp, bool *out_plain,
|
|||||||
bool (**out_evalBare)(const char *),
|
bool (**out_evalBare)(const char *),
|
||||||
bool *out_negate)
|
bool *out_negate)
|
||||||
{
|
{
|
||||||
const char *p = *pp;
|
const char *p = *pp + 2;
|
||||||
|
|
||||||
p += 2;
|
|
||||||
*out_plain = false;
|
*out_plain = false;
|
||||||
*out_evalBare = FuncDefined;
|
*out_evalBare = FuncDefined;
|
||||||
*out_negate = false;
|
*out_negate = skip_string(&p, "n");
|
||||||
if (*p == 'n') {
|
|
||||||
p++;
|
if (skip_string(&p, "def")) { /* .ifdef and .ifndef */
|
||||||
*out_negate = true;
|
} else if (skip_string(&p, "make")) /* .ifmake and .ifnmake */
|
||||||
}
|
|
||||||
if (is_token(p, "def", 3)) { /* .ifdef and .ifndef */
|
|
||||||
p += 3;
|
|
||||||
} else if (is_token(p, "make", 4)) { /* .ifmake and .ifnmake */
|
|
||||||
p += 4;
|
|
||||||
*out_evalBare = FuncMake;
|
*out_evalBare = FuncMake;
|
||||||
} else if (is_token(p, "", 0) && !*out_negate) { /* plain .if */
|
else if (!*out_negate) /* plain .if */
|
||||||
*out_plain = true;
|
*out_plain = true;
|
||||||
} else {
|
else
|
||||||
/*
|
goto unknown_directive;
|
||||||
* TODO: Add error message about unknown directive,
|
if (ch_isalpha(*p))
|
||||||
* since there is no other known directive that starts
|
goto unknown_directive;
|
||||||
* with 'el' or 'if'.
|
|
||||||
*
|
|
||||||
* Example: .elifx 123
|
|
||||||
*/
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*pp = p;
|
*pp = p;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
unknown_directive:
|
||||||
|
/*
|
||||||
|
* TODO: Add error message about unknown directive, since there is no
|
||||||
|
* other known directive that starts with 'el' or 'if'.
|
||||||
|
*
|
||||||
|
* Example: .elifx 123
|
||||||
|
*/
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1129,16 +1084,16 @@ DetermineKindOfConditional(const char **pp, bool *out_plain,
|
|||||||
* parenthetical groupings thereof.
|
* parenthetical groupings thereof.
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* COND_PARSE to continue parsing the lines that follow the
|
* CR_TRUE to continue parsing the lines that follow the
|
||||||
* conditional (when <cond> evaluates to true)
|
* conditional (when <cond> evaluates to true)
|
||||||
* COND_SKIP to skip the lines after the conditional
|
* CR_FALSE to skip the lines after the conditional
|
||||||
* (when <cond> evaluates to false, or when a previous
|
* (when <cond> evaluates to false, or when a previous
|
||||||
* branch has already been taken)
|
* branch has already been taken)
|
||||||
* COND_INVALID if the conditional was not valid, either because of
|
* CR_ERROR if the conditional was not valid, either because of
|
||||||
* a syntax error or because some variable was undefined
|
* a syntax error or because some variable was undefined
|
||||||
* or because the condition could not be evaluated
|
* or because the condition could not be evaluated
|
||||||
*/
|
*/
|
||||||
CondEvalResult
|
CondResult
|
||||||
Cond_EvalLine(const char *line)
|
Cond_EvalLine(const char *line)
|
||||||
{
|
{
|
||||||
typedef enum IfState {
|
typedef enum IfState {
|
||||||
@ -1146,8 +1101,10 @@ Cond_EvalLine(const char *line)
|
|||||||
/* None of the previous <cond> evaluated to true. */
|
/* None of the previous <cond> evaluated to true. */
|
||||||
IFS_INITIAL = 0,
|
IFS_INITIAL = 0,
|
||||||
|
|
||||||
/* The previous <cond> evaluated to true.
|
/*
|
||||||
* The lines following this condition are interpreted. */
|
* The previous <cond> evaluated to true. The lines following
|
||||||
|
* this condition are interpreted.
|
||||||
|
*/
|
||||||
IFS_ACTIVE = 1 << 0,
|
IFS_ACTIVE = 1 << 0,
|
||||||
|
|
||||||
/* The previous directive was an '.else'. */
|
/* The previous directive was an '.else'. */
|
||||||
@ -1165,7 +1122,7 @@ Cond_EvalLine(const char *line)
|
|||||||
bool (*evalBare)(const char *);
|
bool (*evalBare)(const char *);
|
||||||
bool negate;
|
bool negate;
|
||||||
bool isElif;
|
bool isElif;
|
||||||
bool value;
|
CondResult res;
|
||||||
IfState state;
|
IfState state;
|
||||||
const char *p = line;
|
const char *p = line;
|
||||||
|
|
||||||
@ -1186,13 +1143,13 @@ Cond_EvalLine(const char *line)
|
|||||||
|
|
||||||
if (cond_depth == cond_min_depth) {
|
if (cond_depth == cond_min_depth) {
|
||||||
Parse_Error(PARSE_FATAL, "if-less endif");
|
Parse_Error(PARSE_FATAL, "if-less endif");
|
||||||
return COND_PARSE;
|
return CR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return state for previous conditional */
|
/* Return state for previous conditional */
|
||||||
cond_depth--;
|
cond_depth--;
|
||||||
return cond_states[cond_depth] & IFS_ACTIVE
|
return cond_states[cond_depth] & IFS_ACTIVE
|
||||||
? COND_PARSE : COND_SKIP;
|
? CR_TRUE : CR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse the name of the directive, such as 'if', 'elif', 'endif'. */
|
/* Parse the name of the directive, such as 'if', 'elif', 'endif'. */
|
||||||
@ -1203,13 +1160,12 @@ Cond_EvalLine(const char *line)
|
|||||||
* transformation rule like '.err.txt',
|
* transformation rule like '.err.txt',
|
||||||
* therefore no error message here.
|
* therefore no error message here.
|
||||||
*/
|
*/
|
||||||
return COND_INVALID;
|
return CR_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Quite likely this is 'else' or 'elif' */
|
/* Quite likely this is 'else' or 'elif' */
|
||||||
p += 2;
|
p += 2;
|
||||||
if (is_token(p, "se", 2)) { /* It is an 'else'. */
|
if (strncmp(p, "se", 2) == 0 && !ch_isalpha(p[2])) {
|
||||||
|
|
||||||
if (p[2] != '\0')
|
if (p[2] != '\0')
|
||||||
Parse_Error(PARSE_FATAL,
|
Parse_Error(PARSE_FATAL,
|
||||||
"The .else directive "
|
"The .else directive "
|
||||||
@ -1217,7 +1173,7 @@ Cond_EvalLine(const char *line)
|
|||||||
|
|
||||||
if (cond_depth == cond_min_depth) {
|
if (cond_depth == cond_min_depth) {
|
||||||
Parse_Error(PARSE_FATAL, "if-less else");
|
Parse_Error(PARSE_FATAL, "if-less else");
|
||||||
return COND_PARSE;
|
return CR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
state = cond_states[cond_depth];
|
state = cond_states[cond_depth];
|
||||||
@ -1226,12 +1182,12 @@ Cond_EvalLine(const char *line)
|
|||||||
} else {
|
} else {
|
||||||
if (state & IFS_SEEN_ELSE)
|
if (state & IFS_SEEN_ELSE)
|
||||||
Parse_Error(PARSE_WARNING,
|
Parse_Error(PARSE_WARNING,
|
||||||
"extra else");
|
"extra else");
|
||||||
state = IFS_WAS_ACTIVE | IFS_SEEN_ELSE;
|
state = IFS_WAS_ACTIVE | IFS_SEEN_ELSE;
|
||||||
}
|
}
|
||||||
cond_states[cond_depth] = state;
|
cond_states[cond_depth] = state;
|
||||||
|
|
||||||
return state & IFS_ACTIVE ? COND_PARSE : COND_SKIP;
|
return state & IFS_ACTIVE ? CR_TRUE : CR_FALSE;
|
||||||
}
|
}
|
||||||
/* Assume for now it is an elif */
|
/* Assume for now it is an elif */
|
||||||
isElif = true;
|
isElif = true;
|
||||||
@ -1243,27 +1199,27 @@ Cond_EvalLine(const char *line)
|
|||||||
* Unknown directive. It might still be a transformation rule
|
* Unknown directive. It might still be a transformation rule
|
||||||
* like '.elisp.scm', therefore no error message here.
|
* like '.elisp.scm', therefore no error message here.
|
||||||
*/
|
*/
|
||||||
return COND_INVALID; /* Not an ifxxx or elifxxx line */
|
return CR_ERROR; /* Not an ifxxx or elifxxx line */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DetermineKindOfConditional(&p, &plain, &evalBare, &negate))
|
if (!DetermineKindOfConditional(&p, &plain, &evalBare, &negate))
|
||||||
return COND_INVALID;
|
return CR_ERROR;
|
||||||
|
|
||||||
if (isElif) {
|
if (isElif) {
|
||||||
if (cond_depth == cond_min_depth) {
|
if (cond_depth == cond_min_depth) {
|
||||||
Parse_Error(PARSE_FATAL, "if-less elif");
|
Parse_Error(PARSE_FATAL, "if-less elif");
|
||||||
return COND_PARSE;
|
return CR_TRUE;
|
||||||
}
|
}
|
||||||
state = cond_states[cond_depth];
|
state = cond_states[cond_depth];
|
||||||
if (state & IFS_SEEN_ELSE) {
|
if (state & IFS_SEEN_ELSE) {
|
||||||
Parse_Error(PARSE_WARNING, "extra elif");
|
Parse_Error(PARSE_WARNING, "extra elif");
|
||||||
cond_states[cond_depth] =
|
cond_states[cond_depth] =
|
||||||
IFS_WAS_ACTIVE | IFS_SEEN_ELSE;
|
IFS_WAS_ACTIVE | IFS_SEEN_ELSE;
|
||||||
return COND_SKIP;
|
return CR_FALSE;
|
||||||
}
|
}
|
||||||
if (state != IFS_INITIAL) {
|
if (state != IFS_INITIAL) {
|
||||||
cond_states[cond_depth] = IFS_WAS_ACTIVE;
|
cond_states[cond_depth] = IFS_WAS_ACTIVE;
|
||||||
return COND_SKIP;
|
return CR_FALSE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Normal .if */
|
/* Normal .if */
|
||||||
@ -1275,8 +1231,7 @@ Cond_EvalLine(const char *line)
|
|||||||
*/
|
*/
|
||||||
cond_states_cap += 32;
|
cond_states_cap += 32;
|
||||||
cond_states = bmake_realloc(cond_states,
|
cond_states = bmake_realloc(cond_states,
|
||||||
cond_states_cap *
|
cond_states_cap * sizeof *cond_states);
|
||||||
sizeof *cond_states);
|
|
||||||
}
|
}
|
||||||
state = cond_states[cond_depth];
|
state = cond_states[cond_depth];
|
||||||
cond_depth++;
|
cond_depth++;
|
||||||
@ -1286,26 +1241,22 @@ Cond_EvalLine(const char *line)
|
|||||||
* treat as always false.
|
* treat as always false.
|
||||||
*/
|
*/
|
||||||
cond_states[cond_depth] = IFS_WAS_ACTIVE;
|
cond_states[cond_depth] = IFS_WAS_ACTIVE;
|
||||||
return COND_SKIP;
|
return CR_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* And evaluate the conditional expression */
|
/* And evaluate the conditional expression */
|
||||||
if (CondEvalExpression(p, &value, plain, evalBare, negate,
|
res = CondEvalExpression(p, plain, evalBare, negate, true, false);
|
||||||
true, false) == COND_INVALID) {
|
if (res == CR_ERROR) {
|
||||||
/* Syntax error in conditional, error message already output. */
|
/* Syntax error, error message already output. */
|
||||||
/* Skip everything to matching .endif */
|
/* Skip everything to the matching '.endif'. */
|
||||||
/* XXX: An extra '.else' is not detected in this case. */
|
/* An extra '.else' is not detected in this case. */
|
||||||
cond_states[cond_depth] = IFS_WAS_ACTIVE;
|
cond_states[cond_depth] = IFS_WAS_ACTIVE;
|
||||||
return COND_SKIP;
|
return CR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!value) {
|
cond_states[cond_depth] = res == CR_TRUE ? IFS_ACTIVE : IFS_INITIAL;
|
||||||
cond_states[cond_depth] = IFS_INITIAL;
|
return res;
|
||||||
return COND_SKIP;
|
|
||||||
}
|
|
||||||
cond_states[cond_depth] = IFS_ACTIVE;
|
|
||||||
return COND_PARSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1315,7 +1266,7 @@ Cond_restore_depth(unsigned int saved_depth)
|
|||||||
|
|
||||||
if (open_conds != 0 || saved_depth > cond_depth) {
|
if (open_conds != 0 || saved_depth > cond_depth) {
|
||||||
Parse_Error(PARSE_FATAL, "%u open conditional%s",
|
Parse_Error(PARSE_FATAL, "%u open conditional%s",
|
||||||
open_conds, open_conds == 1 ? "" : "s");
|
open_conds, open_conds == 1 ? "" : "s");
|
||||||
cond_depth = cond_min_depth;
|
cond_depth = cond_min_depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: dir.c,v 1.275 2021/11/28 21:46:17 rillig Exp $ */
|
/* $NetBSD: dir.c,v 1.278 2022/02/04 23:22:19 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
@ -138,7 +138,7 @@
|
|||||||
#include "job.h"
|
#include "job.h"
|
||||||
|
|
||||||
/* "@(#)dir.c 8.2 (Berkeley) 1/2/94" */
|
/* "@(#)dir.c 8.2 (Berkeley) 1/2/94" */
|
||||||
MAKE_RCSID("$NetBSD: dir.c,v 1.275 2021/11/28 21:46:17 rillig Exp $");
|
MAKE_RCSID("$NetBSD: dir.c,v 1.278 2022/02/04 23:22:19 rillig Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A search path is a list of CachedDir structures. A CachedDir has in it the
|
* A search path is a list of CachedDir structures. A CachedDir has in it the
|
||||||
@ -672,8 +672,8 @@ DirMatchFiles(const char *pattern, CachedDir *dir, StringList *expansions)
|
|||||||
|
|
||||||
{
|
{
|
||||||
char *fullName = isDot
|
char *fullName = isDot
|
||||||
? bmake_strdup(base)
|
? bmake_strdup(base)
|
||||||
: str_concat3(dirName, "/", base);
|
: str_concat3(dirName, "/", base);
|
||||||
Lst_Append(expansions, fullName);
|
Lst_Append(expansions, fullName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -792,7 +792,7 @@ DirExpandCurly(const char *word, const char *brace, SearchPath *path,
|
|||||||
size_t piece_len = (size_t)(piece_end - piece);
|
size_t piece_len = (size_t)(piece_end - piece);
|
||||||
|
|
||||||
char *file = concat3(prefix, prefix_len, piece, piece_len,
|
char *file = concat3(prefix, prefix_len, piece, piece_len,
|
||||||
suffix, suffix_len);
|
suffix, suffix_len);
|
||||||
|
|
||||||
if (contains_wildcard(file)) {
|
if (contains_wildcard(file)) {
|
||||||
SearchPath_Expand(path, file, expansions);
|
SearchPath_Expand(path, file, expansions);
|
||||||
@ -984,8 +984,9 @@ static char *
|
|||||||
DirLookupSubdir(CachedDir *dir, const char *name)
|
DirLookupSubdir(CachedDir *dir, const char *name)
|
||||||
{
|
{
|
||||||
struct cached_stat cst;
|
struct cached_stat cst;
|
||||||
char *file = dir == dot ? bmake_strdup(name)
|
char *file = dir == dot
|
||||||
: str_concat3(dir->name, "/", name);
|
? bmake_strdup(name)
|
||||||
|
: str_concat3(dir->name, "/", name);
|
||||||
|
|
||||||
DEBUG1(DIR, "checking %s ...\n", file);
|
DEBUG1(DIR, "checking %s ...\n", file);
|
||||||
|
|
||||||
@ -1424,9 +1425,9 @@ ResolveMovedDepends(GNode *gn)
|
|||||||
gn->path = bmake_strdup(fullName);
|
gn->path = bmake_strdup(fullName);
|
||||||
if (!Job_RunTarget(".STALE", gn->fname))
|
if (!Job_RunTarget(".STALE", gn->fname))
|
||||||
fprintf(stdout, /* XXX: Why stdout? */
|
fprintf(stdout, /* XXX: Why stdout? */
|
||||||
"%s: %s, %d: ignoring stale %s for %s, found %s\n",
|
"%s: %s, %u: ignoring stale %s for %s, found %s\n",
|
||||||
progname, gn->fname, gn->lineno,
|
progname, gn->fname, gn->lineno,
|
||||||
makeDependfile, gn->name, fullName);
|
makeDependfile, gn->name, fullName);
|
||||||
|
|
||||||
return fullName;
|
return fullName;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: dir.h,v 1.44 2021/04/03 11:08:40 rillig Exp $ */
|
/* $NetBSD: dir.h,v 1.46 2021/12/15 12:08:25 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
@ -82,18 +82,18 @@ void Dir_InitCur(const char *);
|
|||||||
void Dir_InitDot(void);
|
void Dir_InitDot(void);
|
||||||
void Dir_End(void);
|
void Dir_End(void);
|
||||||
void Dir_SetPATH(void);
|
void Dir_SetPATH(void);
|
||||||
bool Dir_HasWildcards(const char *);
|
bool Dir_HasWildcards(const char *) MAKE_ATTR_USE;
|
||||||
void SearchPath_Expand(SearchPath *, const char *, StringList *);
|
void SearchPath_Expand(SearchPath *, const char *, StringList *);
|
||||||
char *Dir_FindFile(const char *, SearchPath *);
|
char *Dir_FindFile(const char *, SearchPath *) MAKE_ATTR_USE;
|
||||||
char *Dir_FindHereOrAbove(const char *, const char *);
|
char *Dir_FindHereOrAbove(const char *, const char *) MAKE_ATTR_USE;
|
||||||
void Dir_UpdateMTime(GNode *, bool);
|
void Dir_UpdateMTime(GNode *, bool);
|
||||||
CachedDir *SearchPath_Add(SearchPath *, const char *);
|
CachedDir *SearchPath_Add(SearchPath *, const char *);
|
||||||
char *SearchPath_ToFlags(SearchPath *, const char *);
|
char *SearchPath_ToFlags(SearchPath *, const char *) MAKE_ATTR_USE;
|
||||||
void SearchPath_Clear(SearchPath *);
|
void SearchPath_Clear(SearchPath *);
|
||||||
void SearchPath_AddAll(SearchPath *, SearchPath *);
|
void SearchPath_AddAll(SearchPath *, SearchPath *);
|
||||||
void Dir_PrintDirectories(void);
|
void Dir_PrintDirectories(void);
|
||||||
void SearchPath_Print(const SearchPath *);
|
void SearchPath_Print(const SearchPath *);
|
||||||
SearchPath *Dir_CopyDirSearchPath(void);
|
SearchPath *Dir_CopyDirSearchPath(void) MAKE_ATTR_USE;
|
||||||
|
|
||||||
/* Stripped-down variant of struct stat. */
|
/* Stripped-down variant of struct stat. */
|
||||||
struct cached_stat {
|
struct cached_stat {
|
||||||
@ -104,4 +104,4 @@ struct cached_stat {
|
|||||||
int cached_lstat(const char *, struct cached_stat *);
|
int cached_lstat(const char *, struct cached_stat *);
|
||||||
int cached_stat(const char *, struct cached_stat *);
|
int cached_stat(const char *, struct cached_stat *);
|
||||||
|
|
||||||
#endif /* MAKE_DIR_H */
|
#endif
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: filemon.h,v 1.5 2021/01/19 20:51:46 rillig Exp $ */
|
/* $NetBSD: filemon.h,v 1.6 2021/12/15 12:08:25 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 The NetBSD Foundation, Inc.
|
* Copyright (c) 2019 The NetBSD Foundation, Inc.
|
||||||
@ -50,4 +50,4 @@ int filemon_setpid_child(const struct filemon *, pid_t);
|
|||||||
int filemon_readfd(const struct filemon *);
|
int filemon_readfd(const struct filemon *);
|
||||||
int filemon_process(struct filemon *);
|
int filemon_process(struct filemon *);
|
||||||
|
|
||||||
#endif /* MAKE_FILEMON_H */
|
#endif
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: for.c,v 1.150 2021/12/12 15:44:41 rillig Exp $ */
|
/* $NetBSD: for.c,v 1.167 2022/02/04 23:22:19 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1992, The Regents of the University of California.
|
* Copyright (c) 1992, The Regents of the University of California.
|
||||||
@ -58,26 +58,18 @@
|
|||||||
#include "make.h"
|
#include "make.h"
|
||||||
|
|
||||||
/* "@(#)for.c 8.1 (Berkeley) 6/6/93" */
|
/* "@(#)for.c 8.1 (Berkeley) 6/6/93" */
|
||||||
MAKE_RCSID("$NetBSD: for.c,v 1.150 2021/12/12 15:44:41 rillig Exp $");
|
MAKE_RCSID("$NetBSD: for.c,v 1.167 2022/02/04 23:22:19 rillig Exp $");
|
||||||
|
|
||||||
|
|
||||||
/* One of the variables to the left of the "in" in a .for loop. */
|
|
||||||
typedef struct ForVar {
|
|
||||||
char *name;
|
|
||||||
size_t nameLen;
|
|
||||||
} ForVar;
|
|
||||||
|
|
||||||
typedef struct ForLoop {
|
typedef struct ForLoop {
|
||||||
Buffer body; /* Unexpanded body of the loop */
|
Vector /* of 'char *' */ vars; /* Iteration variables */
|
||||||
Vector /* of ForVar */ vars; /* Iteration variables */
|
|
||||||
SubstringWords items; /* Substitution items */
|
SubstringWords items; /* Substitution items */
|
||||||
Buffer curBody; /* Expanded body of the current iteration */
|
Buffer body; /* Unexpanded body of the loop */
|
||||||
unsigned int nextItem; /* Where to continue iterating */
|
unsigned int nextItem; /* Where to continue iterating */
|
||||||
} ForLoop;
|
} ForLoop;
|
||||||
|
|
||||||
|
|
||||||
static ForLoop *accumFor; /* Loop being accumulated */
|
static ForLoop *accumFor; /* Loop being accumulated */
|
||||||
static int forLevel = 0; /* Nesting level */
|
|
||||||
|
|
||||||
|
|
||||||
static ForLoop *
|
static ForLoop *
|
||||||
@ -85,38 +77,49 @@ ForLoop_New(void)
|
|||||||
{
|
{
|
||||||
ForLoop *f = bmake_malloc(sizeof *f);
|
ForLoop *f = bmake_malloc(sizeof *f);
|
||||||
|
|
||||||
Buf_Init(&f->body);
|
Vector_Init(&f->vars, sizeof(char *));
|
||||||
Vector_Init(&f->vars, sizeof(ForVar));
|
|
||||||
SubstringWords_Init(&f->items);
|
SubstringWords_Init(&f->items);
|
||||||
Buf_Init(&f->curBody);
|
Buf_Init(&f->body);
|
||||||
f->nextItem = 0;
|
f->nextItem = 0;
|
||||||
|
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
ForLoop_Free(ForLoop *f)
|
ForLoop_Free(ForLoop *f)
|
||||||
{
|
{
|
||||||
Buf_Done(&f->body);
|
while (f->vars.len > 0)
|
||||||
|
free(*(char **)Vector_Pop(&f->vars));
|
||||||
while (f->vars.len > 0) {
|
|
||||||
ForVar *var = Vector_Pop(&f->vars);
|
|
||||||
free(var->name);
|
|
||||||
}
|
|
||||||
Vector_Done(&f->vars);
|
Vector_Done(&f->vars);
|
||||||
|
|
||||||
SubstringWords_Free(f->items);
|
SubstringWords_Free(f->items);
|
||||||
Buf_Done(&f->curBody);
|
Buf_Done(&f->body);
|
||||||
|
|
||||||
free(f);
|
free(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
char *
|
||||||
ForLoop_AddVar(ForLoop *f, const char *name, size_t len)
|
ForLoop_Details(ForLoop *f)
|
||||||
{
|
{
|
||||||
ForVar *var = Vector_Push(&f->vars);
|
size_t i, n;
|
||||||
var->name = bmake_strldup(name, len);
|
const char **vars;
|
||||||
var->nameLen = len;
|
const Substring *items;
|
||||||
|
Buffer buf;
|
||||||
|
|
||||||
|
n = f->vars.len;
|
||||||
|
vars = f->vars.items;
|
||||||
|
assert(f->nextItem >= n);
|
||||||
|
items = f->items.words + f->nextItem - n;
|
||||||
|
|
||||||
|
Buf_Init(&buf);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (i > 0)
|
||||||
|
Buf_AddStr(&buf, ", ");
|
||||||
|
Buf_AddStr(&buf, vars[i]);
|
||||||
|
Buf_AddStr(&buf, " = ");
|
||||||
|
Buf_AddBytesBetween(&buf, items[i].start, items[i].end);
|
||||||
|
}
|
||||||
|
return Buf_DoneData(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -145,7 +148,7 @@ ForLoop_ParseVarnames(ForLoop *f, const char **pp)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ForLoop_AddVar(f, p, len);
|
*(char **)Vector_Push(&f->vars) = bmake_strldup(p, len);
|
||||||
p += len;
|
p += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,9 +177,9 @@ ForLoop_ParseItems(ForLoop *f, const char *p)
|
|||||||
free(items);
|
free(items);
|
||||||
|
|
||||||
if (f->items.len == 1 && Substring_IsEmpty(f->items.words[0]))
|
if (f->items.len == 1 && Substring_IsEmpty(f->items.words[0]))
|
||||||
f->items.len = 0; /* .for var in ${:U} */
|
f->items.len = 0; /* .for var in ${:U} */
|
||||||
|
|
||||||
if (f->items.len != 0 && f->items.len % f->vars.len != 0) {
|
if (f->items.len % f->vars.len != 0) {
|
||||||
Parse_Error(PARSE_FATAL,
|
Parse_Error(PARSE_FATAL,
|
||||||
"Wrong number of words (%u) in .for "
|
"Wrong number of words (%u) in .for "
|
||||||
"substitution list with %u variables",
|
"substitution list with %u variables",
|
||||||
@ -204,47 +207,38 @@ IsEndfor(const char *p)
|
|||||||
* Evaluate the for loop in the passed line. The line looks like this:
|
* Evaluate the for loop in the passed line. The line looks like this:
|
||||||
* .for <varname...> in <value...>
|
* .for <varname...> in <value...>
|
||||||
*
|
*
|
||||||
* Input:
|
|
||||||
* line Line to parse
|
|
||||||
*
|
|
||||||
* Results:
|
* Results:
|
||||||
* 0: Not a .for statement, parse the line
|
* 0 not a .for directive
|
||||||
* 1: We found a for loop
|
* 1 found a .for directive
|
||||||
* -1: A .for statement with a bad syntax error, discard.
|
* -1 erroneous .for directive
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
For_Eval(const char *line)
|
For_Eval(const char *line)
|
||||||
{
|
{
|
||||||
ForLoop *f;
|
|
||||||
const char *p;
|
const char *p;
|
||||||
|
ForLoop *f;
|
||||||
|
|
||||||
p = line + 1; /* skip the '.' */
|
p = line + 1; /* skip the '.' */
|
||||||
cpp_skip_whitespace(&p);
|
cpp_skip_whitespace(&p);
|
||||||
|
|
||||||
if (!IsFor(p)) {
|
if (IsFor(p)) {
|
||||||
if (IsEndfor(p)) {
|
p += 3;
|
||||||
Parse_Error(PARSE_FATAL, "for-less endfor");
|
|
||||||
|
f = ForLoop_New();
|
||||||
|
if (!ForLoop_ParseVarnames(f, &p)) {
|
||||||
|
ForLoop_Free(f);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
if (!ForLoop_ParseItems(f, p))
|
||||||
}
|
f->items.len = 0; /* don't iterate */
|
||||||
p += 3;
|
|
||||||
|
|
||||||
f = ForLoop_New();
|
accumFor = f;
|
||||||
|
return 1;
|
||||||
if (!ForLoop_ParseVarnames(f, &p)) {
|
} else if (IsEndfor(p)) {
|
||||||
ForLoop_Free(f);
|
Parse_Error(PARSE_FATAL, "for-less endfor");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else
|
||||||
|
return 0;
|
||||||
if (!ForLoop_ParseItems(f, p)) {
|
|
||||||
/* Continue parsing the .for loop, but don't iterate. */
|
|
||||||
f->items.len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
accumFor = f;
|
|
||||||
forLevel = 1;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -252,7 +246,7 @@ For_Eval(const char *line)
|
|||||||
* Returns false when the matching .endfor is reached.
|
* Returns false when the matching .endfor is reached.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
For_Accum(const char *line)
|
For_Accum(const char *line, int *forLevel)
|
||||||
{
|
{
|
||||||
const char *p = line;
|
const char *p = line;
|
||||||
|
|
||||||
@ -261,12 +255,12 @@ For_Accum(const char *line)
|
|||||||
cpp_skip_whitespace(&p);
|
cpp_skip_whitespace(&p);
|
||||||
|
|
||||||
if (IsEndfor(p)) {
|
if (IsEndfor(p)) {
|
||||||
DEBUG1(FOR, "For: end for %d\n", forLevel);
|
DEBUG1(FOR, "For: end for %d\n", *forLevel);
|
||||||
if (--forLevel <= 0)
|
if (--*forLevel == 0)
|
||||||
return false;
|
return false;
|
||||||
} else if (IsFor(p)) {
|
} else if (IsFor(p)) {
|
||||||
forLevel++;
|
(*forLevel)++;
|
||||||
DEBUG1(FOR, "For: new loop %d\n", forLevel);
|
DEBUG1(FOR, "For: new loop %d\n", *forLevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,12 +319,11 @@ NeedsEscapes(Substring value, char endc)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* While expanding the body of a .for loop, write the item in the ${:U...}
|
* While expanding the body of a .for loop, write the item in the ${:U...}
|
||||||
* expression, escaping characters as needed.
|
* expression, escaping characters as needed. The result is later unescaped
|
||||||
*
|
* by ApplyModifier_Defined.
|
||||||
* The result is later unescaped by ApplyModifier_Defined.
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
Buf_AddEscaped(Buffer *cmds, Substring item, char endc)
|
AddEscaped(Buffer *cmds, Substring item, char endc)
|
||||||
{
|
{
|
||||||
const char *p;
|
const char *p;
|
||||||
char ch;
|
char ch;
|
||||||
@ -340,9 +333,7 @@ Buf_AddEscaped(Buffer *cmds, Substring item, char endc)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Escape ':', '$', '\\' and 'endc' - these will be removed later by
|
for (p = item.start; p != item.end;) {
|
||||||
* :U processing, see ApplyModifier_Defined. */
|
|
||||||
for (p = item.start; p != item.end; p++) {
|
|
||||||
ch = *p;
|
ch = *p;
|
||||||
if (ch == '$') {
|
if (ch == '$') {
|
||||||
size_t len = ExprLen(p + 1, item.end);
|
size_t len = ExprLen(p + 1, item.end);
|
||||||
@ -352,7 +343,7 @@ Buf_AddEscaped(Buffer *cmds, Substring item, char endc)
|
|||||||
* See directive-for-escape.mk, ExprLen.
|
* See directive-for-escape.mk, ExprLen.
|
||||||
*/
|
*/
|
||||||
Buf_AddBytes(cmds, p, 1 + len);
|
Buf_AddBytes(cmds, p, 1 + len);
|
||||||
p += len;
|
p += 1 + len;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Buf_AddByte(cmds, '\\');
|
Buf_AddByte(cmds, '\\');
|
||||||
@ -363,6 +354,7 @@ Buf_AddEscaped(Buffer *cmds, Substring item, char endc)
|
|||||||
ch = ' '; /* prevent newline injection */
|
ch = ' '; /* prevent newline injection */
|
||||||
}
|
}
|
||||||
Buf_AddByte(cmds, ch);
|
Buf_AddByte(cmds, ch);
|
||||||
|
p++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,36 +363,30 @@ Buf_AddEscaped(Buffer *cmds, Substring item, char endc)
|
|||||||
* expression like ${i} or ${i:...} or $(i) or $(i:...) with ":Uvalue".
|
* expression like ${i} or ${i:...} or $(i) or $(i:...) with ":Uvalue".
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ForLoop_SubstVarLong(ForLoop *f, const char **pp, const char *bodyEnd,
|
ForLoop_SubstVarLong(ForLoop *f, unsigned int firstItem, Buffer *body,
|
||||||
char endc, const char **inout_mark)
|
const char **pp, char endc, const char **inout_mark)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
const char *p = *pp;
|
const char *start = *pp;
|
||||||
|
const char **vars = Vector_Get(&f->vars, 0);
|
||||||
|
|
||||||
for (i = 0; i < f->vars.len; i++) {
|
for (i = 0; i < f->vars.len; i++) {
|
||||||
const ForVar *forVar = Vector_Get(&f->vars, i);
|
const char *p = start;
|
||||||
const char *varname = forVar->name;
|
|
||||||
size_t varnameLen = forVar->nameLen;
|
|
||||||
|
|
||||||
if (varnameLen >= (size_t)(bodyEnd - p))
|
if (!cpp_skip_string(&p, vars[i]))
|
||||||
continue;
|
|
||||||
if (memcmp(p, varname, varnameLen) != 0)
|
|
||||||
continue;
|
continue;
|
||||||
/* XXX: why test for backslash here? */
|
/* XXX: why test for backslash here? */
|
||||||
if (p[varnameLen] != ':' && p[varnameLen] != endc &&
|
if (*p != ':' && *p != endc && *p != '\\')
|
||||||
p[varnameLen] != '\\')
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Found a variable match. Skip over the variable name and
|
* Found a variable match. Skip over the variable name and
|
||||||
* instead add ':U<value>' to the current body.
|
* instead add ':U<value>' to the current body.
|
||||||
*/
|
*/
|
||||||
Buf_AddBytesBetween(&f->curBody, *inout_mark, p);
|
Buf_AddBytesBetween(body, *inout_mark, start);
|
||||||
Buf_AddStr(&f->curBody, ":U");
|
Buf_AddStr(body, ":U");
|
||||||
Buf_AddEscaped(&f->curBody,
|
AddEscaped(body, f->items.words[firstItem + i], endc);
|
||||||
f->items.words[f->nextItem + i], endc);
|
|
||||||
|
|
||||||
p += varnameLen;
|
|
||||||
*inout_mark = p;
|
*inout_mark = p;
|
||||||
*pp = p;
|
*pp = p;
|
||||||
return;
|
return;
|
||||||
@ -412,10 +398,11 @@ ForLoop_SubstVarLong(ForLoop *f, const char **pp, const char *bodyEnd,
|
|||||||
* variable expressions like $i with their ${:U...} expansion.
|
* variable expressions like $i with their ${:U...} expansion.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ForLoop_SubstVarShort(ForLoop *f, const char *p, const char **inout_mark)
|
ForLoop_SubstVarShort(ForLoop *f, unsigned int firstItem, Buffer *body,
|
||||||
|
const char *p, const char **inout_mark)
|
||||||
{
|
{
|
||||||
const char ch = *p;
|
const char ch = *p;
|
||||||
const ForVar *vars;
|
const char **vars;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
/* Skip $$ and stupid ones. */
|
/* Skip $$ and stupid ones. */
|
||||||
@ -424,20 +411,20 @@ ForLoop_SubstVarShort(ForLoop *f, const char *p, const char **inout_mark)
|
|||||||
|
|
||||||
vars = Vector_Get(&f->vars, 0);
|
vars = Vector_Get(&f->vars, 0);
|
||||||
for (i = 0; i < f->vars.len; i++) {
|
for (i = 0; i < f->vars.len; i++) {
|
||||||
const char *varname = vars[i].name;
|
const char *varname = vars[i];
|
||||||
if (varname[0] == ch && varname[1] == '\0')
|
if (varname[0] == ch && varname[1] == '\0')
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
found:
|
found:
|
||||||
Buf_AddBytesBetween(&f->curBody, *inout_mark, p);
|
Buf_AddBytesBetween(body, *inout_mark, p);
|
||||||
*inout_mark = p + 1;
|
*inout_mark = p + 1;
|
||||||
|
|
||||||
/* Replace $<ch> with ${:U<value>} */
|
/* Replace $<ch> with ${:U<value>} */
|
||||||
Buf_AddStr(&f->curBody, "{:U");
|
Buf_AddStr(body, "{:U");
|
||||||
Buf_AddEscaped(&f->curBody, f->items.words[f->nextItem + i], '}');
|
AddEscaped(body, f->items.words[firstItem + i], '}');
|
||||||
Buf_AddByte(&f->curBody, '}');
|
Buf_AddByte(body, '}');
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -454,68 +441,59 @@ found:
|
|||||||
* possible to contrive a makefile where an unwanted substitution happens.
|
* possible to contrive a makefile where an unwanted substitution happens.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ForLoop_SubstBody(ForLoop *f)
|
ForLoop_SubstBody(ForLoop *f, unsigned int firstItem, Buffer *body)
|
||||||
{
|
{
|
||||||
const char *p, *bodyEnd;
|
const char *p, *end;
|
||||||
const char *mark; /* where the last substitution left off */
|
const char *mark; /* where the last substitution left off */
|
||||||
|
|
||||||
Buf_Empty(&f->curBody);
|
Buf_Clear(body);
|
||||||
|
|
||||||
mark = f->body.data;
|
mark = f->body.data;
|
||||||
bodyEnd = f->body.data + f->body.len;
|
end = f->body.data + f->body.len;
|
||||||
for (p = mark; (p = strchr(p, '$')) != NULL;) {
|
for (p = mark; (p = strchr(p, '$')) != NULL;) {
|
||||||
if (p[1] == '{' || p[1] == '(') {
|
if (p[1] == '{' || p[1] == '(') {
|
||||||
char endc = p[1] == '{' ? '}' : ')';
|
char endc = p[1] == '{' ? '}' : ')';
|
||||||
p += 2;
|
p += 2;
|
||||||
ForLoop_SubstVarLong(f, &p, bodyEnd, endc, &mark);
|
ForLoop_SubstVarLong(f, firstItem, body,
|
||||||
|
&p, endc, &mark);
|
||||||
} else if (p[1] != '\0') {
|
} else if (p[1] != '\0') {
|
||||||
ForLoop_SubstVarShort(f, p + 1, &mark);
|
ForLoop_SubstVarShort(f, firstItem, body,
|
||||||
|
p + 1, &mark);
|
||||||
p += 2;
|
p += 2;
|
||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buf_AddBytesBetween(&f->curBody, mark, bodyEnd);
|
Buf_AddBytesBetween(body, mark, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute the body for the current iteration by copying the unexpanded body,
|
* Compute the body for the current iteration by copying the unexpanded body,
|
||||||
* replacing the expressions for the iteration variables on the way.
|
* replacing the expressions for the iteration variables on the way.
|
||||||
*/
|
*/
|
||||||
static char *
|
bool
|
||||||
ForReadMore(void *v_arg, size_t *out_len)
|
For_NextIteration(ForLoop *f, Buffer *body)
|
||||||
{
|
{
|
||||||
ForLoop *f = v_arg;
|
if (f->nextItem == f->items.len)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (f->nextItem == f->items.len) {
|
|
||||||
/* No more iterations */
|
|
||||||
ForLoop_Free(f);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ForLoop_SubstBody(f);
|
|
||||||
DEBUG1(FOR, "For: loop body:\n%s", f->curBody.data);
|
|
||||||
f->nextItem += (unsigned int)f->vars.len;
|
f->nextItem += (unsigned int)f->vars.len;
|
||||||
|
ForLoop_SubstBody(f, f->nextItem - (unsigned int)f->vars.len, body);
|
||||||
*out_len = f->curBody.len;
|
DEBUG1(FOR, "For: loop body:\n%s", body->data);
|
||||||
return f->curBody.data;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Run the .for loop, imitating the actions of an include file. */
|
/* Run the .for loop, imitating the actions of an include file. */
|
||||||
void
|
void
|
||||||
For_Run(int lineno)
|
For_Run(unsigned headLineno, unsigned bodyReadLines)
|
||||||
{
|
{
|
||||||
|
Buffer buf;
|
||||||
ForLoop *f = accumFor;
|
ForLoop *f = accumFor;
|
||||||
accumFor = NULL;
|
accumFor = NULL;
|
||||||
|
|
||||||
if (f->items.len == 0) {
|
if (f->items.len > 0) {
|
||||||
/*
|
Buf_Init(&buf);
|
||||||
* Nothing to expand - possibly due to an earlier syntax
|
Parse_PushInput(NULL, headLineno, bodyReadLines, buf, f);
|
||||||
* error.
|
} else
|
||||||
*/
|
|
||||||
ForLoop_Free(f);
|
ForLoop_Free(f);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Parse_PushInput(NULL, lineno, -1, ForReadMore, f);
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: hash.c,v 1.66 2021/12/07 21:58:01 rillig Exp $ */
|
/* $NetBSD: hash.c,v 1.71 2022/01/27 11:00:07 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
@ -74,7 +74,7 @@
|
|||||||
#include "make.h"
|
#include "make.h"
|
||||||
|
|
||||||
/* "@(#)hash.c 8.1 (Berkeley) 6/6/93" */
|
/* "@(#)hash.c 8.1 (Berkeley) 6/6/93" */
|
||||||
MAKE_RCSID("$NetBSD: hash.c,v 1.66 2021/12/07 21:58:01 rillig Exp $");
|
MAKE_RCSID("$NetBSD: hash.c,v 1.71 2022/01/27 11:00:07 rillig Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The ratio of # entries to # buckets at which we rebuild the table to
|
* The ratio of # entries to # buckets at which we rebuild the table to
|
||||||
@ -84,7 +84,7 @@ MAKE_RCSID("$NetBSD: hash.c,v 1.66 2021/12/07 21:58:01 rillig Exp $");
|
|||||||
|
|
||||||
/* This hash function matches Gosling's Emacs and java.lang.String. */
|
/* This hash function matches Gosling's Emacs and java.lang.String. */
|
||||||
static unsigned int
|
static unsigned int
|
||||||
Hash_String(const char *key, size_t *out_keylen)
|
Hash_String(const char *key, const char **out_keyEnd)
|
||||||
{
|
{
|
||||||
unsigned int h;
|
unsigned int h;
|
||||||
const char *p;
|
const char *p;
|
||||||
@ -93,8 +93,7 @@ Hash_String(const char *key, size_t *out_keylen)
|
|||||||
for (p = key; *p != '\0'; p++)
|
for (p = key; *p != '\0'; p++)
|
||||||
h = 31 * h + (unsigned char)*p;
|
h = 31 * h + (unsigned char)*p;
|
||||||
|
|
||||||
if (out_keylen != NULL)
|
*out_keyEnd = p;
|
||||||
*out_keylen = (size_t)(p - key);
|
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,53 +111,22 @@ Hash_Substring(Substring key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static HashEntry *
|
static HashEntry *
|
||||||
HashTable_Find(HashTable *t, unsigned int h, const char *key)
|
HashTable_Find(HashTable *t, Substring key, unsigned int h)
|
||||||
{
|
{
|
||||||
HashEntry *e;
|
HashEntry *e;
|
||||||
unsigned int chainlen = 0;
|
unsigned int chainlen = 0;
|
||||||
|
size_t keyLen = Substring_Length(key);
|
||||||
|
|
||||||
#ifdef DEBUG_HASH_LOOKUP
|
#ifdef DEBUG_HASH_LOOKUP
|
||||||
DEBUG4(HASH, "%s: %p h=%08x key=%s\n", __func__, t, h, key);
|
DEBUG4(HASH, "HashTable_Find: %p h=%08x key=%.*s\n",
|
||||||
|
t, h, (int)keyLen, key.start);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (e = t->buckets[h & t->bucketsMask]; e != NULL; e = e->next) {
|
for (e = t->buckets[h & t->bucketsMask]; e != NULL; e = e->next) {
|
||||||
chainlen++;
|
chainlen++;
|
||||||
if (e->key_hash == h && strcmp(e->key, key) == 0)
|
if (e->key_hash == h &&
|
||||||
break;
|
strncmp(e->key, key.start, keyLen) == 0 &&
|
||||||
}
|
e->key[keyLen] == '\0')
|
||||||
|
|
||||||
if (chainlen > t->maxchain)
|
|
||||||
t->maxchain = chainlen;
|
|
||||||
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
HashEntry_KeyEquals(const HashEntry *he, Substring key)
|
|
||||||
{
|
|
||||||
const char *heKey, *p;
|
|
||||||
|
|
||||||
heKey = he->key;
|
|
||||||
for (p = key.start; p != key.end; p++, heKey++)
|
|
||||||
if (*p != *heKey || *heKey == '\0')
|
|
||||||
return false;
|
|
||||||
return *heKey == '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static HashEntry *
|
|
||||||
HashTable_FindEntryBySubstring(HashTable *t, Substring key, unsigned int h)
|
|
||||||
{
|
|
||||||
HashEntry *e;
|
|
||||||
unsigned int chainlen = 0;
|
|
||||||
|
|
||||||
#ifdef DEBUG_HASH_LOOKUP
|
|
||||||
DEBUG5(HASH, "%s: %p h=%08x key=%.*s\n", __func__, t, h,
|
|
||||||
(int)Substring_Length(key), key.start);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (e = t->buckets[h & t->bucketsMask]; e != NULL; e = e->next) {
|
|
||||||
chainlen++;
|
|
||||||
if (e->key_hash == h && HashEntry_KeyEquals(e, key))
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,8 +181,9 @@ HashTable_Done(HashTable *t)
|
|||||||
HashEntry *
|
HashEntry *
|
||||||
HashTable_FindEntry(HashTable *t, const char *key)
|
HashTable_FindEntry(HashTable *t, const char *key)
|
||||||
{
|
{
|
||||||
unsigned int h = Hash_String(key, NULL);
|
const char *keyEnd;
|
||||||
return HashTable_Find(t, h, key);
|
unsigned int h = Hash_String(key, &keyEnd);
|
||||||
|
return HashTable_Find(t, Substring_Init(key, keyEnd), h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the value corresponding to the key, or return NULL. */
|
/* Find the value corresponding to the key, or return NULL. */
|
||||||
@ -232,7 +201,7 @@ HashTable_FindValue(HashTable *t, const char *key)
|
|||||||
void *
|
void *
|
||||||
HashTable_FindValueBySubstringHash(HashTable *t, Substring key, unsigned int h)
|
HashTable_FindValueBySubstringHash(HashTable *t, Substring key, unsigned int h)
|
||||||
{
|
{
|
||||||
HashEntry *he = HashTable_FindEntryBySubstring(t, key, h);
|
HashEntry *he = HashTable_Find(t, key, h);
|
||||||
return he != NULL ? he->value : NULL;
|
return he != NULL ? he->value : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,8 +237,8 @@ HashTable_Enlarge(HashTable *t)
|
|||||||
t->bucketsSize = newSize;
|
t->bucketsSize = newSize;
|
||||||
t->bucketsMask = newMask;
|
t->bucketsMask = newMask;
|
||||||
t->buckets = newBuckets;
|
t->buckets = newBuckets;
|
||||||
DEBUG5(HASH, "%s: %p size=%d entries=%d maxchain=%d\n",
|
DEBUG4(HASH, "HashTable_Enlarge: %p size=%d entries=%d maxchain=%d\n",
|
||||||
__func__, (void *)t, t->bucketsSize, t->numEntries, t->maxchain);
|
(void *)t, t->bucketsSize, t->numEntries, t->maxchain);
|
||||||
t->maxchain = 0;
|
t->maxchain = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,9 +249,9 @@ HashTable_Enlarge(HashTable *t)
|
|||||||
HashEntry *
|
HashEntry *
|
||||||
HashTable_CreateEntry(HashTable *t, const char *key, bool *out_isNew)
|
HashTable_CreateEntry(HashTable *t, const char *key, bool *out_isNew)
|
||||||
{
|
{
|
||||||
size_t keylen;
|
const char *keyEnd;
|
||||||
unsigned int h = Hash_String(key, &keylen);
|
unsigned int h = Hash_String(key, &keyEnd);
|
||||||
HashEntry *he = HashTable_Find(t, h, key);
|
HashEntry *he = HashTable_Find(t, Substring_Init(key, keyEnd), h);
|
||||||
|
|
||||||
if (he != NULL) {
|
if (he != NULL) {
|
||||||
if (out_isNew != NULL)
|
if (out_isNew != NULL)
|
||||||
@ -293,10 +262,10 @@ HashTable_CreateEntry(HashTable *t, const char *key, bool *out_isNew)
|
|||||||
if (t->numEntries >= rebuildLimit * t->bucketsSize)
|
if (t->numEntries >= rebuildLimit * t->bucketsSize)
|
||||||
HashTable_Enlarge(t);
|
HashTable_Enlarge(t);
|
||||||
|
|
||||||
he = bmake_malloc(sizeof *he + keylen);
|
he = bmake_malloc(sizeof *he + (size_t)(keyEnd - key));
|
||||||
he->value = NULL;
|
he->value = NULL;
|
||||||
he->key_hash = h;
|
he->key_hash = h;
|
||||||
memcpy(he->key, key, keylen + 1);
|
memcpy(he->key, key, (size_t)(keyEnd - key) + 1);
|
||||||
|
|
||||||
he->next = t->buckets[h & t->bucketsMask];
|
he->next = t->buckets[h & t->bucketsMask];
|
||||||
t->buckets[h & t->bucketsMask] = he;
|
t->buckets[h & t->bucketsMask] = he;
|
||||||
@ -307,12 +276,11 @@ HashTable_CreateEntry(HashTable *t, const char *key, bool *out_isNew)
|
|||||||
return he;
|
return he;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashEntry *
|
void
|
||||||
HashTable_Set(HashTable *t, const char *key, void *value)
|
HashTable_Set(HashTable *t, const char *key, void *value)
|
||||||
{
|
{
|
||||||
HashEntry *he = HashTable_CreateEntry(t, key, NULL);
|
HashEntry *he = HashTable_CreateEntry(t, key, NULL);
|
||||||
HashEntry_Set(he, value);
|
HashEntry_Set(he, value);
|
||||||
return he;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete the entry from the table and free the associated memory. */
|
/* Delete the entry from the table and free the associated memory. */
|
||||||
@ -361,5 +329,5 @@ void
|
|||||||
HashTable_DebugStats(HashTable *t, const char *name)
|
HashTable_DebugStats(HashTable *t, const char *name)
|
||||||
{
|
{
|
||||||
DEBUG4(HASH, "HashTable %s: size=%u numEntries=%u maxchain=%u\n",
|
DEBUG4(HASH, "HashTable %s: size=%u numEntries=%u maxchain=%u\n",
|
||||||
name, t->bucketsSize, t->numEntries, t->maxchain);
|
name, t->bucketsSize, t->numEntries, t->maxchain);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: hash.h,v 1.41 2021/12/07 21:58:01 rillig Exp $ */
|
/* $NetBSD: hash.h,v 1.46 2022/01/31 22:58:26 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
@ -88,8 +88,8 @@ typedef struct HashEntry {
|
|||||||
|
|
||||||
/* The hash table containing the entries. */
|
/* The hash table containing the entries. */
|
||||||
typedef struct HashTable {
|
typedef struct HashTable {
|
||||||
HashEntry **buckets; /* Pointers to HashEntry, one
|
HashEntry **buckets; /* Pointers to HashEntry, one for each bucket
|
||||||
* for each bucket in the table. */
|
* in the table. */
|
||||||
unsigned int bucketsSize;
|
unsigned int bucketsSize;
|
||||||
unsigned int numEntries; /* Number of entries in the table. */
|
unsigned int numEntries; /* Number of entries in the table. */
|
||||||
unsigned int bucketsMask; /* Used to select the bucket for a hash. */
|
unsigned int bucketsMask; /* Used to select the bucket for a hash. */
|
||||||
@ -108,7 +108,7 @@ typedef struct HashSet {
|
|||||||
HashTable tbl;
|
HashTable tbl;
|
||||||
} HashSet;
|
} HashSet;
|
||||||
|
|
||||||
MAKE_INLINE void *
|
MAKE_INLINE void * MAKE_ATTR_USE
|
||||||
HashEntry_Get(HashEntry *h)
|
HashEntry_Get(HashEntry *h)
|
||||||
{
|
{
|
||||||
return h->value;
|
return h->value;
|
||||||
@ -131,16 +131,16 @@ HashIter_Init(HashIter *hi, HashTable *t)
|
|||||||
|
|
||||||
void HashTable_Init(HashTable *);
|
void HashTable_Init(HashTable *);
|
||||||
void HashTable_Done(HashTable *);
|
void HashTable_Done(HashTable *);
|
||||||
HashEntry *HashTable_FindEntry(HashTable *, const char *);
|
HashEntry *HashTable_FindEntry(HashTable *, const char *) MAKE_ATTR_USE;
|
||||||
void *HashTable_FindValue(HashTable *, const char *);
|
void *HashTable_FindValue(HashTable *, const char *) MAKE_ATTR_USE;
|
||||||
unsigned int Hash_Substring(Substring);
|
unsigned int Hash_Substring(Substring) MAKE_ATTR_USE;
|
||||||
void *HashTable_FindValueBySubstringHash(HashTable *, Substring, unsigned int);
|
void *HashTable_FindValueBySubstringHash(HashTable *, Substring, unsigned int)
|
||||||
|
MAKE_ATTR_USE;
|
||||||
HashEntry *HashTable_CreateEntry(HashTable *, const char *, bool *);
|
HashEntry *HashTable_CreateEntry(HashTable *, const char *, bool *);
|
||||||
HashEntry *HashTable_Set(HashTable *, const char *, void *);
|
void HashTable_Set(HashTable *, const char *, void *);
|
||||||
void HashTable_DeleteEntry(HashTable *, HashEntry *);
|
void HashTable_DeleteEntry(HashTable *, HashEntry *);
|
||||||
void HashTable_DebugStats(HashTable *, const char *);
|
void HashTable_DebugStats(HashTable *, const char *);
|
||||||
|
|
||||||
void HashIter_Init(HashIter *, HashTable *);
|
|
||||||
HashEntry *HashIter_Next(HashIter *);
|
HashEntry *HashIter_Next(HashIter *);
|
||||||
|
|
||||||
MAKE_INLINE void
|
MAKE_INLINE void
|
||||||
@ -164,7 +164,7 @@ HashSet_Add(HashSet *set, const char *key)
|
|||||||
return isNew;
|
return isNew;
|
||||||
}
|
}
|
||||||
|
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
HashSet_Contains(HashSet *set, const char *key)
|
HashSet_Contains(HashSet *set, const char *key)
|
||||||
{
|
{
|
||||||
return HashTable_FindEntry(&set->tbl, key) != NULL;
|
return HashTable_FindEntry(&set->tbl, key) != NULL;
|
||||||
@ -176,4 +176,4 @@ HashIter_InitSet(HashIter *hi, HashSet *set)
|
|||||||
HashIter_Init(hi, &set->tbl);
|
HashIter_Init(hi, &set->tbl);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* MAKE_HASH_H */
|
#endif
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: job.c,v 1.440 2021/11/28 19:51:06 rillig Exp $ */
|
/* $NetBSD: job.c,v 1.451 2022/02/04 23:22:19 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
@ -155,7 +155,7 @@
|
|||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
/* "@(#)job.c 8.2 (Berkeley) 3/19/94" */
|
/* "@(#)job.c 8.2 (Berkeley) 3/19/94" */
|
||||||
MAKE_RCSID("$NetBSD: job.c,v 1.440 2021/11/28 19:51:06 rillig Exp $");
|
MAKE_RCSID("$NetBSD: job.c,v 1.451 2022/02/04 23:22:19 rillig Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A shell defines how the commands are run. All commands for a target are
|
* A shell defines how the commands are run. All commands for a target are
|
||||||
@ -214,13 +214,15 @@ typedef struct Shell {
|
|||||||
const char *errOff; /* command to turn off error checking */
|
const char *errOff; /* command to turn off error checking */
|
||||||
|
|
||||||
const char *echoTmpl; /* template to echo a command */
|
const char *echoTmpl; /* template to echo a command */
|
||||||
const char *runIgnTmpl; /* template to run a command
|
const char *runIgnTmpl; /* template to run a command without error
|
||||||
* without error checking */
|
* checking */
|
||||||
const char *runChkTmpl; /* template to run a command
|
const char *runChkTmpl; /* template to run a command with error
|
||||||
* with error checking */
|
* checking */
|
||||||
|
|
||||||
/* string literal that results in a newline character when it appears
|
/*
|
||||||
* outside of any 'quote' or "quote" characters */
|
* A string literal that results in a newline character when it
|
||||||
|
* occurs outside of any 'quote' or "quote" characters.
|
||||||
|
*/
|
||||||
const char *newline;
|
const char *newline;
|
||||||
char commentChar; /* character used by shell for comment lines */
|
char commentChar; /* character used by shell for comment lines */
|
||||||
|
|
||||||
@ -454,7 +456,7 @@ static void watchfd(Job *);
|
|||||||
static void clearfd(Job *);
|
static void clearfd(Job *);
|
||||||
static bool readyfd(Job *);
|
static bool readyfd(Job *);
|
||||||
|
|
||||||
static char *targPrefix = NULL; /* To identify a job change in the output. */
|
static char *targPrefix = NULL; /* To identify a job change in the output. */
|
||||||
static Job tokenWaitJob; /* token wait pseudo-job */
|
static Job tokenWaitJob; /* token wait pseudo-job */
|
||||||
|
|
||||||
static Job childExitJob; /* child exit pseudo-job */
|
static Job childExitJob; /* child exit pseudo-job */
|
||||||
@ -533,13 +535,13 @@ JobDeleteTarget(GNode *gn)
|
|||||||
return;
|
return;
|
||||||
if (gn->type & OP_PHONY)
|
if (gn->type & OP_PHONY)
|
||||||
return;
|
return;
|
||||||
if (Targ_Precious(gn))
|
if (GNode_IsPrecious(gn))
|
||||||
return;
|
return;
|
||||||
if (opts.noExecute)
|
if (opts.noExecute)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
file = GNode_Path(gn);
|
file = GNode_Path(gn);
|
||||||
if (eunlink(file) != -1)
|
if (unlink_file(file))
|
||||||
Error("*** %s removed", file);
|
Error("*** %s removed", file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -940,7 +942,7 @@ JobWriteCommand(Job *job, ShellWriter *wr, StringListNode *ln, const char *ucmd)
|
|||||||
|
|
||||||
run = GNode_ShouldExecute(job->node);
|
run = GNode_ShouldExecute(job->node);
|
||||||
|
|
||||||
Var_Subst(ucmd, job->node, VARE_WANTRES, &xcmd);
|
(void)Var_Subst(ucmd, job->node, VARE_WANTRES, &xcmd);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
xcmdStart = xcmd;
|
xcmdStart = xcmd;
|
||||||
|
|
||||||
@ -954,7 +956,7 @@ JobWriteCommand(Job *job, ShellWriter *wr, StringListNode *ln, const char *ucmd)
|
|||||||
* We're not actually executing anything...
|
* We're not actually executing anything...
|
||||||
* but this one needs to be - use compat mode just for it.
|
* but this one needs to be - use compat mode just for it.
|
||||||
*/
|
*/
|
||||||
Compat_RunCommand(ucmd, job->node, ln);
|
(void)Compat_RunCommand(ucmd, job->node, ln);
|
||||||
free(xcmdStart);
|
free(xcmdStart);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1135,7 +1137,7 @@ JobFinishDoneExitedError(Job *job, WAIT_T *inout_status)
|
|||||||
else {
|
else {
|
||||||
if (deleteOnError)
|
if (deleteOnError)
|
||||||
JobDeleteTarget(job->node);
|
JobDeleteTarget(job->node);
|
||||||
PrintOnError(job->node, NULL);
|
PrintOnError(job->node, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1295,9 +1297,11 @@ TouchRegular(GNode *gn)
|
|||||||
return; /* XXX: What about propagating the error? */
|
return; /* XXX: What about propagating the error? */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Last resort: update the file's time stamps in the traditional way.
|
/*
|
||||||
|
* Last resort: update the file's time stamps in the traditional way.
|
||||||
* XXX: This doesn't work for empty files, which are sometimes used
|
* XXX: This doesn't work for empty files, which are sometimes used
|
||||||
* as marker files. */
|
* as marker files.
|
||||||
|
*/
|
||||||
if (read(fd, &c, 1) == 1) {
|
if (read(fd, &c, 1) == 1) {
|
||||||
(void)lseek(fd, 0, SEEK_SET);
|
(void)lseek(fd, 0, SEEK_SET);
|
||||||
while (write(fd, &c, 1) == -1 && errno == EAGAIN)
|
while (write(fd, &c, 1) == -1 && errno == EAGAIN)
|
||||||
@ -1399,7 +1403,7 @@ Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...))
|
|||||||
if (gn->flags.fromDepend) {
|
if (gn->flags.fromDepend) {
|
||||||
if (!Job_RunTarget(".STALE", gn->fname))
|
if (!Job_RunTarget(".STALE", gn->fname))
|
||||||
fprintf(stdout,
|
fprintf(stdout,
|
||||||
"%s: %s, %d: ignoring stale %s for %s\n",
|
"%s: %s, %u: ignoring stale %s for %s\n",
|
||||||
progname, gn->fname, gn->lineno, makeDependfile,
|
progname, gn->fname, gn->lineno, makeDependfile,
|
||||||
gn->name);
|
gn->name);
|
||||||
return true;
|
return true;
|
||||||
@ -1471,9 +1475,8 @@ JobExec(Job *job, char **argv)
|
|||||||
sigset_t tmask;
|
sigset_t tmask;
|
||||||
|
|
||||||
#ifdef USE_META
|
#ifdef USE_META
|
||||||
if (useMeta) {
|
if (useMeta)
|
||||||
meta_job_child(job);
|
meta_job_child(job);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
* Reset all signal handlers; this is necessary because we
|
* Reset all signal handlers; this is necessary because we
|
||||||
@ -1556,9 +1559,8 @@ JobExec(Job *job, char **argv)
|
|||||||
Trace_Log(JOBSTART, job);
|
Trace_Log(JOBSTART, job);
|
||||||
|
|
||||||
#ifdef USE_META
|
#ifdef USE_META
|
||||||
if (useMeta) {
|
if (useMeta)
|
||||||
meta_job_parent(job, cpid);
|
meta_job_parent(job, cpid);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1652,7 +1654,7 @@ JobWriteShellCommands(Job *job, GNode *gn, bool *out_run)
|
|||||||
#ifdef USE_META
|
#ifdef USE_META
|
||||||
if (useMeta) {
|
if (useMeta) {
|
||||||
meta_job_start(job, gn);
|
meta_job_start(job, gn);
|
||||||
if (gn->type & OP_SILENT) /* might have changed */
|
if (gn->type & OP_SILENT) /* might have changed */
|
||||||
job->echo = false;
|
job->echo = false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1696,7 +1698,7 @@ JobStart(GNode *gn, bool special)
|
|||||||
|
|
||||||
job->special = special || gn->type & OP_SPECIAL;
|
job->special = special || gn->type & OP_SPECIAL;
|
||||||
job->ignerr = opts.ignoreErrors || gn->type & OP_IGNORE;
|
job->ignerr = opts.ignoreErrors || gn->type & OP_IGNORE;
|
||||||
job->echo = !(opts.beSilent || gn->type & OP_SILENT);
|
job->echo = !(opts.silent || gn->type & OP_SILENT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check the commands now so any attributes from .DEFAULT have a
|
* Check the commands now so any attributes from .DEFAULT have a
|
||||||
@ -1715,11 +1717,11 @@ JobStart(GNode *gn, bool special)
|
|||||||
* also dead...
|
* also dead...
|
||||||
*/
|
*/
|
||||||
if (!cmdsOK) {
|
if (!cmdsOK) {
|
||||||
PrintOnError(gn, NULL); /* provide some clue */
|
PrintOnError(gn, "\n"); /* provide some clue */
|
||||||
DieHorribly();
|
DieHorribly();
|
||||||
}
|
}
|
||||||
} else if (((gn->type & OP_MAKE) && !opts.noRecursiveExecute) ||
|
} else if (((gn->type & OP_MAKE) && !opts.noRecursiveExecute) ||
|
||||||
(!opts.noExecute && !opts.touchFlag)) {
|
(!opts.noExecute && !opts.touch)) {
|
||||||
/*
|
/*
|
||||||
* The above condition looks very similar to
|
* The above condition looks very similar to
|
||||||
* GNode_ShouldExecute but is subtly different. It prevents
|
* GNode_ShouldExecute but is subtly different. It prevents
|
||||||
@ -1732,7 +1734,7 @@ JobStart(GNode *gn, bool special)
|
|||||||
* also dead...
|
* also dead...
|
||||||
*/
|
*/
|
||||||
if (!cmdsOK) {
|
if (!cmdsOK) {
|
||||||
PrintOnError(gn, NULL); /* provide some clue */
|
PrintOnError(gn, "\n"); /* provide some clue */
|
||||||
DieHorribly();
|
DieHorribly();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1952,7 +1954,7 @@ again:
|
|||||||
* we add one of our own free will.
|
* we add one of our own free will.
|
||||||
*/
|
*/
|
||||||
if (*cp != '\0') {
|
if (*cp != '\0') {
|
||||||
if (!opts.beSilent)
|
if (!opts.silent)
|
||||||
SwitchOutputTo(job->node);
|
SwitchOutputTo(job->node);
|
||||||
#ifdef USE_META
|
#ifdef USE_META
|
||||||
if (useMeta) {
|
if (useMeta) {
|
||||||
@ -2016,7 +2018,7 @@ JobRun(GNode *targ)
|
|||||||
Compat_Make(targ, targ);
|
Compat_Make(targ, targ);
|
||||||
/* XXX: Replace with GNode_IsError(gn) */
|
/* XXX: Replace with GNode_IsError(gn) */
|
||||||
if (targ->made == ERROR) {
|
if (targ->made == ERROR) {
|
||||||
PrintOnError(targ, "\n\nStop.");
|
PrintOnError(targ, "\n\nStop.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -2164,9 +2166,8 @@ Job_CatchOutput(void)
|
|||||||
* than job->inPollfd.
|
* than job->inPollfd.
|
||||||
*/
|
*/
|
||||||
if (useMeta && job->inPollfd != &fds[i]) {
|
if (useMeta && job->inPollfd != &fds[i]) {
|
||||||
if (meta_job_event(job) <= 0) {
|
if (meta_job_event(job) <= 0)
|
||||||
fds[i].events = 0; /* never mind */
|
fds[i].events = 0; /* never mind */
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (--nready == 0)
|
if (--nready == 0)
|
||||||
@ -2220,14 +2221,8 @@ Shell_Init(void)
|
|||||||
free(shellErrFlag);
|
free(shellErrFlag);
|
||||||
shellErrFlag = NULL;
|
shellErrFlag = NULL;
|
||||||
}
|
}
|
||||||
if (shellErrFlag == NULL) {
|
if (shellErrFlag == NULL)
|
||||||
size_t n = strlen(shell->errFlag) + 2;
|
shellErrFlag = str_concat2("-", shell->errFlag);
|
||||||
|
|
||||||
shellErrFlag = bmake_malloc(n);
|
|
||||||
if (shellErrFlag != NULL)
|
|
||||||
snprintf(shellErrFlag, n, "-%s",
|
|
||||||
shell->errFlag);
|
|
||||||
}
|
|
||||||
} else if (shellErrFlag != NULL) {
|
} else if (shellErrFlag != NULL) {
|
||||||
free(shellErrFlag);
|
free(shellErrFlag);
|
||||||
shellErrFlag = NULL;
|
shellErrFlag = NULL;
|
||||||
@ -2352,8 +2347,10 @@ Job_Init(void)
|
|||||||
AddSig(SIGCONT, JobContinueSig);
|
AddSig(SIGCONT, JobContinueSig);
|
||||||
|
|
||||||
(void)Job_RunTarget(".BEGIN", NULL);
|
(void)Job_RunTarget(".BEGIN", NULL);
|
||||||
/* Create the .END node now, even though no code in the unit tests
|
/*
|
||||||
* depends on it. See also Targ_GetEndNode in Compat_Run. */
|
* Create the .END node now, even though no code in the unit tests
|
||||||
|
* depends on it. See also Targ_GetEndNode in Compat_Run.
|
||||||
|
*/
|
||||||
(void)Targ_GetEndNode();
|
(void)Targ_GetEndNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2493,13 +2490,17 @@ Job_ParseShell(char *line)
|
|||||||
} else if (strncmp(arg, "newline=", 8) == 0) {
|
} else if (strncmp(arg, "newline=", 8) == 0) {
|
||||||
newShell.newline = arg + 8;
|
newShell.newline = arg + 8;
|
||||||
} else if (strncmp(arg, "check=", 6) == 0) {
|
} else if (strncmp(arg, "check=", 6) == 0) {
|
||||||
/* Before 2020-12-10, these two variables
|
/*
|
||||||
* had been a single variable. */
|
* Before 2020-12-10, these two variables had
|
||||||
|
* been a single variable.
|
||||||
|
*/
|
||||||
newShell.errOn = arg + 6;
|
newShell.errOn = arg + 6;
|
||||||
newShell.echoTmpl = arg + 6;
|
newShell.echoTmpl = arg + 6;
|
||||||
} else if (strncmp(arg, "ignore=", 7) == 0) {
|
} else if (strncmp(arg, "ignore=", 7) == 0) {
|
||||||
/* Before 2020-12-10, these two variables
|
/*
|
||||||
* had been a single variable. */
|
* Before 2020-12-10, these two variables had
|
||||||
|
* been a single variable.
|
||||||
|
*/
|
||||||
newShell.errOff = arg + 7;
|
newShell.errOff = arg + 7;
|
||||||
newShell.runIgnTmpl = arg + 7;
|
newShell.runIgnTmpl = arg + 7;
|
||||||
} else if (strncmp(arg, "errout=", 7) == 0) {
|
} else if (strncmp(arg, "errout=", 7) == 0) {
|
||||||
@ -2641,7 +2642,7 @@ JobInterrupt(bool runINTERRUPT, int signo)
|
|||||||
|
|
||||||
JobSigUnlock(&mask);
|
JobSigUnlock(&mask);
|
||||||
|
|
||||||
if (runINTERRUPT && !opts.touchFlag) {
|
if (runINTERRUPT && !opts.touch) {
|
||||||
interrupt = Targ_FindNode(".INTERRUPT");
|
interrupt = Targ_FindNode(".INTERRUPT");
|
||||||
if (interrupt != NULL) {
|
if (interrupt != NULL) {
|
||||||
opts.ignoreErrors = false;
|
opts.ignoreErrors = false;
|
||||||
@ -2867,7 +2868,7 @@ Job_TempFile(const char *pattern, char *tfile, size_t tfile_sz)
|
|||||||
JobSigLock(&mask);
|
JobSigLock(&mask);
|
||||||
fd = mkTempFile(pattern, tfile, tfile_sz);
|
fd = mkTempFile(pattern, tfile, tfile_sz);
|
||||||
if (tfile != NULL && !DEBUG(SCRIPT))
|
if (tfile != NULL && !DEBUG(SCRIPT))
|
||||||
unlink(tfile);
|
unlink(tfile);
|
||||||
JobSigUnlock(&mask);
|
JobSigUnlock(&mask);
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
@ -2999,7 +3000,7 @@ Job_RunTarget(const char *target, const char *fname)
|
|||||||
JobRun(gn);
|
JobRun(gn);
|
||||||
/* XXX: Replace with GNode_IsError(gn) */
|
/* XXX: Replace with GNode_IsError(gn) */
|
||||||
if (gn->made == ERROR) {
|
if (gn->made == ERROR) {
|
||||||
PrintOnError(gn, "\n\nStop.");
|
PrintOnError(gn, "\n\nStop.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -3064,4 +3065,4 @@ emul_poll(struct pollfd *fd, int nfd, int timeout)
|
|||||||
|
|
||||||
return npoll;
|
return npoll;
|
||||||
}
|
}
|
||||||
#endif /* USE_SELECT */
|
#endif /* USE_SELECT */
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: job.h,v 1.73 2021/04/03 11:08:40 rillig Exp $ */
|
/* $NetBSD: job.h,v 1.77 2021/12/15 12:58:01 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
@ -80,7 +80,7 @@
|
|||||||
#ifndef MAKE_JOB_H
|
#ifndef MAKE_JOB_H
|
||||||
#define MAKE_JOB_H
|
#define MAKE_JOB_H
|
||||||
|
|
||||||
#define TMPPAT "makeXXXXXX" /* relative to tmpdir */
|
#define TMPPAT "makeXXXXXX" /* relative to tmpdir */
|
||||||
|
|
||||||
#ifdef USE_SELECT
|
#ifdef USE_SELECT
|
||||||
/*
|
/*
|
||||||
@ -92,16 +92,15 @@
|
|||||||
#define pollfd emul_pollfd
|
#define pollfd emul_pollfd
|
||||||
|
|
||||||
struct emul_pollfd {
|
struct emul_pollfd {
|
||||||
int fd;
|
int fd;
|
||||||
short events;
|
short events;
|
||||||
short revents;
|
short revents;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define POLLIN 0x0001
|
#define POLLIN 0x0001
|
||||||
#define POLLOUT 0x0004
|
#define POLLOUT 0x0004
|
||||||
|
|
||||||
int
|
int emul_poll(struct pollfd *, int, int);
|
||||||
emul_poll(struct pollfd *fd, int nfd, int timeout);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -145,9 +144,11 @@ typedef struct Job {
|
|||||||
/* The target the child is making */
|
/* The target the child is making */
|
||||||
GNode *node;
|
GNode *node;
|
||||||
|
|
||||||
/* If one of the shell commands is "...", all following commands are
|
/*
|
||||||
* delayed until the .END node is made. This list node points to the
|
* If one of the shell commands is "...", all following commands are
|
||||||
* first of these commands, if any. */
|
* delayed until the .END node is made. This list node points to the
|
||||||
|
* first of these commands, if any.
|
||||||
|
*/
|
||||||
StringListNode *tailCmds;
|
StringListNode *tailCmds;
|
||||||
|
|
||||||
/* This is where the shell commands go. */
|
/* This is where the shell commands go. */
|
||||||
@ -187,24 +188,25 @@ extern char *shellErrFlag;
|
|||||||
extern int jobTokensRunning; /* tokens currently "out" */
|
extern int jobTokensRunning; /* tokens currently "out" */
|
||||||
|
|
||||||
void Shell_Init(void);
|
void Shell_Init(void);
|
||||||
const char *Shell_GetNewline(void);
|
const char *Shell_GetNewline(void) MAKE_ATTR_USE;
|
||||||
void Job_Touch(GNode *, bool);
|
void Job_Touch(GNode *, bool);
|
||||||
bool Job_CheckCommands(GNode *, void (*abortProc)(const char *, ...));
|
bool Job_CheckCommands(GNode *, void (*abortProc)(const char *, ...))
|
||||||
|
MAKE_ATTR_USE;
|
||||||
void Job_CatchChildren(void);
|
void Job_CatchChildren(void);
|
||||||
void Job_CatchOutput(void);
|
void Job_CatchOutput(void);
|
||||||
void Job_Make(GNode *);
|
void Job_Make(GNode *);
|
||||||
void Job_Init(void);
|
void Job_Init(void);
|
||||||
bool Job_ParseShell(char *);
|
bool Job_ParseShell(char *) MAKE_ATTR_USE;
|
||||||
int Job_Finish(void);
|
int Job_Finish(void);
|
||||||
void Job_End(void);
|
void Job_End(void);
|
||||||
void Job_Wait(void);
|
void Job_Wait(void);
|
||||||
void Job_AbortAll(void);
|
void Job_AbortAll(void);
|
||||||
void Job_TokenReturn(void);
|
void Job_TokenReturn(void);
|
||||||
bool Job_TokenWithdraw(void);
|
bool Job_TokenWithdraw(void) MAKE_ATTR_USE;
|
||||||
void Job_ServerStart(int, int, int);
|
void Job_ServerStart(int, int, int);
|
||||||
void Job_SetPrefix(void);
|
void Job_SetPrefix(void);
|
||||||
bool Job_RunTarget(const char *, const char *);
|
bool Job_RunTarget(const char *, const char *);
|
||||||
void Job_FlagsToString(const Job *, char *, size_t);
|
void Job_FlagsToString(const Job *, char *, size_t);
|
||||||
int Job_TempFile(const char *, char *, size_t);
|
int Job_TempFile(const char *, char *, size_t) MAKE_ATTR_USE;
|
||||||
|
|
||||||
#endif /* MAKE_JOB_H */
|
#endif
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: lst.h,v 1.99 2021/12/05 10:11:31 rillig Exp $ */
|
/* $NetBSD: lst.h,v 1.102 2021/12/15 12:24:13 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
@ -109,7 +109,7 @@ typedef void LstFreeProc(void *);
|
|||||||
/* Create or destroy a list */
|
/* Create or destroy a list */
|
||||||
|
|
||||||
/* Create a new list. */
|
/* Create a new list. */
|
||||||
List *Lst_New(void);
|
List *Lst_New(void) MAKE_ATTR_USE;
|
||||||
/* Free the list nodes, but not the list itself. */
|
/* Free the list nodes, but not the list itself. */
|
||||||
void Lst_Done(List *);
|
void Lst_Done(List *);
|
||||||
/* Free the list nodes, freeing the node data using the given function. */
|
/* Free the list nodes, freeing the node data using the given function. */
|
||||||
@ -129,14 +129,14 @@ Lst_Init(List *list)
|
|||||||
|
|
||||||
/* Get information about a list */
|
/* Get information about a list */
|
||||||
|
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
Lst_IsEmpty(List *list)
|
Lst_IsEmpty(List *list)
|
||||||
{
|
{
|
||||||
return list->first == NULL;
|
return list->first == NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the first node that contains the given datum, or NULL. */
|
/* Find the first node that contains the given datum, or NULL. */
|
||||||
ListNode *Lst_FindDatum(List *, const void *);
|
ListNode *Lst_FindDatum(List *, const void *) MAKE_ATTR_USE;
|
||||||
|
|
||||||
/* Modify a list */
|
/* Modify a list */
|
||||||
|
|
||||||
@ -163,12 +163,13 @@ void LstNode_SetNull(ListNode *);
|
|||||||
|
|
||||||
/* Add a datum at the tail of the queue. */
|
/* Add a datum at the tail of the queue. */
|
||||||
MAKE_INLINE void
|
MAKE_INLINE void
|
||||||
Lst_Enqueue(List *list, void *datum) {
|
Lst_Enqueue(List *list, void *datum)
|
||||||
|
{
|
||||||
Lst_Append(list, datum);
|
Lst_Append(list, datum);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove the head node of the queue and return its datum. */
|
/* Remove the head node of the queue and return its datum. */
|
||||||
void *Lst_Dequeue(List *);
|
void *Lst_Dequeue(List *) MAKE_ATTR_USE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A vector is an ordered collection of items, allowing for fast indexed
|
* A vector is an ordered collection of items, allowing for fast indexed
|
||||||
@ -187,7 +188,7 @@ void Vector_Init(Vector *, size_t);
|
|||||||
* Return the pointer to the given item in the vector.
|
* Return the pointer to the given item in the vector.
|
||||||
* The returned data is valid until the next modifying operation.
|
* The returned data is valid until the next modifying operation.
|
||||||
*/
|
*/
|
||||||
MAKE_INLINE void *
|
MAKE_INLINE void * MAKE_ATTR_USE
|
||||||
Vector_Get(Vector *v, size_t i)
|
Vector_Get(Vector *v, size_t i)
|
||||||
{
|
{
|
||||||
unsigned char *items = v->items;
|
unsigned char *items = v->items;
|
||||||
@ -198,8 +199,9 @@ void *Vector_Push(Vector *);
|
|||||||
void *Vector_Pop(Vector *);
|
void *Vector_Pop(Vector *);
|
||||||
|
|
||||||
MAKE_INLINE void
|
MAKE_INLINE void
|
||||||
Vector_Done(Vector *v) {
|
Vector_Done(Vector *v)
|
||||||
|
{
|
||||||
free(v->items);
|
free(v->items);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* MAKE_LST_H */
|
#endif
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
|||||||
.\" $NetBSD: make.1,v 1.300 2021/12/12 20:45:48 sjg Exp $
|
.\" $NetBSD: make.1,v 1.304 2022/01/29 20:54:58 sjg Exp $
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 1990, 1993
|
.\" Copyright (c) 1990, 1993
|
||||||
.\" The Regents of the University of California. All rights reserved.
|
.\" The Regents of the University of California. All rights reserved.
|
||||||
@ -29,7 +29,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
|
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
|
||||||
.\"
|
.\"
|
||||||
.Dd December 12, 2021
|
.Dd January 28, 2022
|
||||||
.Dt MAKE 1
|
.Dt MAKE 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -691,10 +691,38 @@ Variables defined as part of the command line.
|
|||||||
Variables that are defined specific to a certain target.
|
Variables that are defined specific to a certain target.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
Local variables are all built in and their values vary magically from
|
Local variables can be set on a dependency line, if
|
||||||
target to target.
|
.Va .MAKE.TARGET_LOCAL_VARIABLES ,
|
||||||
It is not currently possible to define new local variables.
|
is not set to
|
||||||
The seven local variables are as follows:
|
.Ql false .
|
||||||
|
The rest of the line
|
||||||
|
(which will already have had Global variables expanded),
|
||||||
|
is the variable value.
|
||||||
|
For example:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
COMPILER_WRAPPERS+= ccache distcc icecc
|
||||||
|
|
||||||
|
${OBJS}: .MAKE.META.CMP_FILTER=${COMPILER_WRAPPERS:S,^,N,}
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Only the targets
|
||||||
|
.Ql ${OBJS}
|
||||||
|
will be impacted by that filter (in "meta" mode) and
|
||||||
|
simply enabling/disabling any of the wrappers will not render all
|
||||||
|
of those targets out-of-date.
|
||||||
|
.Pp
|
||||||
|
.Em NOTE :
|
||||||
|
target local variable assignments behave differently in that;
|
||||||
|
.Bl -tag -width Ds -offset indent
|
||||||
|
.It Ic \&+=
|
||||||
|
Only appends to a previous local assignment
|
||||||
|
for the same target and variable.
|
||||||
|
.It Ic \&:=
|
||||||
|
Is redundant with respect to Global variables,
|
||||||
|
which have already been expanded.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The seven built-in local variables are as follows:
|
||||||
.Bl -tag -width ".ARCHIVE" -offset indent
|
.Bl -tag -width ".ARCHIVE" -offset indent
|
||||||
.It Va .ALLSRC
|
.It Va .ALLSRC
|
||||||
The list of all sources for this target; also known as
|
The list of all sources for this target; also known as
|
||||||
@ -857,6 +885,11 @@ For example:
|
|||||||
would produce tokens like
|
would produce tokens like
|
||||||
.Ql ---make[1234] target ---
|
.Ql ---make[1234] target ---
|
||||||
making it easier to track the degree of parallelism being achieved.
|
making it easier to track the degree of parallelism being achieved.
|
||||||
|
.It .MAKE.TARGET_LOCAL_VARIABLES
|
||||||
|
If set to
|
||||||
|
.Ql false ,
|
||||||
|
apparent variable assignments in dependency lines are
|
||||||
|
treated as normal sources.
|
||||||
.It Ev MAKEFLAGS
|
.It Ev MAKEFLAGS
|
||||||
The environment variable
|
The environment variable
|
||||||
.Ql Ev MAKEFLAGS
|
.Ql Ev MAKEFLAGS
|
||||||
@ -965,6 +998,12 @@ If a file that was generated outside of
|
|||||||
.Va .OBJDIR
|
.Va .OBJDIR
|
||||||
but within said bailiwick is missing,
|
but within said bailiwick is missing,
|
||||||
the current target is considered out-of-date.
|
the current target is considered out-of-date.
|
||||||
|
.It Va .MAKE.META.CMP_FILTER
|
||||||
|
In "meta" mode, it can (very rarely!) be useful to filter command
|
||||||
|
lines before comparison.
|
||||||
|
This variable can be set to a set of modifiers that will be applied to
|
||||||
|
each line of the old and new command that differ, if the filtered
|
||||||
|
commands still differ, the target is considered out-of-date.
|
||||||
.It Va .MAKE.META.CREATED
|
.It Va .MAKE.META.CREATED
|
||||||
In "meta" mode, this variable contains a list of all the meta files
|
In "meta" mode, this variable contains a list of all the meta files
|
||||||
updated.
|
updated.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: make.c,v 1.248 2021/11/28 23:12:51 rillig Exp $ */
|
/* $NetBSD: make.c,v 1.252 2022/01/09 15:48:30 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
* Copyright (c) 1988, 1989, 1990, 1993
|
||||||
@ -104,7 +104,7 @@
|
|||||||
#include "job.h"
|
#include "job.h"
|
||||||
|
|
||||||
/* "@(#)make.c 8.1 (Berkeley) 6/6/93" */
|
/* "@(#)make.c 8.1 (Berkeley) 6/6/93" */
|
||||||
MAKE_RCSID("$NetBSD: make.c,v 1.248 2021/11/28 23:12:51 rillig Exp $");
|
MAKE_RCSID("$NetBSD: make.c,v 1.252 2022/01/09 15:48:30 rillig Exp $");
|
||||||
|
|
||||||
/* Sequence # to detect recursion. */
|
/* Sequence # to detect recursion. */
|
||||||
static unsigned int checked_seqno = 1;
|
static unsigned int checked_seqno = 1;
|
||||||
@ -120,11 +120,11 @@ static GNodeList toBeMade = LST_INIT;
|
|||||||
void
|
void
|
||||||
debug_printf(const char *fmt, ...)
|
debug_printf(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list ap;
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(ap, fmt);
|
||||||
vfprintf(opts.debug_file, fmt, args);
|
vfprintf(opts.debug_file, fmt, ap);
|
||||||
va_end(args);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
MAKE_ATTR_DEAD static void
|
MAKE_ATTR_DEAD static void
|
||||||
@ -370,9 +370,8 @@ GNode_IsOODate(GNode *gn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_META
|
#ifdef USE_META
|
||||||
if (useMeta) {
|
if (useMeta)
|
||||||
oodate = meta_oodate(gn, oodate);
|
oodate = meta_oodate(gn, oodate);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -599,8 +598,9 @@ Make_Recheck(GNode *gn)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* XXX: The returned mtime may differ from gn->mtime.
|
/*
|
||||||
* Intentionally? */
|
* XXX: The returned mtime may differ from gn->mtime. Intentionally?
|
||||||
|
*/
|
||||||
return mtime;
|
return mtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -952,7 +952,9 @@ MakeBuildChild(GNode *cn, GNodeListNode *toBeMadeNext)
|
|||||||
|
|
||||||
/* If this node is on the RHS of a .ORDER, check LHSs. */
|
/* If this node is on the RHS of a .ORDER, check LHSs. */
|
||||||
if (IsWaitingForOrder(cn)) {
|
if (IsWaitingForOrder(cn)) {
|
||||||
/* Can't build this (or anything else in this child list) yet */
|
/*
|
||||||
|
* Can't build this (or anything else in this child list) yet
|
||||||
|
*/
|
||||||
cn->made = DEFERRED;
|
cn->made = DEFERRED;
|
||||||
return false; /* but keep looking */
|
return false; /* but keep looking */
|
||||||
}
|
}
|
||||||
@ -1070,7 +1072,7 @@ MakeStartJobs(void)
|
|||||||
gn->made = BEINGMADE;
|
gn->made = BEINGMADE;
|
||||||
if (GNode_IsOODate(gn)) {
|
if (GNode_IsOODate(gn)) {
|
||||||
DEBUG0(MAKE, "out-of-date\n");
|
DEBUG0(MAKE, "out-of-date\n");
|
||||||
if (opts.queryFlag)
|
if (opts.query)
|
||||||
return true;
|
return true;
|
||||||
GNode_SetLocalVars(gn);
|
GNode_SetLocalVars(gn);
|
||||||
Job_Make(gn);
|
Job_Make(gn);
|
||||||
@ -1327,7 +1329,9 @@ add_wait_dependency(GNodeListNode *owln, GNode *wn)
|
|||||||
DEBUG3(MAKE, ".WAIT: add dependency %s%s -> %s\n",
|
DEBUG3(MAKE, ".WAIT: add dependency %s%s -> %s\n",
|
||||||
cn->name, cn->cohort_num, wn->name);
|
cn->name, cn->cohort_num, wn->name);
|
||||||
|
|
||||||
/* XXX: This pattern should be factored out, it repeats often */
|
/*
|
||||||
|
* XXX: This pattern should be factored out, it repeats often
|
||||||
|
*/
|
||||||
Lst_Append(&wn->children, cn);
|
Lst_Append(&wn->children, cn);
|
||||||
wn->unmade++;
|
wn->unmade++;
|
||||||
Lst_Append(&cn->parents, wn);
|
Lst_Append(&cn->parents, wn);
|
||||||
@ -1436,7 +1440,7 @@ Make_Run(GNodeList *targs)
|
|||||||
Targ_PrintGraph(1);
|
Targ_PrintGraph(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.queryFlag) {
|
if (opts.query) {
|
||||||
/*
|
/*
|
||||||
* We wouldn't do any work unless we could start some jobs
|
* We wouldn't do any work unless we could start some jobs
|
||||||
* in the next loop... (we won't actually start any, of
|
* in the next loop... (we won't actually start any, of
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: make.h,v 1.270 2021/11/28 23:12:51 rillig Exp $ */
|
/* $NetBSD: make.h,v 1.298 2022/02/05 00:26:21 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
* Copyright (c) 1988, 1989, 1990, 1993
|
||||||
@ -74,7 +74,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* make.h --
|
* make.h --
|
||||||
* The global definitions for pmake
|
* The global definitions for make
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MAKE_MAKE_H
|
#ifndef MAKE_MAKE_H
|
||||||
@ -110,9 +110,9 @@
|
|||||||
#define MAKE_GNUC_PREREQ(x, y) \
|
#define MAKE_GNUC_PREREQ(x, y) \
|
||||||
((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \
|
((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \
|
||||||
(__GNUC__ > (x)))
|
(__GNUC__ > (x)))
|
||||||
#else /* defined(__GNUC__) */
|
#else
|
||||||
#define MAKE_GNUC_PREREQ(x, y) 0
|
#define MAKE_GNUC_PREREQ(x, y) 0
|
||||||
#endif /* defined(__GNUC__) */
|
#endif
|
||||||
|
|
||||||
#if MAKE_GNUC_PREREQ(2, 7)
|
#if MAKE_GNUC_PREREQ(2, 7)
|
||||||
#define MAKE_ATTR_UNUSED __attribute__((__unused__))
|
#define MAKE_ATTR_UNUSED __attribute__((__unused__))
|
||||||
@ -135,7 +135,17 @@
|
|||||||
#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) /* delete */
|
#define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) /* delete */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MAKE_GNUC_PREREQ(4, 0)
|
||||||
|
#define MAKE_ATTR_USE __attribute__((__warn_unused_result__))
|
||||||
|
#else
|
||||||
|
#define MAKE_ATTR_USE /* delete */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __STDC__ >= 199901L || defined(lint)
|
||||||
#define MAKE_INLINE static inline MAKE_ATTR_UNUSED
|
#define MAKE_INLINE static inline MAKE_ATTR_UNUSED
|
||||||
|
#else
|
||||||
|
#define MAKE_INLINE static MAKE_ATTR_UNUSED
|
||||||
|
#endif
|
||||||
|
|
||||||
/* MAKE_STATIC marks a function that may or may not be inlined. */
|
/* MAKE_STATIC marks a function that may or may not be inlined. */
|
||||||
#if defined(lint)
|
#if defined(lint)
|
||||||
@ -206,26 +216,34 @@ typedef unsigned char bool;
|
|||||||
typedef enum GNodeMade {
|
typedef enum GNodeMade {
|
||||||
/* Not examined yet. */
|
/* Not examined yet. */
|
||||||
UNMADE,
|
UNMADE,
|
||||||
/* The node has been examined but is not yet ready since its
|
/*
|
||||||
* dependencies have to be made first. */
|
* The node has been examined but is not yet ready since its
|
||||||
|
* dependencies have to be made first.
|
||||||
|
*/
|
||||||
DEFERRED,
|
DEFERRED,
|
||||||
|
|
||||||
/* The node is on the toBeMade list. */
|
/* The node is on the toBeMade list. */
|
||||||
REQUESTED,
|
REQUESTED,
|
||||||
|
|
||||||
/* The node is already being made. Trying to build a node in this
|
/*
|
||||||
* state indicates a cycle in the graph. */
|
* The node is already being made. Trying to build a node in this
|
||||||
|
* state indicates a cycle in the graph.
|
||||||
|
*/
|
||||||
BEINGMADE,
|
BEINGMADE,
|
||||||
|
|
||||||
/* Was out-of-date and has been made. */
|
/* Was out-of-date and has been made. */
|
||||||
MADE,
|
MADE,
|
||||||
/* Was already up-to-date, does not need to be made. */
|
/* Was already up-to-date, does not need to be made. */
|
||||||
UPTODATE,
|
UPTODATE,
|
||||||
/* An error occurred while it was being made.
|
/*
|
||||||
* Used only in compat mode. */
|
* An error occurred while it was being made. Used only in compat
|
||||||
|
* mode.
|
||||||
|
*/
|
||||||
ERROR,
|
ERROR,
|
||||||
/* The target was aborted due to an error making a dependency.
|
/*
|
||||||
* Used only in compat mode. */
|
* The target was aborted due to an error making a dependency. Used
|
||||||
|
* only in compat mode.
|
||||||
|
*/
|
||||||
ABORTED
|
ABORTED
|
||||||
} GNodeMade;
|
} GNodeMade;
|
||||||
|
|
||||||
@ -241,16 +259,22 @@ typedef enum GNodeMade {
|
|||||||
typedef enum GNodeType {
|
typedef enum GNodeType {
|
||||||
OP_NONE = 0,
|
OP_NONE = 0,
|
||||||
|
|
||||||
/* The dependency operator ':' is the most common one. The commands
|
/*
|
||||||
* of this node are executed if any child is out-of-date. */
|
* The dependency operator ':' is the most common one. The commands
|
||||||
|
* of this node are executed if any child is out-of-date.
|
||||||
|
*/
|
||||||
OP_DEPENDS = 1 << 0,
|
OP_DEPENDS = 1 << 0,
|
||||||
/* The dependency operator '!' always executes its commands, even if
|
/*
|
||||||
* its children are up-to-date. */
|
* The dependency operator '!' always executes its commands, even if
|
||||||
|
* its children are up-to-date.
|
||||||
|
*/
|
||||||
OP_FORCE = 1 << 1,
|
OP_FORCE = 1 << 1,
|
||||||
/* The dependency operator '::' behaves like ':', except that it
|
/*
|
||||||
|
* The dependency operator '::' behaves like ':', except that it
|
||||||
* allows multiple dependency groups to be defined. Each of these
|
* allows multiple dependency groups to be defined. Each of these
|
||||||
* groups is executed on its own, independently from the others.
|
* groups is executed on its own, independently from the others. Each
|
||||||
* Each individual dependency group is called a cohort. */
|
* individual dependency group is called a cohort.
|
||||||
|
*/
|
||||||
OP_DOUBLEDEP = 1 << 2,
|
OP_DOUBLEDEP = 1 << 2,
|
||||||
|
|
||||||
/* Matches the dependency operators ':', '!' and '::'. */
|
/* Matches the dependency operators ':', '!' and '::'. */
|
||||||
@ -260,21 +284,29 @@ typedef enum GNodeType {
|
|||||||
OP_OPTIONAL = 1 << 3,
|
OP_OPTIONAL = 1 << 3,
|
||||||
/* Use associated commands for parents. */
|
/* Use associated commands for parents. */
|
||||||
OP_USE = 1 << 4,
|
OP_USE = 1 << 4,
|
||||||
/* Target is never out of date, but always execute commands anyway.
|
/*
|
||||||
* Its time doesn't matter, so it has none...sort of. */
|
* Target is never out of date, but always execute commands anyway.
|
||||||
|
* Its time doesn't matter, so it has none...sort of.
|
||||||
|
*/
|
||||||
OP_EXEC = 1 << 5,
|
OP_EXEC = 1 << 5,
|
||||||
/* Ignore non-zero exit status from shell commands when creating the
|
/*
|
||||||
* node. */
|
* Ignore non-zero exit status from shell commands when creating the
|
||||||
|
* node.
|
||||||
|
*/
|
||||||
OP_IGNORE = 1 << 6,
|
OP_IGNORE = 1 << 6,
|
||||||
/* Don't remove the target when interrupted. */
|
/* Don't remove the target when interrupted. */
|
||||||
OP_PRECIOUS = 1 << 7,
|
OP_PRECIOUS = 1 << 7,
|
||||||
/* Don't echo commands when executed. */
|
/* Don't echo commands when executed. */
|
||||||
OP_SILENT = 1 << 8,
|
OP_SILENT = 1 << 8,
|
||||||
/* Target is a recursive make so its commands should always be
|
/*
|
||||||
* executed when it is out of date, regardless of the state of the
|
* Target is a recursive make so its commands should always be
|
||||||
* -n or -t flags. */
|
* executed when it is out of date, regardless of the state of the -n
|
||||||
|
* or -t flags.
|
||||||
|
*/
|
||||||
OP_MAKE = 1 << 9,
|
OP_MAKE = 1 << 9,
|
||||||
/* Target is out-of-date only if any of its children was out-of-date. */
|
/*
|
||||||
|
* Target is out-of-date only if any of its children was out-of-date.
|
||||||
|
*/
|
||||||
OP_JOIN = 1 << 10,
|
OP_JOIN = 1 << 10,
|
||||||
/* Assume the children of the node have been already made. */
|
/* Assume the children of the node have been already made. */
|
||||||
OP_MADE = 1 << 11,
|
OP_MADE = 1 << 11,
|
||||||
@ -282,20 +314,26 @@ typedef enum GNodeType {
|
|||||||
OP_SPECIAL = 1 << 12,
|
OP_SPECIAL = 1 << 12,
|
||||||
/* Like .USE, only prepend commands. */
|
/* Like .USE, only prepend commands. */
|
||||||
OP_USEBEFORE = 1 << 13,
|
OP_USEBEFORE = 1 << 13,
|
||||||
/* The node is invisible to its parents. I.e. it doesn't show up in
|
/*
|
||||||
* the parents' local variables (.IMPSRC, .ALLSRC). */
|
* The node is invisible to its parents. I.e. it doesn't show up in
|
||||||
|
* the parents' local variables (.IMPSRC, .ALLSRC).
|
||||||
|
*/
|
||||||
OP_INVISIBLE = 1 << 14,
|
OP_INVISIBLE = 1 << 14,
|
||||||
/* The node does not become the main target, even if it is the first
|
/*
|
||||||
* target in the first makefile. */
|
* The node does not become the main target, even if it is the first
|
||||||
|
* target in the first makefile.
|
||||||
|
*/
|
||||||
OP_NOTMAIN = 1 << 15,
|
OP_NOTMAIN = 1 << 15,
|
||||||
/* Not a file target; run always. */
|
/* Not a file target; run always. */
|
||||||
OP_PHONY = 1 << 16,
|
OP_PHONY = 1 << 16,
|
||||||
/* Don't search for the file in the path. */
|
/* Don't search for the file in the path. */
|
||||||
OP_NOPATH = 1 << 17,
|
OP_NOPATH = 1 << 17,
|
||||||
/* In a dependency line "target: source1 .WAIT source2", source1 is
|
/*
|
||||||
|
* In a dependency line "target: source1 .WAIT source2", source1 is
|
||||||
* made first, including its children. Once that is finished,
|
* made first, including its children. Once that is finished,
|
||||||
* source2 is made, including its children. The .WAIT keyword may
|
* source2 is made, including its children. The .WAIT keyword may
|
||||||
* appear more than once in a single dependency declaration. */
|
* appear more than once in a single dependency declaration.
|
||||||
|
*/
|
||||||
OP_WAIT = 1 << 18,
|
OP_WAIT = 1 << 18,
|
||||||
/* .NOMETA do not create a .meta file */
|
/* .NOMETA do not create a .meta file */
|
||||||
OP_NOMETA = 1 << 19,
|
OP_NOMETA = 1 << 19,
|
||||||
@ -313,28 +351,35 @@ typedef enum GNodeType {
|
|||||||
/* Target is a member of an archive */
|
/* Target is a member of an archive */
|
||||||
/* XXX: How does this differ from OP_ARCHV? */
|
/* XXX: How does this differ from OP_ARCHV? */
|
||||||
OP_MEMBER = 1 << 29,
|
OP_MEMBER = 1 << 29,
|
||||||
/* The node is a library,
|
/*
|
||||||
* its name has the form "-l<libname>" */
|
* The node is a library, its name has the form "-l<libname>".
|
||||||
|
*/
|
||||||
OP_LIB = 1 << 28,
|
OP_LIB = 1 << 28,
|
||||||
/* The node is an archive member,
|
/*
|
||||||
* its name has the form "archive(member)" */
|
* The node is an archive member, its name has the form
|
||||||
|
* "archive(member)".
|
||||||
|
*/
|
||||||
/* XXX: How does this differ from OP_MEMBER? */
|
/* XXX: How does this differ from OP_MEMBER? */
|
||||||
OP_ARCHV = 1 << 27,
|
OP_ARCHV = 1 << 27,
|
||||||
/* Target has all the commands it should. Used when parsing to catch
|
/*
|
||||||
|
* Target has all the commands it should. Used when parsing to catch
|
||||||
* multiple command groups for a target. Only applies to the
|
* multiple command groups for a target. Only applies to the
|
||||||
* dependency operators ':' and '!', but not to '::'. */
|
* dependency operators ':' and '!', but not to '::'.
|
||||||
|
*/
|
||||||
OP_HAS_COMMANDS = 1 << 26,
|
OP_HAS_COMMANDS = 1 << 26,
|
||||||
/* The special command "..." has been seen. All further commands from
|
/*
|
||||||
* this node will be saved on the .END node instead, to be executed at
|
* The special command "..." has been seen. All further commands from
|
||||||
* the very end. */
|
* this node will be saved on the .END node instead, to be executed
|
||||||
|
* at the very end.
|
||||||
|
*/
|
||||||
OP_SAVE_CMDS = 1 << 25,
|
OP_SAVE_CMDS = 1 << 25,
|
||||||
/* Already processed by Suff_FindDeps, to find dependencies from
|
/*
|
||||||
* suffix transformation rules. */
|
* Already processed by Suff_FindDeps, to find dependencies from
|
||||||
|
* suffix transformation rules.
|
||||||
|
*/
|
||||||
OP_DEPS_FOUND = 1 << 24,
|
OP_DEPS_FOUND = 1 << 24,
|
||||||
/* Node found while expanding .ALLSRC */
|
/* Node found while expanding .ALLSRC */
|
||||||
OP_MARK = 1 << 23,
|
OP_MARK = 1 << 23
|
||||||
|
|
||||||
OP_NOTARGET = OP_NOTMAIN | OP_USE | OP_EXEC | OP_TRANSFORM
|
|
||||||
} GNodeType;
|
} GNodeType;
|
||||||
|
|
||||||
typedef struct GNodeFlags {
|
typedef struct GNodeFlags {
|
||||||
@ -377,14 +422,20 @@ typedef struct GNode {
|
|||||||
char *name;
|
char *name;
|
||||||
/* The unexpanded name of a .USE node */
|
/* The unexpanded name of a .USE node */
|
||||||
char *uname;
|
char *uname;
|
||||||
/* The full pathname of the file belonging to the target.
|
/*
|
||||||
|
* The full pathname of the file belonging to the target.
|
||||||
|
*
|
||||||
* XXX: What about .PHONY targets? These don't have an associated
|
* XXX: What about .PHONY targets? These don't have an associated
|
||||||
* path. */
|
* path.
|
||||||
|
*/
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
/* The type of operator used to define the sources (see the OP flags
|
/*
|
||||||
|
* The type of operator used to define the sources (see the OP flags
|
||||||
* below).
|
* below).
|
||||||
* XXX: This looks like a wild mixture of type and flags. */
|
*
|
||||||
|
* XXX: This looks like a wild mixture of type and flags.
|
||||||
|
*/
|
||||||
GNodeType type;
|
GNodeType type;
|
||||||
GNodeFlags flags;
|
GNodeFlags flags;
|
||||||
|
|
||||||
@ -393,29 +444,39 @@ typedef struct GNode {
|
|||||||
/* The number of unmade children */
|
/* The number of unmade children */
|
||||||
int unmade;
|
int unmade;
|
||||||
|
|
||||||
/* The modification time; 0 means the node does not have a
|
/*
|
||||||
* corresponding file; see GNode_IsOODate. */
|
* The modification time; 0 means the node does not have a
|
||||||
|
* corresponding file; see GNode_IsOODate.
|
||||||
|
*/
|
||||||
time_t mtime;
|
time_t mtime;
|
||||||
struct GNode *youngestChild;
|
struct GNode *youngestChild;
|
||||||
|
|
||||||
/* The GNodes for which this node is an implied source. May be empty.
|
/*
|
||||||
* For example, when there is an inference rule for .c.o, the node for
|
* The GNodes for which this node is an implied source. May be empty.
|
||||||
* file.c has the node for file.o in this list. */
|
* For example, when there is an inference rule for .c.o, the node
|
||||||
|
* for file.c has the node for file.o in this list.
|
||||||
|
*/
|
||||||
GNodeList implicitParents;
|
GNodeList implicitParents;
|
||||||
|
|
||||||
/* The nodes that depend on this one, or in other words, the nodes for
|
/*
|
||||||
* which this is a source. */
|
* The nodes that depend on this one, or in other words, the nodes
|
||||||
|
* for which this is a source.
|
||||||
|
*/
|
||||||
GNodeList parents;
|
GNodeList parents;
|
||||||
/* The nodes on which this one depends. */
|
/* The nodes on which this one depends. */
|
||||||
GNodeList children;
|
GNodeList children;
|
||||||
|
|
||||||
/* .ORDER nodes we need made. The nodes that must be made (if they're
|
/*
|
||||||
|
* .ORDER nodes we need made. The nodes that must be made (if they're
|
||||||
* made) before this node can be made, but that do not enter into the
|
* made) before this node can be made, but that do not enter into the
|
||||||
* datedness of this node. */
|
* datedness of this node.
|
||||||
|
*/
|
||||||
GNodeList order_pred;
|
GNodeList order_pred;
|
||||||
/* .ORDER nodes who need us. The nodes that must be made (if they're
|
/*
|
||||||
|
* .ORDER nodes who need us. The nodes that must be made (if they're
|
||||||
* made at all) after this node is made, but that do not depend on
|
* made at all) after this node is made, but that do not depend on
|
||||||
* this node, in the normal sense. */
|
* this node, in the normal sense.
|
||||||
|
*/
|
||||||
GNodeList order_succ;
|
GNodeList order_succ;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -427,8 +488,10 @@ typedef struct GNode {
|
|||||||
char cohort_num[8];
|
char cohort_num[8];
|
||||||
/* The number of unmade instances on the cohorts list */
|
/* The number of unmade instances on the cohorts list */
|
||||||
int unmade_cohorts;
|
int unmade_cohorts;
|
||||||
/* Pointer to the first instance of a '::' node; only set when on a
|
/*
|
||||||
* cohorts list */
|
* Pointer to the first instance of a '::' node; only set when on a
|
||||||
|
* cohorts list
|
||||||
|
*/
|
||||||
struct GNode *centurion;
|
struct GNode *centurion;
|
||||||
|
|
||||||
/* Last time (sequence number) we tried to make this node */
|
/* Last time (sequence number) we tried to make this node */
|
||||||
@ -447,21 +510,24 @@ typedef struct GNode {
|
|||||||
/* The commands to be given to a shell to create this target. */
|
/* The commands to be given to a shell to create this target. */
|
||||||
StringList commands;
|
StringList commands;
|
||||||
|
|
||||||
/* Suffix for the node (determined by Suff_FindDeps and opaque to
|
/*
|
||||||
* everyone but the Suff module) */
|
* Suffix for the node (determined by Suff_FindDeps and opaque to
|
||||||
|
* everyone but the Suff module)
|
||||||
|
*/
|
||||||
struct Suffix *suffix;
|
struct Suffix *suffix;
|
||||||
|
|
||||||
/* Filename where the GNode got defined */
|
/* Filename where the GNode got defined, unlimited lifetime */
|
||||||
/* XXX: What is the lifetime of this string? */
|
|
||||||
const char *fname;
|
const char *fname;
|
||||||
/* Line number where the GNode got defined */
|
/* Line number where the GNode got defined, 1-based */
|
||||||
int lineno;
|
unsigned lineno;
|
||||||
} GNode;
|
} GNode;
|
||||||
|
|
||||||
/* Error levels for diagnostics during parsing. */
|
/* Error levels for diagnostics during parsing. */
|
||||||
typedef enum ParseErrorLevel {
|
typedef enum ParseErrorLevel {
|
||||||
/* Exit when the current top-level makefile has been parsed
|
/*
|
||||||
* completely. */
|
* Exit when the current top-level makefile has been parsed
|
||||||
|
* completely.
|
||||||
|
*/
|
||||||
PARSE_FATAL = 1,
|
PARSE_FATAL = 1,
|
||||||
/* Print "warning"; may be upgraded to fatal by the -w option. */
|
/* Print "warning"; may be upgraded to fatal by the -w option. */
|
||||||
PARSE_WARNING,
|
PARSE_WARNING,
|
||||||
@ -472,20 +538,20 @@ typedef enum ParseErrorLevel {
|
|||||||
/*
|
/*
|
||||||
* Values returned by Cond_EvalLine and Cond_EvalCondition.
|
* Values returned by Cond_EvalLine and Cond_EvalCondition.
|
||||||
*/
|
*/
|
||||||
typedef enum CondEvalResult {
|
typedef enum CondResult {
|
||||||
COND_PARSE, /* Parse the next lines */
|
CR_TRUE, /* Parse the next lines */
|
||||||
COND_SKIP, /* Skip the next lines */
|
CR_FALSE, /* Skip the next lines */
|
||||||
COND_INVALID /* Not a conditional statement */
|
CR_ERROR /* Unknown directive or parse error */
|
||||||
} CondEvalResult;
|
} CondResult;
|
||||||
|
|
||||||
/* Names of the variables that are "local" to a specific target. */
|
/* Names of the variables that are "local" to a specific target. */
|
||||||
#define TARGET "@" /* Target of dependency */
|
#define TARGET "@" /* Target of dependency */
|
||||||
#define OODATE "?" /* All out-of-date sources */
|
#define OODATE "?" /* All out-of-date sources */
|
||||||
#define ALLSRC ">" /* All sources */
|
#define ALLSRC ">" /* All sources */
|
||||||
#define IMPSRC "<" /* Source implied by transformation */
|
#define IMPSRC "<" /* Source implied by transformation */
|
||||||
#define PREFIX "*" /* Common prefix */
|
#define PREFIX "*" /* Common prefix */
|
||||||
#define ARCHIVE "!" /* Archive in "archive(member)" syntax */
|
#define ARCHIVE "!" /* Archive in "archive(member)" syntax */
|
||||||
#define MEMBER "%" /* Member in "archive(member)" syntax */
|
#define MEMBER "%" /* Member in "archive(member)" syntax */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global Variables
|
* Global Variables
|
||||||
@ -543,6 +609,7 @@ extern int makelevel;
|
|||||||
extern char *makeDependfile;
|
extern char *makeDependfile;
|
||||||
/* If we replaced environ, this will be non-NULL. */
|
/* If we replaced environ, this will be non-NULL. */
|
||||||
extern char **savedEnv;
|
extern char **savedEnv;
|
||||||
|
extern GNode *mainNode;
|
||||||
|
|
||||||
extern pid_t myPid;
|
extern pid_t myPid;
|
||||||
|
|
||||||
@ -560,34 +627,32 @@ extern pid_t myPid;
|
|||||||
# define MAKE_LEVEL_ENV "MAKELEVEL"
|
# define MAKE_LEVEL_ENV "MAKELEVEL"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum DebugFlags {
|
typedef struct DebugFlags {
|
||||||
DEBUG_NONE = 0,
|
bool DEBUG_ARCH:1;
|
||||||
DEBUG_ARCH = 1 << 0,
|
bool DEBUG_COND:1;
|
||||||
DEBUG_COND = 1 << 1,
|
bool DEBUG_CWD:1;
|
||||||
DEBUG_CWD = 1 << 2,
|
bool DEBUG_DIR:1;
|
||||||
DEBUG_DIR = 1 << 3,
|
bool DEBUG_ERROR:1;
|
||||||
DEBUG_ERROR = 1 << 4,
|
bool DEBUG_FOR:1;
|
||||||
DEBUG_FOR = 1 << 5,
|
bool DEBUG_GRAPH1:1;
|
||||||
DEBUG_GRAPH1 = 1 << 6,
|
bool DEBUG_GRAPH2:1;
|
||||||
DEBUG_GRAPH2 = 1 << 7,
|
bool DEBUG_GRAPH3:1;
|
||||||
DEBUG_GRAPH3 = 1 << 8,
|
bool DEBUG_HASH:1;
|
||||||
DEBUG_HASH = 1 << 9,
|
bool DEBUG_JOB:1;
|
||||||
DEBUG_JOB = 1 << 10,
|
bool DEBUG_LOUD:1;
|
||||||
DEBUG_LOUD = 1 << 11,
|
bool DEBUG_MAKE:1;
|
||||||
DEBUG_MAKE = 1 << 12,
|
bool DEBUG_META:1;
|
||||||
DEBUG_META = 1 << 13,
|
bool DEBUG_PARSE:1;
|
||||||
DEBUG_PARSE = 1 << 14,
|
bool DEBUG_SCRIPT:1;
|
||||||
DEBUG_SCRIPT = 1 << 15,
|
bool DEBUG_SHELL:1;
|
||||||
DEBUG_SHELL = 1 << 16,
|
bool DEBUG_SUFF:1;
|
||||||
DEBUG_SUFF = 1 << 17,
|
bool DEBUG_TARG:1;
|
||||||
DEBUG_TARG = 1 << 18,
|
bool DEBUG_VAR:1;
|
||||||
DEBUG_VAR = 1 << 19,
|
|
||||||
DEBUG_ALL = (1 << 20) - 1
|
|
||||||
} DebugFlags;
|
} DebugFlags;
|
||||||
|
|
||||||
#define CONCAT(a, b) a##b
|
#define CONCAT(a, b) a##b
|
||||||
|
|
||||||
#define DEBUG(module) ((opts.debug & CONCAT(DEBUG_, module)) != 0)
|
#define DEBUG(module) (opts.debug.CONCAT(DEBUG_, module))
|
||||||
|
|
||||||
void debug_printf(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
|
void debug_printf(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
|
||||||
|
|
||||||
@ -597,8 +662,8 @@ void debug_printf(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
|
|||||||
debug_printf args; \
|
debug_printf args; \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define DEBUG0(module, text) \
|
#define DEBUG0(module, fmt) \
|
||||||
DEBUG_IMPL(module, ("%s", text))
|
DEBUG_IMPL(module, (fmt))
|
||||||
#define DEBUG1(module, fmt, arg1) \
|
#define DEBUG1(module, fmt, arg1) \
|
||||||
DEBUG_IMPL(module, (fmt, arg1))
|
DEBUG_IMPL(module, (fmt, arg1))
|
||||||
#define DEBUG2(module, fmt, arg1, arg2) \
|
#define DEBUG2(module, fmt, arg1, arg2) \
|
||||||
@ -621,17 +686,21 @@ typedef struct CmdOpts {
|
|||||||
/* -B: whether we are make compatible */
|
/* -B: whether we are make compatible */
|
||||||
bool compatMake;
|
bool compatMake;
|
||||||
|
|
||||||
/* -d: debug control: There is one bit per module. It is up to the
|
/*
|
||||||
* module what debug information to print. */
|
* -d: debug control: There is one bit per module. It is up to the
|
||||||
|
* module what debug information to print.
|
||||||
|
*/
|
||||||
DebugFlags debug;
|
DebugFlags debug;
|
||||||
|
|
||||||
/* -df: debug output is written here - default stderr */
|
/* -df: debug output is written here - default stderr */
|
||||||
FILE *debug_file;
|
FILE *debug_file;
|
||||||
|
|
||||||
/* -dL: lint mode
|
/*
|
||||||
|
* -dL: lint mode
|
||||||
*
|
*
|
||||||
* Runs make in strict mode, with additional checks and better error
|
* Runs make in strict mode, with additional checks and better error
|
||||||
* handling. */
|
* handling.
|
||||||
|
*/
|
||||||
bool strict;
|
bool strict;
|
||||||
|
|
||||||
/* -dV: for the -V option, print unexpanded variable values */
|
/* -dV: for the -V option, print unexpanded variable values */
|
||||||
@ -646,12 +715,16 @@ typedef struct CmdOpts {
|
|||||||
/* -i: if true, ignore all errors from shell commands */
|
/* -i: if true, ignore all errors from shell commands */
|
||||||
bool ignoreErrors;
|
bool ignoreErrors;
|
||||||
|
|
||||||
/* -j: the maximum number of jobs that can run in parallel;
|
/*
|
||||||
* this is coordinated with the submakes */
|
* -j: the maximum number of jobs that can run in parallel; this is
|
||||||
|
* coordinated with the submakes
|
||||||
|
*/
|
||||||
int maxJobs;
|
int maxJobs;
|
||||||
|
|
||||||
/* -k: if true and an error occurs while making a node, continue
|
/*
|
||||||
* making nodes that do not depend on the erroneous node */
|
* -k: if true and an error occurs while making a node, continue
|
||||||
|
* making nodes that do not depend on the erroneous node
|
||||||
|
*/
|
||||||
bool keepgoing;
|
bool keepgoing;
|
||||||
|
|
||||||
/* -N: execute no commands from the targets */
|
/* -N: execute no commands from the targets */
|
||||||
@ -664,17 +737,19 @@ typedef struct CmdOpts {
|
|||||||
* -q: if true, do not really make anything, just see if the targets
|
* -q: if true, do not really make anything, just see if the targets
|
||||||
* are out-of-date
|
* are out-of-date
|
||||||
*/
|
*/
|
||||||
bool queryFlag;
|
bool query;
|
||||||
|
|
||||||
/* -r: raw mode, do not load the builtin rules. */
|
/* -r: raw mode, do not load the builtin rules. */
|
||||||
bool noBuiltins;
|
bool noBuiltins;
|
||||||
|
|
||||||
/* -s: don't echo the shell commands before executing them */
|
/* -s: don't echo the shell commands before executing them */
|
||||||
bool beSilent;
|
bool silent;
|
||||||
|
|
||||||
/* -t: touch the targets if they are out-of-date, but don't actually
|
/*
|
||||||
* make them */
|
* -t: touch the targets if they are out-of-date, but don't actually
|
||||||
bool touchFlag;
|
* make them
|
||||||
|
*/
|
||||||
|
bool touch;
|
||||||
|
|
||||||
/* -[Vv]: print expanded or unexpanded selected variables */
|
/* -[Vv]: print expanded or unexpanded selected variables */
|
||||||
PrintVarsMode printVars;
|
PrintVarsMode printVars;
|
||||||
@ -687,90 +762,364 @@ typedef struct CmdOpts {
|
|||||||
/* -w: print 'Entering' and 'Leaving' for submakes */
|
/* -w: print 'Entering' and 'Leaving' for submakes */
|
||||||
bool enterFlag;
|
bool enterFlag;
|
||||||
|
|
||||||
/* -X: if true, do not export variables set on the command line to the
|
/*
|
||||||
* environment. */
|
* -X: if true, do not export variables set on the command line to
|
||||||
|
* the environment.
|
||||||
|
*/
|
||||||
bool varNoExportEnv;
|
bool varNoExportEnv;
|
||||||
|
|
||||||
/* The target names specified on the command line.
|
/*
|
||||||
* Used to resolve .if make(...) statements. */
|
* The target names specified on the command line. Used to resolve
|
||||||
|
* .if make(...) statements.
|
||||||
|
*/
|
||||||
StringList create;
|
StringList create;
|
||||||
|
|
||||||
} CmdOpts;
|
} CmdOpts;
|
||||||
|
|
||||||
extern CmdOpts opts;
|
extern CmdOpts opts;
|
||||||
|
|
||||||
#include "nonints.h"
|
/* arch.c */
|
||||||
|
void Arch_Init(void);
|
||||||
|
void Arch_End(void);
|
||||||
|
|
||||||
|
bool Arch_ParseArchive(char **, GNodeList *, GNode *);
|
||||||
|
void Arch_Touch(GNode *);
|
||||||
|
void Arch_TouchLib(GNode *);
|
||||||
|
void Arch_UpdateMTime(GNode *gn);
|
||||||
|
void Arch_UpdateMemberMTime(GNode *gn);
|
||||||
|
void Arch_FindLib(GNode *, SearchPath *);
|
||||||
|
bool Arch_LibOODate(GNode *) MAKE_ATTR_USE;
|
||||||
|
bool Arch_IsLib(GNode *) MAKE_ATTR_USE;
|
||||||
|
|
||||||
|
/* compat.c */
|
||||||
|
bool Compat_RunCommand(const char *, GNode *, StringListNode *);
|
||||||
|
void Compat_Run(GNodeList *);
|
||||||
|
void Compat_Make(GNode *, GNode *);
|
||||||
|
|
||||||
|
/* cond.c */
|
||||||
|
CondResult Cond_EvalCondition(const char *) MAKE_ATTR_USE;
|
||||||
|
CondResult Cond_EvalLine(const char *) MAKE_ATTR_USE;
|
||||||
|
void Cond_restore_depth(unsigned int);
|
||||||
|
unsigned int Cond_save_depth(void) MAKE_ATTR_USE;
|
||||||
|
|
||||||
|
/* dir.c; see also dir.h */
|
||||||
|
|
||||||
|
MAKE_INLINE const char * MAKE_ATTR_USE
|
||||||
|
str_basename(const char *pathname)
|
||||||
|
{
|
||||||
|
const char *lastSlash = strrchr(pathname, '/');
|
||||||
|
return lastSlash != NULL ? lastSlash + 1 : pathname;
|
||||||
|
}
|
||||||
|
|
||||||
|
MAKE_INLINE SearchPath * MAKE_ATTR_USE
|
||||||
|
SearchPath_New(void)
|
||||||
|
{
|
||||||
|
SearchPath *path = bmake_malloc(sizeof *path);
|
||||||
|
Lst_Init(&path->dirs);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchPath_Free(SearchPath *);
|
||||||
|
|
||||||
|
/* for.c */
|
||||||
|
struct ForLoop;
|
||||||
|
int For_Eval(const char *) MAKE_ATTR_USE;
|
||||||
|
bool For_Accum(const char *, int *) MAKE_ATTR_USE;
|
||||||
|
void For_Run(unsigned, unsigned);
|
||||||
|
bool For_NextIteration(struct ForLoop *, Buffer *);
|
||||||
|
char *ForLoop_Details(struct ForLoop *);
|
||||||
|
void ForLoop_Free(struct ForLoop *);
|
||||||
|
|
||||||
|
/* job.c */
|
||||||
|
void JobReapChild(pid_t, int, bool);
|
||||||
|
|
||||||
|
/* main.c */
|
||||||
|
void Main_ParseArgLine(const char *);
|
||||||
|
char *Cmd_Exec(const char *, char **) MAKE_ATTR_USE;
|
||||||
|
void Error(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
|
||||||
|
void Fatal(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2) MAKE_ATTR_DEAD;
|
||||||
|
void Punt(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2) MAKE_ATTR_DEAD;
|
||||||
|
void DieHorribly(void) MAKE_ATTR_DEAD;
|
||||||
|
void Finish(int) MAKE_ATTR_DEAD;
|
||||||
|
bool unlink_file(const char *) MAKE_ATTR_USE;
|
||||||
|
void execDie(const char *, const char *);
|
||||||
|
char *getTmpdir(void) MAKE_ATTR_USE;
|
||||||
|
bool ParseBoolean(const char *, bool) MAKE_ATTR_USE;
|
||||||
|
const char *cached_realpath(const char *, char *);
|
||||||
|
bool GetBooleanExpr(const char *, bool);
|
||||||
|
|
||||||
|
/* parse.c */
|
||||||
|
void Parse_Init(void);
|
||||||
|
void Parse_End(void);
|
||||||
|
|
||||||
|
void PrintLocation(FILE *, bool, const char *, unsigned);
|
||||||
|
void PrintStackTrace(bool);
|
||||||
|
void Parse_Error(ParseErrorLevel, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3);
|
||||||
|
bool Parse_VarAssign(const char *, bool, GNode *) MAKE_ATTR_USE;
|
||||||
|
void Parse_AddIncludeDir(const char *);
|
||||||
|
void Parse_File(const char *, int);
|
||||||
|
void Parse_PushInput(const char *, unsigned, unsigned, Buffer,
|
||||||
|
struct ForLoop *);
|
||||||
|
void Parse_MainName(GNodeList *);
|
||||||
|
int Parse_NumErrors(void) MAKE_ATTR_USE;
|
||||||
|
|
||||||
|
|
||||||
|
/* suff.c */
|
||||||
|
void Suff_Init(void);
|
||||||
|
void Suff_End(void);
|
||||||
|
|
||||||
|
void Suff_ClearSuffixes(void);
|
||||||
|
bool Suff_IsTransform(const char *) MAKE_ATTR_USE;
|
||||||
|
GNode *Suff_AddTransform(const char *);
|
||||||
|
void Suff_EndTransform(GNode *);
|
||||||
|
void Suff_AddSuffix(const char *);
|
||||||
|
SearchPath *Suff_GetPath(const char *) MAKE_ATTR_USE;
|
||||||
|
void Suff_ExtendPaths(void);
|
||||||
|
void Suff_AddInclude(const char *);
|
||||||
|
void Suff_AddLib(const char *);
|
||||||
|
void Suff_FindDeps(GNode *);
|
||||||
|
SearchPath *Suff_FindPath(GNode *) MAKE_ATTR_USE;
|
||||||
|
void Suff_SetNull(const char *);
|
||||||
|
void Suff_PrintAll(void);
|
||||||
|
char *Suff_NamesStr(void) MAKE_ATTR_USE;
|
||||||
|
|
||||||
|
/* targ.c */
|
||||||
|
void Targ_Init(void);
|
||||||
|
void Targ_End(void);
|
||||||
|
|
||||||
|
void Targ_Stats(void);
|
||||||
|
GNodeList *Targ_List(void) MAKE_ATTR_USE;
|
||||||
|
GNode *GNode_New(const char *) MAKE_ATTR_USE;
|
||||||
|
GNode *Targ_FindNode(const char *) MAKE_ATTR_USE;
|
||||||
|
GNode *Targ_GetNode(const char *) MAKE_ATTR_USE;
|
||||||
|
GNode *Targ_NewInternalNode(const char *) MAKE_ATTR_USE;
|
||||||
|
GNode *Targ_GetEndNode(void);
|
||||||
|
void Targ_FindList(GNodeList *, StringList *);
|
||||||
|
void Targ_PrintCmds(GNode *);
|
||||||
|
void Targ_PrintNode(GNode *, int);
|
||||||
|
void Targ_PrintNodes(GNodeList *, int);
|
||||||
|
const char *Targ_FmtTime(time_t) MAKE_ATTR_USE;
|
||||||
|
void Targ_PrintType(GNodeType);
|
||||||
|
void Targ_PrintGraph(int);
|
||||||
|
void Targ_Propagate(void);
|
||||||
|
const char *GNodeMade_Name(GNodeMade) MAKE_ATTR_USE;
|
||||||
|
|
||||||
|
/* var.c */
|
||||||
|
void Var_Init(void);
|
||||||
|
void Var_End(void);
|
||||||
|
|
||||||
|
typedef enum VarEvalMode {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only parse the expression but don't evaluate any part of it.
|
||||||
|
*
|
||||||
|
* TODO: Document what Var_Parse and Var_Subst return in this mode.
|
||||||
|
* As of 2021-03-15, they return unspecified, inconsistent results.
|
||||||
|
*/
|
||||||
|
VARE_PARSE_ONLY,
|
||||||
|
|
||||||
|
/* Parse and evaluate the expression. */
|
||||||
|
VARE_WANTRES,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse and evaluate the expression. It is an error if a
|
||||||
|
* subexpression evaluates to undefined.
|
||||||
|
*/
|
||||||
|
VARE_UNDEFERR,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse and evaluate the expression. Keep '$$' as '$$' instead of
|
||||||
|
* reducing it to a single '$'. Subexpressions that evaluate to
|
||||||
|
* undefined expand to an empty string.
|
||||||
|
*
|
||||||
|
* Used in variable assignments using the ':=' operator. It allows
|
||||||
|
* multiple such assignments to be chained without accidentally
|
||||||
|
* expanding '$$file' to '$file' in the first assignment and
|
||||||
|
* interpreting it as '${f}' followed by 'ile' in the next assignment.
|
||||||
|
*/
|
||||||
|
VARE_EVAL_KEEP_DOLLAR,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse and evaluate the expression. Keep undefined variables as-is
|
||||||
|
* instead of expanding them to an empty string.
|
||||||
|
*
|
||||||
|
* Example for a ':=' assignment:
|
||||||
|
* CFLAGS = $(.INCLUDES)
|
||||||
|
* CFLAGS := -I.. $(CFLAGS)
|
||||||
|
* # If .INCLUDES (an undocumented special variable, by the
|
||||||
|
* # way) is still undefined, the updated CFLAGS becomes
|
||||||
|
* # "-I.. $(.INCLUDES)".
|
||||||
|
*/
|
||||||
|
VARE_EVAL_KEEP_UNDEF,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse and evaluate the expression. Keep '$$' as '$$' and preserve
|
||||||
|
* undefined subexpressions.
|
||||||
|
*/
|
||||||
|
VARE_KEEP_DOLLAR_UNDEF
|
||||||
|
} VarEvalMode;
|
||||||
|
|
||||||
|
typedef enum VarSetFlags {
|
||||||
|
VAR_SET_NONE = 0,
|
||||||
|
|
||||||
|
/* do not export */
|
||||||
|
VAR_SET_NO_EXPORT = 1 << 0,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make the variable read-only. No further modification is possible,
|
||||||
|
* except for another call to Var_Set with the same flag.
|
||||||
|
*/
|
||||||
|
VAR_SET_READONLY = 1 << 1
|
||||||
|
} VarSetFlags;
|
||||||
|
|
||||||
|
/* The state of error handling returned by Var_Parse. */
|
||||||
|
typedef enum VarParseResult {
|
||||||
|
|
||||||
|
/* Both parsing and evaluation succeeded. */
|
||||||
|
VPR_OK,
|
||||||
|
|
||||||
|
/* Parsing or evaluating failed, with an error message. */
|
||||||
|
VPR_ERR,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parsing succeeded, undefined expressions are allowed and the
|
||||||
|
* expression was still undefined after applying all modifiers.
|
||||||
|
* No error message is printed in this case.
|
||||||
|
*
|
||||||
|
* Some callers handle this case differently, so return this
|
||||||
|
* information to them, for now.
|
||||||
|
*
|
||||||
|
* TODO: Instead of having this special return value, rather ensure
|
||||||
|
* that VARE_EVAL_KEEP_UNDEF is processed properly.
|
||||||
|
*/
|
||||||
|
VPR_UNDEF
|
||||||
|
|
||||||
|
} VarParseResult;
|
||||||
|
|
||||||
|
typedef enum VarExportMode {
|
||||||
|
/* .export-env */
|
||||||
|
VEM_ENV,
|
||||||
|
/* .export: Initial export or update an already exported variable. */
|
||||||
|
VEM_PLAIN,
|
||||||
|
/* .export-literal: Do not expand the variable value. */
|
||||||
|
VEM_LITERAL
|
||||||
|
} VarExportMode;
|
||||||
|
|
||||||
|
void Var_Delete(GNode *, const char *);
|
||||||
|
void Var_Undef(const char *);
|
||||||
|
void Var_Set(GNode *, const char *, const char *);
|
||||||
|
void Var_SetExpand(GNode *, const char *, const char *);
|
||||||
|
void Var_SetWithFlags(GNode *, const char *, const char *, VarSetFlags);
|
||||||
|
void Var_Append(GNode *, const char *, const char *);
|
||||||
|
void Var_AppendExpand(GNode *, const char *, const char *);
|
||||||
|
bool Var_Exists(GNode *, const char *) MAKE_ATTR_USE;
|
||||||
|
bool Var_ExistsExpand(GNode *, const char *) MAKE_ATTR_USE;
|
||||||
|
FStr Var_Value(GNode *, const char *) MAKE_ATTR_USE;
|
||||||
|
const char *GNode_ValueDirect(GNode *, const char *) MAKE_ATTR_USE;
|
||||||
|
VarParseResult Var_Parse(const char **, GNode *, VarEvalMode, FStr *);
|
||||||
|
VarParseResult Var_Subst(const char *, GNode *, VarEvalMode, char **);
|
||||||
|
void Var_Expand(FStr *, GNode *, VarEvalMode);
|
||||||
|
void Var_Stats(void);
|
||||||
|
void Var_Dump(GNode *);
|
||||||
|
void Var_ReexportVars(void);
|
||||||
|
void Var_Export(VarExportMode, const char *);
|
||||||
|
void Var_ExportVars(const char *);
|
||||||
|
void Var_UnExport(bool, const char *);
|
||||||
|
|
||||||
|
void Global_Set(const char *, const char *);
|
||||||
|
void Global_Append(const char *, const char *);
|
||||||
|
void Global_Delete(const char *);
|
||||||
|
|
||||||
|
/* util.c */
|
||||||
|
typedef void (*SignalProc)(int);
|
||||||
|
SignalProc bmake_signal(int, SignalProc);
|
||||||
|
|
||||||
|
/* make.c */
|
||||||
void GNode_UpdateYoungestChild(GNode *, GNode *);
|
void GNode_UpdateYoungestChild(GNode *, GNode *);
|
||||||
bool GNode_IsOODate(GNode *);
|
bool GNode_IsOODate(GNode *) MAKE_ATTR_USE;
|
||||||
void Make_ExpandUse(GNodeList *);
|
void Make_ExpandUse(GNodeList *);
|
||||||
time_t Make_Recheck(GNode *);
|
time_t Make_Recheck(GNode *) MAKE_ATTR_USE;
|
||||||
void Make_HandleUse(GNode *, GNode *);
|
void Make_HandleUse(GNode *, GNode *);
|
||||||
void Make_Update(GNode *);
|
void Make_Update(GNode *);
|
||||||
void GNode_SetLocalVars(GNode *);
|
void GNode_SetLocalVars(GNode *);
|
||||||
bool Make_Run(GNodeList *);
|
bool Make_Run(GNodeList *);
|
||||||
bool shouldDieQuietly(GNode *, int);
|
bool shouldDieQuietly(GNode *, int) MAKE_ATTR_USE;
|
||||||
void PrintOnError(GNode *, const char *);
|
void PrintOnError(GNode *, const char *);
|
||||||
void Main_ExportMAKEFLAGS(bool);
|
void Main_ExportMAKEFLAGS(bool);
|
||||||
bool Main_SetObjdir(bool, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3);
|
bool Main_SetObjdir(bool, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3);
|
||||||
int mkTempFile(const char *, char *, size_t);
|
int mkTempFile(const char *, char *, size_t) MAKE_ATTR_USE;
|
||||||
int str2Lst_Append(StringList *, char *);
|
int str2Lst_Append(StringList *, char *);
|
||||||
void GNode_FprintDetails(FILE *, const char *, const GNode *, const char *);
|
void GNode_FprintDetails(FILE *, const char *, const GNode *, const char *);
|
||||||
bool GNode_ShouldExecute(GNode *gn);
|
bool GNode_ShouldExecute(GNode *gn) MAKE_ATTR_USE;
|
||||||
|
|
||||||
/* See if the node was seen on the left-hand side of a dependency operator. */
|
/* See if the node was seen on the left-hand side of a dependency operator. */
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
GNode_IsTarget(const GNode *gn)
|
GNode_IsTarget(const GNode *gn)
|
||||||
{
|
{
|
||||||
return (gn->type & OP_OPMASK) != OP_NONE;
|
return (gn->type & OP_OPMASK) != OP_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
MAKE_INLINE const char *
|
MAKE_INLINE const char * MAKE_ATTR_USE
|
||||||
GNode_Path(const GNode *gn)
|
GNode_Path(const GNode *gn)
|
||||||
{
|
{
|
||||||
return gn->path != NULL ? gn->path : gn->name;
|
return gn->path != NULL ? gn->path : gn->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
GNode_IsWaitingFor(const GNode *gn)
|
GNode_IsWaitingFor(const GNode *gn)
|
||||||
{
|
{
|
||||||
return gn->flags.remake && gn->made <= REQUESTED;
|
return gn->flags.remake && gn->made <= REQUESTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
GNode_IsReady(const GNode *gn)
|
GNode_IsReady(const GNode *gn)
|
||||||
{
|
{
|
||||||
return gn->made > DEFERRED;
|
return gn->made > DEFERRED;
|
||||||
}
|
}
|
||||||
|
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
GNode_IsDone(const GNode *gn)
|
GNode_IsDone(const GNode *gn)
|
||||||
{
|
{
|
||||||
return gn->made >= MADE;
|
return gn->made >= MADE;
|
||||||
}
|
}
|
||||||
|
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
GNode_IsError(const GNode *gn)
|
GNode_IsError(const GNode *gn)
|
||||||
{
|
{
|
||||||
return gn->made == ERROR || gn->made == ABORTED;
|
return gn->made == ERROR || gn->made == ABORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
MAKE_INLINE const char *
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
|
GNode_IsMainCandidate(const GNode *gn)
|
||||||
|
{
|
||||||
|
return (gn->type & (OP_NOTMAIN | OP_USE | OP_USEBEFORE |
|
||||||
|
OP_EXEC | OP_TRANSFORM)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return whether the target file should be preserved on interrupt. */
|
||||||
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
|
GNode_IsPrecious(const GNode *gn)
|
||||||
|
{
|
||||||
|
/* XXX: Why are '::' targets precious? */
|
||||||
|
return allPrecious || gn->type & (OP_PRECIOUS | OP_DOUBLEDEP);
|
||||||
|
}
|
||||||
|
|
||||||
|
MAKE_INLINE const char * MAKE_ATTR_USE
|
||||||
GNode_VarTarget(GNode *gn) { return GNode_ValueDirect(gn, TARGET); }
|
GNode_VarTarget(GNode *gn) { return GNode_ValueDirect(gn, TARGET); }
|
||||||
MAKE_INLINE const char *
|
MAKE_INLINE const char * MAKE_ATTR_USE
|
||||||
GNode_VarOodate(GNode *gn) { return GNode_ValueDirect(gn, OODATE); }
|
GNode_VarOodate(GNode *gn) { return GNode_ValueDirect(gn, OODATE); }
|
||||||
MAKE_INLINE const char *
|
MAKE_INLINE const char * MAKE_ATTR_USE
|
||||||
GNode_VarAllsrc(GNode *gn) { return GNode_ValueDirect(gn, ALLSRC); }
|
GNode_VarAllsrc(GNode *gn) { return GNode_ValueDirect(gn, ALLSRC); }
|
||||||
MAKE_INLINE const char *
|
MAKE_INLINE const char * MAKE_ATTR_USE
|
||||||
GNode_VarImpsrc(GNode *gn) { return GNode_ValueDirect(gn, IMPSRC); }
|
GNode_VarImpsrc(GNode *gn) { return GNode_ValueDirect(gn, IMPSRC); }
|
||||||
MAKE_INLINE const char *
|
MAKE_INLINE const char * MAKE_ATTR_USE
|
||||||
GNode_VarPrefix(GNode *gn) { return GNode_ValueDirect(gn, PREFIX); }
|
GNode_VarPrefix(GNode *gn) { return GNode_ValueDirect(gn, PREFIX); }
|
||||||
MAKE_INLINE const char *
|
MAKE_INLINE const char * MAKE_ATTR_USE
|
||||||
GNode_VarArchive(GNode *gn) { return GNode_ValueDirect(gn, ARCHIVE); }
|
GNode_VarArchive(GNode *gn) { return GNode_ValueDirect(gn, ARCHIVE); }
|
||||||
MAKE_INLINE const char *
|
MAKE_INLINE const char * MAKE_ATTR_USE
|
||||||
GNode_VarMember(GNode *gn) { return GNode_ValueDirect(gn, MEMBER); }
|
GNode_VarMember(GNode *gn) { return GNode_ValueDirect(gn, MEMBER); }
|
||||||
|
|
||||||
MAKE_INLINE void *
|
MAKE_INLINE void * MAKE_ATTR_USE
|
||||||
UNCONST(const void *ptr)
|
UNCONST(const void *ptr)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
@ -795,19 +1144,21 @@ UNCONST(const void *ptr)
|
|||||||
#define KILLPG(pid, sig) killpg((pid), (sig))
|
#define KILLPG(pid, sig) killpg((pid), (sig))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
ch_isalnum(char ch) { return isalnum((unsigned char)ch) != 0; }
|
ch_isalnum(char ch) { return isalnum((unsigned char)ch) != 0; }
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
ch_isalpha(char ch) { return isalpha((unsigned char)ch) != 0; }
|
ch_isalpha(char ch) { return isalpha((unsigned char)ch) != 0; }
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
ch_isdigit(char ch) { return isdigit((unsigned char)ch) != 0; }
|
ch_isdigit(char ch) { return isdigit((unsigned char)ch) != 0; }
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
|
ch_islower(char ch) { return islower((unsigned char)ch) != 0; }
|
||||||
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
ch_isspace(char ch) { return isspace((unsigned char)ch) != 0; }
|
ch_isspace(char ch) { return isspace((unsigned char)ch) != 0; }
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
ch_isupper(char ch) { return isupper((unsigned char)ch) != 0; }
|
ch_isupper(char ch) { return isupper((unsigned char)ch) != 0; }
|
||||||
MAKE_INLINE char
|
MAKE_INLINE char MAKE_ATTR_USE
|
||||||
ch_tolower(char ch) { return (char)tolower((unsigned char)ch); }
|
ch_tolower(char ch) { return (char)tolower((unsigned char)ch); }
|
||||||
MAKE_INLINE char
|
MAKE_INLINE char MAKE_ATTR_USE
|
||||||
ch_toupper(char ch) { return (char)toupper((unsigned char)ch); }
|
ch_toupper(char ch) { return (char)toupper((unsigned char)ch); }
|
||||||
|
|
||||||
MAKE_INLINE void
|
MAKE_INLINE void
|
||||||
@ -824,6 +1175,17 @@ cpp_skip_hspace(const char **pp)
|
|||||||
(*pp)++;
|
(*pp)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MAKE_INLINE bool
|
||||||
|
cpp_skip_string(const char **pp, const char *s)
|
||||||
|
{
|
||||||
|
const char *p = *pp;
|
||||||
|
while (*p == *s && *s != '\0')
|
||||||
|
p++, s++;
|
||||||
|
if (*s == '\0')
|
||||||
|
*pp = p;
|
||||||
|
return *s == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
MAKE_INLINE void
|
MAKE_INLINE void
|
||||||
pp_skip_whitespace(char **pp)
|
pp_skip_whitespace(char **pp)
|
||||||
{
|
{
|
||||||
@ -863,4 +1225,4 @@ pp_skip_hspace(char **pp)
|
|||||||
# define MAKE_RCSID(id) static volatile char rcsid[] = id
|
# define MAKE_RCSID(id) static volatile char rcsid[] = id
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* MAKE_MAKE_H */
|
#endif
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: make_malloc.c,v 1.25 2021/01/19 20:51:46 rillig Exp $ */
|
/* $NetBSD: make_malloc.c,v 1.26 2022/01/07 08:30:04 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2009 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||||
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
#include "make.h"
|
#include "make.h"
|
||||||
|
|
||||||
MAKE_RCSID("$NetBSD: make_malloc.c,v 1.25 2021/01/19 20:51:46 rillig Exp $");
|
MAKE_RCSID("$NetBSD: make_malloc.c,v 1.26 2022/01/07 08:30:04 rillig Exp $");
|
||||||
|
|
||||||
#ifndef USE_EMALLOC
|
#ifndef USE_EMALLOC
|
||||||
|
|
||||||
@ -57,12 +57,12 @@ bmake_malloc(size_t len)
|
|||||||
char *
|
char *
|
||||||
bmake_strdup(const char *str)
|
bmake_strdup(const char *str)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t size;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
len = strlen(str) + 1;
|
size = strlen(str) + 1;
|
||||||
p = bmake_malloc(len);
|
p = bmake_malloc(size);
|
||||||
return memcpy(p, str, len);
|
return memcpy(p, str, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate a string starting from str with exactly len characters. */
|
/* Allocate a string starting from str with exactly len characters. */
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: make_malloc.h,v 1.16 2021/01/19 20:51:46 rillig Exp $ */
|
/* $NetBSD: make_malloc.h,v 1.18 2021/12/15 11:01:39 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2009 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||||
@ -27,10 +27,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef USE_EMALLOC
|
#ifndef USE_EMALLOC
|
||||||
void *bmake_malloc(size_t);
|
void *bmake_malloc(size_t) MAKE_ATTR_USE;
|
||||||
void *bmake_realloc(void *, size_t);
|
void *bmake_realloc(void *, size_t) MAKE_ATTR_USE;
|
||||||
char *bmake_strdup(const char *);
|
char *bmake_strdup(const char *) MAKE_ATTR_USE;
|
||||||
char *bmake_strldup(const char *, size_t);
|
char *bmake_strldup(const char *, size_t) MAKE_ATTR_USE;
|
||||||
#else
|
#else
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
#define bmake_malloc(n) emalloc(n)
|
#define bmake_malloc(n) emalloc(n)
|
||||||
@ -39,18 +39,4 @@ char *bmake_strldup(const char *, size_t);
|
|||||||
#define bmake_strldup(s, n) estrndup(s, n)
|
#define bmake_strldup(s, n) estrndup(s, n)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char *bmake_strsedup(const char *, const char *);
|
char *bmake_strsedup(const char *, const char *) MAKE_ATTR_USE;
|
||||||
|
|
||||||
/*
|
|
||||||
* Thin wrapper around free(3) to avoid the extra function call in case
|
|
||||||
* p is NULL, to save a few machine instructions.
|
|
||||||
*
|
|
||||||
* The case of a NULL pointer happens especially often after Var_Value,
|
|
||||||
* since only environment variables need to be freed, but not others.
|
|
||||||
*/
|
|
||||||
MAKE_INLINE void
|
|
||||||
bmake_free(void *p)
|
|
||||||
{
|
|
||||||
if (p != NULL)
|
|
||||||
free(p);
|
|
||||||
}
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: meta.c,v 1.185 2021/11/27 22:04:02 rillig Exp $ */
|
/* $NetBSD: meta.c,v 1.196 2022/02/04 23:22:19 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implement 'meta' mode.
|
* Implement 'meta' mode.
|
||||||
@ -69,6 +69,9 @@ static char *metaIgnorePathsStr; /* string storage for the list */
|
|||||||
#ifndef MAKE_META_IGNORE_FILTER
|
#ifndef MAKE_META_IGNORE_FILTER
|
||||||
#define MAKE_META_IGNORE_FILTER ".MAKE.META.IGNORE_FILTER"
|
#define MAKE_META_IGNORE_FILTER ".MAKE.META.IGNORE_FILTER"
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef MAKE_META_CMP_FILTER
|
||||||
|
#define MAKE_META_CMP_FILTER ".MAKE.META.CMP_FILTER"
|
||||||
|
#endif
|
||||||
|
|
||||||
bool useMeta = false;
|
bool useMeta = false;
|
||||||
static bool useFilemon = false;
|
static bool useFilemon = false;
|
||||||
@ -80,6 +83,7 @@ static bool metaVerbose = false;
|
|||||||
static bool metaIgnoreCMDs = false; /* ignore CMDs in .meta files */
|
static bool metaIgnoreCMDs = false; /* ignore CMDs in .meta files */
|
||||||
static bool metaIgnorePatterns = false; /* do we need to do pattern matches */
|
static bool metaIgnorePatterns = false; /* do we need to do pattern matches */
|
||||||
static bool metaIgnoreFilter = false; /* do we have more complex filtering? */
|
static bool metaIgnoreFilter = false; /* do we have more complex filtering? */
|
||||||
|
static bool metaCmpFilter = false; /* do we have CMP_FILTER ? */
|
||||||
static bool metaCurdirOk = false; /* write .meta in .CURDIR Ok? */
|
static bool metaCurdirOk = false; /* write .meta in .CURDIR Ok? */
|
||||||
static bool metaSilent = false; /* if we have a .meta be SILENT */
|
static bool metaSilent = false; /* if we have a .meta be SILENT */
|
||||||
|
|
||||||
@ -208,42 +212,25 @@ filemon_read(FILE *mfp, int fd)
|
|||||||
* we use this, to clean up ./ and ../
|
* we use this, to clean up ./ and ../
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
eat_dots(char *buf, size_t bufsz, int dots)
|
eat_dots(char *buf)
|
||||||
{
|
{
|
||||||
char *cp;
|
char *p;
|
||||||
char *cp2;
|
|
||||||
const char *eat;
|
|
||||||
size_t eatlen;
|
|
||||||
|
|
||||||
switch (dots) {
|
while ((p = strstr(buf, "/./")) != NULL)
|
||||||
case 1:
|
memmove(p, p + 2, strlen(p + 2) + 1);
|
||||||
eat = "/./";
|
|
||||||
eatlen = 2;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
eat = "/../";
|
|
||||||
eatlen = 3;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
while ((p = strstr(buf, "/../")) != NULL) {
|
||||||
cp = strstr(buf, eat);
|
char *p2 = p + 3;
|
||||||
if (cp != NULL) {
|
if (p > buf) {
|
||||||
cp2 = cp + eatlen;
|
do {
|
||||||
if (dots == 2 && cp > buf) {
|
p--;
|
||||||
do {
|
} while (p > buf && *p != '/');
|
||||||
cp--;
|
|
||||||
} while (cp > buf && *cp != '/');
|
|
||||||
}
|
|
||||||
if (*cp == '/') {
|
|
||||||
strlcpy(cp, cp2, bufsz - (size_t)(cp - buf));
|
|
||||||
} else {
|
|
||||||
return; /* can't happen? */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} while (cp != NULL);
|
if (*p == '/')
|
||||||
|
memmove(p, p2, strlen(p2) + 1);
|
||||||
|
else
|
||||||
|
return; /* can't happen? */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
@ -287,8 +274,7 @@ meta_name(char *mname, size_t mnamelen,
|
|||||||
} else {
|
} else {
|
||||||
snprintf(buf, sizeof buf, "%s/%s", cwd, tname);
|
snprintf(buf, sizeof buf, "%s/%s", cwd, tname);
|
||||||
}
|
}
|
||||||
eat_dots(buf, sizeof buf, 1); /* ./ */
|
eat_dots(buf);
|
||||||
eat_dots(buf, sizeof buf, 2); /* ../ */
|
|
||||||
tname = buf;
|
tname = buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -330,15 +316,14 @@ is_submake(const char *cmd, GNode *gn)
|
|||||||
static const char *p_make = NULL;
|
static const char *p_make = NULL;
|
||||||
static size_t p_len;
|
static size_t p_len;
|
||||||
char *mp = NULL;
|
char *mp = NULL;
|
||||||
const char *cp, *cp2;
|
const char *cp2;
|
||||||
bool rc = false;
|
bool rc = false;
|
||||||
|
|
||||||
if (p_make == NULL) {
|
if (p_make == NULL) {
|
||||||
p_make = Var_Value(gn, ".MAKE").str;
|
p_make = Var_Value(gn, ".MAKE").str;
|
||||||
p_len = strlen(p_make);
|
p_len = strlen(p_make);
|
||||||
}
|
}
|
||||||
cp = strchr(cmd, '$');
|
if (strchr(cmd, '$') != NULL) {
|
||||||
if (cp != NULL) {
|
|
||||||
(void)Var_Subst(cmd, gn, VARE_WANTRES, &mp);
|
(void)Var_Subst(cmd, gn, VARE_WANTRES, &mp);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
cmd = mp;
|
cmd = mp;
|
||||||
@ -385,13 +370,7 @@ printCMD(const char *ucmd, FILE *fp, GNode *gn)
|
|||||||
{
|
{
|
||||||
FStr xcmd = FStr_InitRefer(ucmd);
|
FStr xcmd = FStr_InitRefer(ucmd);
|
||||||
|
|
||||||
if (strchr(ucmd, '$') != NULL) {
|
Var_Expand(&xcmd, gn, VARE_WANTRES);
|
||||||
char *expanded;
|
|
||||||
(void)Var_Subst(ucmd, gn, VARE_WANTRES, &expanded);
|
|
||||||
/* TODO: handle errors */
|
|
||||||
xcmd = FStr_InitOwn(expanded);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "CMD %s\n", xcmd.str);
|
fprintf(fp, "CMD %s\n", xcmd.str);
|
||||||
FStr_Done(&xcmd);
|
FStr_Done(&xcmd);
|
||||||
}
|
}
|
||||||
@ -601,7 +580,6 @@ meta_mode_init(const char *make_mode)
|
|||||||
{
|
{
|
||||||
static bool once = false;
|
static bool once = false;
|
||||||
const char *cp;
|
const char *cp;
|
||||||
FStr value;
|
|
||||||
|
|
||||||
useMeta = true;
|
useMeta = true;
|
||||||
useFilemon = true;
|
useFilemon = true;
|
||||||
@ -658,16 +636,9 @@ meta_mode_init(const char *make_mode)
|
|||||||
/*
|
/*
|
||||||
* We ignore any paths that match ${.MAKE.META.IGNORE_PATTERNS}
|
* We ignore any paths that match ${.MAKE.META.IGNORE_PATTERNS}
|
||||||
*/
|
*/
|
||||||
value = Var_Value(SCOPE_GLOBAL, MAKE_META_IGNORE_PATTERNS);
|
metaIgnorePatterns = Var_Exists(SCOPE_GLOBAL, MAKE_META_IGNORE_PATTERNS);
|
||||||
if (value.str != NULL) {
|
metaIgnoreFilter = Var_Exists(SCOPE_GLOBAL, MAKE_META_IGNORE_FILTER);
|
||||||
metaIgnorePatterns = true;
|
metaCmpFilter = Var_Exists(SCOPE_GLOBAL, MAKE_META_CMP_FILTER);
|
||||||
FStr_Done(&value);
|
|
||||||
}
|
|
||||||
value = Var_Value(SCOPE_GLOBAL, MAKE_META_IGNORE_FILTER);
|
|
||||||
if (value.str != NULL) {
|
|
||||||
metaIgnoreFilter = true;
|
|
||||||
FStr_Done(&value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1061,7 +1032,7 @@ meta_ignore(GNode *gn, const char *p)
|
|||||||
* Setting oodate true will have that effect.
|
* Setting oodate true will have that effect.
|
||||||
*/
|
*/
|
||||||
#define CHECK_VALID_META(p) if (!(p != NULL && *p != '\0')) { \
|
#define CHECK_VALID_META(p) if (!(p != NULL && *p != '\0')) { \
|
||||||
warnx("%s: %d: malformed", fname, lineno); \
|
warnx("%s: %u: malformed", fname, lineno); \
|
||||||
oodate = true; \
|
oodate = true; \
|
||||||
continue; \
|
continue; \
|
||||||
}
|
}
|
||||||
@ -1084,6 +1055,39 @@ append_if_new(StringList *list, const char *str)
|
|||||||
Lst_Append(list, bmake_strdup(str));
|
Lst_Append(list, bmake_strdup(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
meta_filter_cmd(Buffer *buf, GNode *gn, char *s)
|
||||||
|
{
|
||||||
|
Buf_Clear(buf);
|
||||||
|
Buf_AddStr(buf, "${");
|
||||||
|
Buf_AddStr(buf, s);
|
||||||
|
Buf_AddStr(buf, ":L:${" MAKE_META_CMP_FILTER ":ts:}}");
|
||||||
|
Var_Subst(buf->data, gn, VARE_WANTRES, &s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
meta_cmd_cmp(GNode *gn, char *a, char *b, bool filter)
|
||||||
|
{
|
||||||
|
static bool once = false;
|
||||||
|
static Buffer buf;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = strcmp(a, b);
|
||||||
|
if (rc == 0 || !filter)
|
||||||
|
return rc;
|
||||||
|
if (!once) {
|
||||||
|
once = true;
|
||||||
|
Buf_Init(&buf);
|
||||||
|
}
|
||||||
|
a = meta_filter_cmd(&buf, gn, a);
|
||||||
|
b = meta_filter_cmd(&buf, gn, b);
|
||||||
|
rc = strcmp(a, b);
|
||||||
|
free(a);
|
||||||
|
free(b);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
meta_oodate(GNode *gn, bool oodate)
|
meta_oodate(GNode *gn, bool oodate)
|
||||||
{
|
{
|
||||||
@ -1108,6 +1112,7 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
bool needOODATE = false;
|
bool needOODATE = false;
|
||||||
StringList missingFiles;
|
StringList missingFiles;
|
||||||
bool have_filemon = false;
|
bool have_filemon = false;
|
||||||
|
bool cmp_filter;
|
||||||
|
|
||||||
if (oodate)
|
if (oodate)
|
||||||
return oodate; /* we're done */
|
return oodate; /* we're done */
|
||||||
@ -1139,7 +1144,7 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
if ((fp = fopen(fname, "r")) != NULL) {
|
if ((fp = fopen(fname, "r")) != NULL) {
|
||||||
static char *buf = NULL;
|
static char *buf = NULL;
|
||||||
static size_t bufsz;
|
static size_t bufsz;
|
||||||
int lineno = 0;
|
unsigned lineno = 0;
|
||||||
int lastpid = 0;
|
int lastpid = 0;
|
||||||
int pid;
|
int pid;
|
||||||
int x;
|
int x;
|
||||||
@ -1167,13 +1172,16 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
/* we want to track all the .meta we read */
|
/* we want to track all the .meta we read */
|
||||||
Global_Append(".MAKE.META.FILES", fname);
|
Global_Append(".MAKE.META.FILES", fname);
|
||||||
|
|
||||||
|
cmp_filter = metaCmpFilter ? metaCmpFilter :
|
||||||
|
Var_Exists(gn, MAKE_META_CMP_FILTER);
|
||||||
|
|
||||||
cmdNode = gn->commands.first;
|
cmdNode = gn->commands.first;
|
||||||
while (!oodate && (x = fgetLine(&buf, &bufsz, 0, fp)) > 0) {
|
while (!oodate && (x = fgetLine(&buf, &bufsz, 0, fp)) > 0) {
|
||||||
lineno++;
|
lineno++;
|
||||||
if (buf[x - 1] == '\n')
|
if (buf[x - 1] == '\n')
|
||||||
buf[x - 1] = '\0';
|
buf[x - 1] = '\0';
|
||||||
else {
|
else {
|
||||||
warnx("%s: %d: line truncated at %u", fname, lineno, x);
|
warnx("%s: %u: line truncated at %u", fname, lineno, x);
|
||||||
oodate = true;
|
oodate = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1194,7 +1202,7 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
/* Delimit the record type. */
|
/* Delimit the record type. */
|
||||||
p = buf;
|
p = buf;
|
||||||
#ifdef DEBUG_META_MODE
|
#ifdef DEBUG_META_MODE
|
||||||
DEBUG3(META, "%s: %d: %s\n", fname, lineno, buf);
|
DEBUG3(META, "%s: %u: %s\n", fname, lineno, buf);
|
||||||
#endif
|
#endif
|
||||||
strsep(&p, " ");
|
strsep(&p, " ");
|
||||||
if (have_filemon) {
|
if (have_filemon) {
|
||||||
@ -1240,8 +1248,8 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
|
|
||||||
if (lastpid > 0) {
|
if (lastpid > 0) {
|
||||||
/* We need to remember these. */
|
/* We need to remember these. */
|
||||||
Global_SetExpand(lcwd_vname, lcwd);
|
Global_Set(lcwd_vname, lcwd);
|
||||||
Global_SetExpand(ldir_vname, latestdir);
|
Global_Set(ldir_vname, latestdir);
|
||||||
}
|
}
|
||||||
snprintf(lcwd_vname, sizeof lcwd_vname, LCWD_VNAME_FMT, pid);
|
snprintf(lcwd_vname, sizeof lcwd_vname, LCWD_VNAME_FMT, pid);
|
||||||
snprintf(ldir_vname, sizeof ldir_vname, LDIR_VNAME_FMT, pid);
|
snprintf(ldir_vname, sizeof ldir_vname, LDIR_VNAME_FMT, pid);
|
||||||
@ -1262,7 +1270,7 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
continue;
|
continue;
|
||||||
#ifdef DEBUG_META_MODE
|
#ifdef DEBUG_META_MODE
|
||||||
if (DEBUG(META))
|
if (DEBUG(META))
|
||||||
debug_printf("%s: %d: %d: %c: cwd=%s lcwd=%s ldir=%s\n",
|
debug_printf("%s: %u: %d: %c: cwd=%s lcwd=%s ldir=%s\n",
|
||||||
fname, lineno,
|
fname, lineno,
|
||||||
pid, buf[0], cwd, lcwd, latestdir);
|
pid, buf[0], cwd, lcwd, latestdir);
|
||||||
#endif
|
#endif
|
||||||
@ -1274,8 +1282,8 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
/* Process according to record type. */
|
/* Process according to record type. */
|
||||||
switch (buf[0]) {
|
switch (buf[0]) {
|
||||||
case 'X': /* eXit */
|
case 'X': /* eXit */
|
||||||
Var_DeleteExpand(SCOPE_GLOBAL, lcwd_vname);
|
Var_Delete(SCOPE_GLOBAL, lcwd_vname);
|
||||||
Var_DeleteExpand(SCOPE_GLOBAL, ldir_vname);
|
Var_Delete(SCOPE_GLOBAL, ldir_vname);
|
||||||
lastpid = 0; /* no need to save ldir_vname */
|
lastpid = 0; /* no need to save ldir_vname */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1287,13 +1295,13 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
child = atoi(p);
|
child = atoi(p);
|
||||||
if (child > 0) {
|
if (child > 0) {
|
||||||
snprintf(cldir, sizeof cldir, LCWD_VNAME_FMT, child);
|
snprintf(cldir, sizeof cldir, LCWD_VNAME_FMT, child);
|
||||||
Global_SetExpand(cldir, lcwd);
|
Global_Set(cldir, lcwd);
|
||||||
snprintf(cldir, sizeof cldir, LDIR_VNAME_FMT, child);
|
snprintf(cldir, sizeof cldir, LDIR_VNAME_FMT, child);
|
||||||
Global_SetExpand(cldir, latestdir);
|
Global_Set(cldir, latestdir);
|
||||||
#ifdef DEBUG_META_MODE
|
#ifdef DEBUG_META_MODE
|
||||||
if (DEBUG(META))
|
if (DEBUG(META))
|
||||||
debug_printf(
|
debug_printf(
|
||||||
"%s: %d: %d: cwd=%s lcwd=%s ldir=%s\n",
|
"%s: %u: %d: cwd=%s lcwd=%s ldir=%s\n",
|
||||||
fname, lineno,
|
fname, lineno,
|
||||||
child, cwd, lcwd, latestdir);
|
child, cwd, lcwd, latestdir);
|
||||||
#endif
|
#endif
|
||||||
@ -1305,10 +1313,10 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
/* Update lcwd and latest directory. */
|
/* Update lcwd and latest directory. */
|
||||||
strlcpy(latestdir, p, sizeof latestdir);
|
strlcpy(latestdir, p, sizeof latestdir);
|
||||||
strlcpy(lcwd, p, sizeof lcwd);
|
strlcpy(lcwd, p, sizeof lcwd);
|
||||||
Global_SetExpand(lcwd_vname, lcwd);
|
Global_Set(lcwd_vname, lcwd);
|
||||||
Global_SetExpand(ldir_vname, lcwd);
|
Global_Set(ldir_vname, lcwd);
|
||||||
#ifdef DEBUG_META_MODE
|
#ifdef DEBUG_META_MODE
|
||||||
DEBUG4(META, "%s: %d: cwd=%s ldir=%s\n",
|
DEBUG4(META, "%s: %u: cwd=%s ldir=%s\n",
|
||||||
fname, lineno, cwd, lcwd);
|
fname, lineno, cwd, lcwd);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
@ -1461,7 +1469,7 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
|
|
||||||
for (sdp = sdirs; *sdp != NULL && !found; sdp++) {
|
for (sdp = sdirs; *sdp != NULL && !found; sdp++) {
|
||||||
#ifdef DEBUG_META_MODE
|
#ifdef DEBUG_META_MODE
|
||||||
DEBUG3(META, "%s: %d: looking for: %s\n",
|
DEBUG3(META, "%s: %u: looking for: %s\n",
|
||||||
fname, lineno, *sdp);
|
fname, lineno, *sdp);
|
||||||
#endif
|
#endif
|
||||||
if (cached_stat(*sdp, &cst) == 0) {
|
if (cached_stat(*sdp, &cst) == 0) {
|
||||||
@ -1471,12 +1479,12 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
}
|
}
|
||||||
if (found) {
|
if (found) {
|
||||||
#ifdef DEBUG_META_MODE
|
#ifdef DEBUG_META_MODE
|
||||||
DEBUG3(META, "%s: %d: found: %s\n",
|
DEBUG3(META, "%s: %u: found: %s\n",
|
||||||
fname, lineno, p);
|
fname, lineno, p);
|
||||||
#endif
|
#endif
|
||||||
if (!S_ISDIR(cst.cst_mode) &&
|
if (!S_ISDIR(cst.cst_mode) &&
|
||||||
cst.cst_mtime > gn->mtime) {
|
cst.cst_mtime > gn->mtime) {
|
||||||
DEBUG3(META, "%s: %d: file '%s' is newer than the target...\n",
|
DEBUG3(META, "%s: %u: file '%s' is newer than the target...\n",
|
||||||
fname, lineno, p);
|
fname, lineno, p);
|
||||||
oodate = true;
|
oodate = true;
|
||||||
} else if (S_ISDIR(cst.cst_mode)) {
|
} else if (S_ISDIR(cst.cst_mode)) {
|
||||||
@ -1508,7 +1516,7 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
* meta data file.
|
* meta data file.
|
||||||
*/
|
*/
|
||||||
if (cmdNode == NULL) {
|
if (cmdNode == NULL) {
|
||||||
DEBUG2(META, "%s: %d: there were more build commands in the meta data file than there are now...\n",
|
DEBUG2(META, "%s: %u: there were more build commands in the meta data file than there are now...\n",
|
||||||
fname, lineno);
|
fname, lineno);
|
||||||
oodate = true;
|
oodate = true;
|
||||||
} else {
|
} else {
|
||||||
@ -1525,7 +1533,7 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
}
|
}
|
||||||
if (hasOODATE) {
|
if (hasOODATE) {
|
||||||
needOODATE = true;
|
needOODATE = true;
|
||||||
DEBUG2(META, "%s: %d: cannot compare command using .OODATE\n",
|
DEBUG2(META, "%s: %u: cannot compare command using .OODATE\n",
|
||||||
fname, lineno);
|
fname, lineno);
|
||||||
}
|
}
|
||||||
(void)Var_Subst(cmd, gn, VARE_UNDEFERR, &cmd);
|
(void)Var_Subst(cmd, gn, VARE_UNDEFERR, &cmd);
|
||||||
@ -1548,7 +1556,7 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
x = n;
|
x = n;
|
||||||
lineno++;
|
lineno++;
|
||||||
if (buf[x - 1] != '\n') {
|
if (buf[x - 1] != '\n') {
|
||||||
warnx("%s: %d: line truncated at %u", fname, lineno, x);
|
warnx("%s: %u: line truncated at %u", fname, lineno, x);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cp = strchr(cp + 1, '\n');
|
cp = strchr(cp + 1, '\n');
|
||||||
@ -1559,8 +1567,8 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
if (p != NULL &&
|
if (p != NULL &&
|
||||||
!hasOODATE &&
|
!hasOODATE &&
|
||||||
!(gn->type & OP_NOMETA_CMP) &&
|
!(gn->type & OP_NOMETA_CMP) &&
|
||||||
(strcmp(p, cmd) != 0)) {
|
(meta_cmd_cmp(gn, p, cmd, cmp_filter) != 0)) {
|
||||||
DEBUG4(META, "%s: %d: a build command has changed\n%s\nvs\n%s\n",
|
DEBUG4(META, "%s: %u: a build command has changed\n%s\nvs\n%s\n",
|
||||||
fname, lineno, p, cmd);
|
fname, lineno, p, cmd);
|
||||||
if (!metaIgnoreCMDs)
|
if (!metaIgnoreCMDs)
|
||||||
oodate = true;
|
oodate = true;
|
||||||
@ -1574,13 +1582,13 @@ meta_oodate(GNode *gn, bool oodate)
|
|||||||
* that weren't in the meta data file.
|
* that weren't in the meta data file.
|
||||||
*/
|
*/
|
||||||
if (!oodate && cmdNode != NULL) {
|
if (!oodate && cmdNode != NULL) {
|
||||||
DEBUG2(META, "%s: %d: there are extra build commands now that weren't in the meta data file\n",
|
DEBUG2(META, "%s: %u: there are extra build commands now that weren't in the meta data file\n",
|
||||||
fname, lineno);
|
fname, lineno);
|
||||||
oodate = true;
|
oodate = true;
|
||||||
}
|
}
|
||||||
CHECK_VALID_META(p);
|
CHECK_VALID_META(p);
|
||||||
if (strcmp(p, cwd) != 0) {
|
if (strcmp(p, cwd) != 0) {
|
||||||
DEBUG4(META, "%s: %d: the current working directory has changed from '%s' to '%s'\n",
|
DEBUG4(META, "%s: %u: the current working directory has changed from '%s' to '%s'\n",
|
||||||
fname, lineno, p, curdir);
|
fname, lineno, p, curdir);
|
||||||
oodate = true;
|
oodate = true;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: meta.h,v 1.10 2021/04/03 11:08:40 rillig Exp $ */
|
/* $NetBSD: meta.h,v 1.11 2021/12/15 09:53:41 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Things needed for 'meta' mode.
|
* Things needed for 'meta' mode.
|
||||||
@ -46,13 +46,13 @@ void meta_mode_init(const char *);
|
|||||||
void meta_job_start(struct Job *, GNode *);
|
void meta_job_start(struct Job *, GNode *);
|
||||||
void meta_job_child(struct Job *);
|
void meta_job_child(struct Job *);
|
||||||
void meta_job_parent(struct Job *, pid_t);
|
void meta_job_parent(struct Job *, pid_t);
|
||||||
int meta_job_fd(struct Job *);
|
int meta_job_fd(struct Job *) MAKE_ATTR_USE;
|
||||||
int meta_job_event(struct Job *);
|
int meta_job_event(struct Job *) MAKE_ATTR_USE;
|
||||||
void meta_job_error(struct Job *, GNode *, bool, int);
|
void meta_job_error(struct Job *, GNode *, bool, int);
|
||||||
void meta_job_output(struct Job *, char *, const char *);
|
void meta_job_output(struct Job *, char *, const char *);
|
||||||
int meta_cmd_finish(void *);
|
int meta_cmd_finish(void *);
|
||||||
int meta_job_finish(struct Job *);
|
int meta_job_finish(struct Job *);
|
||||||
bool meta_oodate(GNode *, bool);
|
bool meta_oodate(GNode *, bool) MAKE_ATTR_USE;
|
||||||
void meta_compat_start(void);
|
void meta_compat_start(void);
|
||||||
void meta_compat_child(void);
|
void meta_compat_child(void);
|
||||||
void meta_compat_parent(pid_t);
|
void meta_compat_parent(pid_t);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: metachar.h,v 1.17 2021/06/21 18:54:41 rillig Exp $ */
|
/* $NetBSD: metachar.h,v 1.20 2022/01/08 11:04:13 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015 The NetBSD Foundation, Inc.
|
* Copyright (c) 2015 The NetBSD Foundation, Inc.
|
||||||
@ -35,18 +35,18 @@
|
|||||||
|
|
||||||
extern const unsigned char _metachar[];
|
extern const unsigned char _metachar[];
|
||||||
|
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
is_shell_metachar(char c)
|
ch_is_shell_meta(char c)
|
||||||
{
|
{
|
||||||
return _metachar[c & 0x7f] != 0;
|
return _metachar[c & 0x7f] != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool MAKE_ATTR_USE
|
||||||
needshell(const char *cmd)
|
needshell(const char *cmd)
|
||||||
{
|
{
|
||||||
while (!is_shell_metachar(*cmd) && *cmd != ':' && *cmd != '=')
|
while (!ch_is_shell_meta(*cmd) && *cmd != ':' && *cmd != '=')
|
||||||
cmd++;
|
cmd++;
|
||||||
return *cmd != '\0';
|
return *cmd != '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* MAKE_METACHAR_H */
|
#endif
|
||||||
|
@ -1,3 +1,60 @@
|
|||||||
|
2022-02-04 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* install-mk (MK_VERSION): 20220204
|
||||||
|
|
||||||
|
* host-target.mk: use .MAKE.OS if available
|
||||||
|
|
||||||
|
2022-02-02 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* install-mk (MK_VERSION): 20220202
|
||||||
|
|
||||||
|
* cc-wrap.mk: allow other entries in CC_WRAP_FILTER
|
||||||
|
We add our filter on extensions last, so prior filters
|
||||||
|
can apply to the whole value of .IMPSRC
|
||||||
|
|
||||||
|
2022-02-01 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* cc-wrap.mk: take advantage of target local variables to
|
||||||
|
wrap compilers like CC CXX with wrappers like ccache distcc etc
|
||||||
|
|
||||||
|
2022-01-28 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* meta2deps: we do not expect any trace data for setid apps
|
||||||
|
|
||||||
|
2022-01-26 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* dirdeps.mk: ensure TARGET_SPEC and TARGET_SPEC_VARS are passed
|
||||||
|
to sub-make using DIRDEPS_CACHE
|
||||||
|
|
||||||
|
2022-01-07 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* dirdeps.mk: use _cache_script to minimize the number of shells
|
||||||
|
forked when generating dirdeps.cache
|
||||||
|
|
||||||
|
2022-01-02 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* install-mk (MK_VERSION): 20220101
|
||||||
|
|
||||||
|
* dirdeps.mk: initialize DEP_* and _debug_reldir earlier.
|
||||||
|
If initial DIRDEPS are from command line, create the target
|
||||||
|
_dirdeps_cmdline as an indication.
|
||||||
|
|
||||||
|
2022-01-01 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* init.mk (_SKIP_BUILD): when doing DIRDEPS_BUILD
|
||||||
|
at top-level only some targets are allowed at level 0,
|
||||||
|
for leaf makefiles only the default (all) target is restricted
|
||||||
|
|
||||||
|
2021-12-28 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* install-mk (MK_VERSION): 20211228
|
||||||
|
|
||||||
|
* meta2deps.py: filemon on Linux is not as reliable as we might
|
||||||
|
like, we do not want to update DIRDEPS if filemon output is
|
||||||
|
incomplete. Track pids that we 'E'xec and make sure we see an
|
||||||
|
e'X'it for each one. Throw an error if we are missing any 'X'
|
||||||
|
records.
|
||||||
|
|
||||||
2021-12-12 Simon J Gerraty <sjg@beast.crufty.net>
|
2021-12-12 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
* sys.mk: simplify; include meta.sys.mk if MK_META_MODE is yes.
|
* sys.mk: simplify; include meta.sys.mk if MK_META_MODE is yes.
|
||||||
|
@ -6,6 +6,7 @@ auto.obj.mk
|
|||||||
autoconf.mk
|
autoconf.mk
|
||||||
autodep.mk
|
autodep.mk
|
||||||
auto.dep.mk
|
auto.dep.mk
|
||||||
|
cc-wrap.mk
|
||||||
compiler.mk
|
compiler.mk
|
||||||
cython.mk
|
cython.mk
|
||||||
dep.mk
|
dep.mk
|
||||||
|
61
contrib/bmake/mk/cc-wrap.mk
Normal file
61
contrib/bmake/mk/cc-wrap.mk
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# $Id: cc-wrap.mk,v 1.4 2022/02/02 17:41:56 sjg Exp $
|
||||||
|
#
|
||||||
|
# @(#) Copyright (c) 2022, Simon J. Gerraty
|
||||||
|
#
|
||||||
|
# This file is provided in the hope that it will
|
||||||
|
# be of use. There is absolutely NO WARRANTY.
|
||||||
|
# Permission to copy, redistribute or otherwise
|
||||||
|
# use this file is hereby granted provided that
|
||||||
|
# the above copyright notice and this notice are
|
||||||
|
# left intact.
|
||||||
|
#
|
||||||
|
# Please send copies of changes and bug-fixes to:
|
||||||
|
# sjg@crufty.net
|
||||||
|
#
|
||||||
|
|
||||||
|
.if ${MAKE_VERSION} >= 20220126
|
||||||
|
# which targets are we interested in?
|
||||||
|
CC_WRAP_TARGETS ?= ${OBJS:U} ${POBJS:U} ${SOBJS:U}
|
||||||
|
|
||||||
|
.if !empty(CC_WRAP_TARGETS)
|
||||||
|
# cleanup
|
||||||
|
# all the target assignments below are effectively := anyway
|
||||||
|
# so we might as well do this once
|
||||||
|
CC_WRAP_TARGETS := ${CC_WRAP_TARGETS:O:u}
|
||||||
|
|
||||||
|
# what do we wrap?
|
||||||
|
CC_WRAP_LIST += CC CXX
|
||||||
|
CC_WRAP_LIST := ${CC_WRAP_LIST:O:u}
|
||||||
|
|
||||||
|
# what might we wrap them with?
|
||||||
|
CC_WRAPPERS += ccache distcc icecc
|
||||||
|
CC_WRAPPERS := ${CC_WRAPPERS:O:u}
|
||||||
|
.for w in ${CC_WRAPPERS}
|
||||||
|
${w:tu} ?= $w
|
||||||
|
.endfor
|
||||||
|
|
||||||
|
# we do not want to make all these targets out-of-date
|
||||||
|
# just because one of the above wrappers are enabled/disabled
|
||||||
|
${CC_WRAP_TARGETS}: .MAKE.META.CMP_FILTER = ${CC_WRAPPERS:tu@W@${$W}@:S,^,N,}
|
||||||
|
|
||||||
|
# some object src types we should not wrap
|
||||||
|
CC_WRAP_SKIP_EXTS += s
|
||||||
|
|
||||||
|
# We add the sequence we care about - excluding CC_WRAP_SKIP_EXTS
|
||||||
|
# but prior filters can apply to full value of .IMPSRC
|
||||||
|
CC_WRAP_FILTER += E:tl:${CC_WRAP_SKIP_EXTS:${M_ListToSkip}}
|
||||||
|
CC_WRAP_FILTER := ${CC_WRAP_FILTER:ts:}
|
||||||
|
|
||||||
|
# last one enabled wins!
|
||||||
|
.for W in ${CC_WRAPPERS:tu}
|
||||||
|
.if ${MK_$W:U} == "yes"
|
||||||
|
.for C in ${CC_WRAP_LIST}
|
||||||
|
# we have to protect the check of .IMPSRC from Global expansion
|
||||||
|
${CC_WRAP_TARGETS}: $C = $${"$${.IMPSRC:${CC_WRAP_FILTER}}":?${$W}:} ${$C}
|
||||||
|
.endfor
|
||||||
|
.endif
|
||||||
|
.endfor
|
||||||
|
|
||||||
|
.endif
|
||||||
|
.endif
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
# $Id: dirdeps.mk,v 1.147 2021/12/14 02:09:53 sjg Exp $
|
# $Id: dirdeps.mk,v 1.151 2022/01/28 01:13:14 sjg Exp $
|
||||||
|
|
||||||
# Copyright (c) 2010-2021, Simon J. Gerraty
|
# Copyright (c) 2010-2022, Simon J. Gerraty
|
||||||
# Copyright (c) 2010-2018, Juniper Networks, Inc.
|
# Copyright (c) 2010-2018, Juniper Networks, Inc.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
@ -134,6 +134,16 @@
|
|||||||
# A list of MACHINEs the current directory should not be
|
# A list of MACHINEs the current directory should not be
|
||||||
# built for.
|
# built for.
|
||||||
#
|
#
|
||||||
|
# DIRDEPS_EXPORT_VARS (DEP_EXPORT_VARS)
|
||||||
|
# It is discouraged, but sometimes necessary for a
|
||||||
|
# Makefile.depend file to influence the environment.
|
||||||
|
# Doing this is correctly (especially if using DIRDEPS_CACHE) is
|
||||||
|
# tricky so a Makefile.depend file can set DIRDEPS_EXPORT_VARS
|
||||||
|
# and dirdeps.mk will do the deed:
|
||||||
|
#
|
||||||
|
# MK_UEFI = yes
|
||||||
|
# DIRDEPS_EXPORT_VARS = MK_UEFI
|
||||||
|
#
|
||||||
# _build_xtra_dirs
|
# _build_xtra_dirs
|
||||||
# local.dirdeps.mk can add targets to this variable.
|
# local.dirdeps.mk can add targets to this variable.
|
||||||
# They will be hooked into the build, but independent of
|
# They will be hooked into the build, but independent of
|
||||||
@ -161,6 +171,8 @@ _DIRDEP_USE_LEVEL?= 0
|
|||||||
.if ${.MAKE.LEVEL} == ${_DIRDEP_USE_LEVEL}
|
.if ${.MAKE.LEVEL} == ${_DIRDEP_USE_LEVEL}
|
||||||
# only the first instance is interested in all this
|
# only the first instance is interested in all this
|
||||||
|
|
||||||
|
# the first time we are included the _DIRDEP_USE target will not be defined
|
||||||
|
# we can use this as a clue to do initialization and other one time things.
|
||||||
.if !target(_DIRDEP_USE)
|
.if !target(_DIRDEP_USE)
|
||||||
|
|
||||||
# do some setup we only need once
|
# do some setup we only need once
|
||||||
@ -184,6 +196,8 @@ TARGET_MACHINE := ${MACHINE}
|
|||||||
.endif
|
.endif
|
||||||
# disable DIRDEPS_CACHE as it does not like this trick
|
# disable DIRDEPS_CACHE as it does not like this trick
|
||||||
MK_DIRDEPS_CACHE = no
|
MK_DIRDEPS_CACHE = no
|
||||||
|
# incase anyone needs to know
|
||||||
|
_dirdeps_cmdline:
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# make sure we get the behavior we expect
|
# make sure we get the behavior we expect
|
||||||
@ -257,12 +271,36 @@ _machine_dependfiles := ${.MAKE.DEPENDFILE_PREFERENCE:T:M*${MACHINE}*}
|
|||||||
.endif
|
.endif
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
|
|
||||||
# this is how we identify non-machine specific dependfiles
|
# this is how we identify non-machine specific dependfiles
|
||||||
N_notmachine := ${.MAKE.DEPENDFILE_PREFERENCE:E:N*${MACHINE}*:${M_ListToSkip}}
|
N_notmachine := ${.MAKE.DEPENDFILE_PREFERENCE:E:N*${MACHINE}*:${M_ListToSkip}}
|
||||||
|
|
||||||
|
# this gets reset for each dirdep we check
|
||||||
|
DEP_RELDIR ?= ${RELDIR}
|
||||||
|
|
||||||
|
# remember the initial value of DEP_RELDIR - we test for it below.
|
||||||
|
_DEP_RELDIR := ${DEP_RELDIR}
|
||||||
|
|
||||||
|
# this can cause lots of output!
|
||||||
|
# set to a set of glob expressions that might match RELDIR
|
||||||
|
DEBUG_DIRDEPS ?= no
|
||||||
|
|
||||||
|
# make sure this target exists
|
||||||
|
dirdeps: beforedirdeps .WAIT
|
||||||
|
beforedirdeps:
|
||||||
|
|
||||||
.endif # !target(_DIRDEP_USE)
|
.endif # !target(_DIRDEP_USE)
|
||||||
|
|
||||||
|
.if ${DEBUG_DIRDEPS:@x@${DEP_RELDIR:M$x}${${DEP_RELDIR}.${DEP_MACHINE}:L:M$x}@} != ""
|
||||||
|
_debug_reldir = 1
|
||||||
|
.else
|
||||||
|
_debug_reldir = 0
|
||||||
|
.endif
|
||||||
|
.if ${DEBUG_DIRDEPS:@x@${DEP_RELDIR:M$x}${${DEP_RELDIR}.depend depend:L:M$x}@} != ""
|
||||||
|
_debug_search = 1
|
||||||
|
.else
|
||||||
|
_debug_search = 0
|
||||||
|
.endif
|
||||||
|
|
||||||
# First off, we want to know what ${MACHINE} to build for.
|
# First off, we want to know what ${MACHINE} to build for.
|
||||||
# This can be complicated if we are using a mixture of ${MACHINE} specific
|
# This can be complicated if we are using a mixture of ${MACHINE} specific
|
||||||
# and non-specific Makefile.depend*
|
# and non-specific Makefile.depend*
|
||||||
@ -297,26 +335,6 @@ DEP_MACHINE := ${_DEP_TARGET_SPEC}
|
|||||||
_build_all_dirs =
|
_build_all_dirs =
|
||||||
_build_xtra_dirs =
|
_build_xtra_dirs =
|
||||||
|
|
||||||
# the first time we are included the _DIRDEP_USE target will not be defined
|
|
||||||
# we can use this as a clue to do initialization and other one time things.
|
|
||||||
.if !target(_DIRDEP_USE)
|
|
||||||
# make sure this target exists
|
|
||||||
dirdeps: beforedirdeps .WAIT
|
|
||||||
beforedirdeps:
|
|
||||||
|
|
||||||
# We normally expect to be included by Makefile.depend.*
|
|
||||||
# which sets the DEP_* macros below.
|
|
||||||
DEP_RELDIR ?= ${RELDIR}
|
|
||||||
|
|
||||||
# this can cause lots of output!
|
|
||||||
# set to a set of glob expressions that might match RELDIR
|
|
||||||
DEBUG_DIRDEPS ?= no
|
|
||||||
|
|
||||||
# remember the initial value of DEP_RELDIR - we test for it below.
|
|
||||||
_DEP_RELDIR := ${DEP_RELDIR}
|
|
||||||
|
|
||||||
.endif
|
|
||||||
|
|
||||||
# DIRDEPS_CACHE can be very handy for debugging.
|
# DIRDEPS_CACHE can be very handy for debugging.
|
||||||
# Also if repeatedly building the same target,
|
# Also if repeatedly building the same target,
|
||||||
# we can avoid the overhead of re-computing the tree dependencies.
|
# we can avoid the overhead of re-computing the tree dependencies.
|
||||||
@ -329,16 +347,6 @@ BUILD_DIRDEPS ?= yes
|
|||||||
DIRDEPS_CACHE ?= ${_OBJDIR:tA}/dirdeps.cache${_TARGETS:U${.TARGETS}:Nall:O:u:ts-:S,/,_,g:S,^,.,:N.}
|
DIRDEPS_CACHE ?= ${_OBJDIR:tA}/dirdeps.cache${_TARGETS:U${.TARGETS}:Nall:O:u:ts-:S,/,_,g:S,^,.,:N.}
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
.if ${DEBUG_DIRDEPS:@x@${DEP_RELDIR:M$x}${${DEP_RELDIR}.${DEP_MACHINE}:L:M$x}@} != ""
|
|
||||||
_debug_reldir = 1
|
|
||||||
.else
|
|
||||||
_debug_reldir = 0
|
|
||||||
.endif
|
|
||||||
.if ${DEBUG_DIRDEPS:@x@${DEP_RELDIR:M$x}${${DEP_RELDIR}.depend:L:M$x}@} != ""
|
|
||||||
_debug_search = 1
|
|
||||||
.else
|
|
||||||
_debug_search = 0
|
|
||||||
.endif
|
|
||||||
|
|
||||||
# pickup customizations
|
# pickup customizations
|
||||||
# as below you can use !target(_DIRDEP_USE) to protect things
|
# as below you can use !target(_DIRDEP_USE) to protect things
|
||||||
@ -532,7 +540,10 @@ BUILD_DIRDEPS = no
|
|||||||
dirdeps: dirdeps-cached
|
dirdeps: dirdeps-cached
|
||||||
dirdeps-cached: ${DIRDEPS_CACHE} .MAKE
|
dirdeps-cached: ${DIRDEPS_CACHE} .MAKE
|
||||||
@echo "${TRACER}Using ${DIRDEPS_CACHE}"
|
@echo "${TRACER}Using ${DIRDEPS_CACHE}"
|
||||||
@MAKELEVEL=${.MAKE.LEVEL} ${.MAKE} -C ${_CURDIR} -f ${DIRDEPS_CACHE} \
|
@MAKELEVEL=${.MAKE.LEVEL} \
|
||||||
|
TARGET_SPEC=${TARGET_SPEC} \
|
||||||
|
${TARGET_SPEC_VARS:@v@$v=${$v}@} \
|
||||||
|
${.MAKE} -C ${_CURDIR} -f ${DIRDEPS_CACHE} \
|
||||||
dirdeps MK_DIRDEPS_CACHE=no BUILD_DIRDEPS=no
|
dirdeps MK_DIRDEPS_CACHE=no BUILD_DIRDEPS=no
|
||||||
|
|
||||||
# leaf makefiles rarely work for building DIRDEPS_CACHE
|
# leaf makefiles rarely work for building DIRDEPS_CACHE
|
||||||
@ -701,15 +712,18 @@ _build_all_dirs := ${_build_all_dirs:O:u}
|
|||||||
.if ${.MAKEFLAGS:M-V${_V_READ_DIRDEPS:U}} == ""
|
.if ${.MAKEFLAGS:M-V${_V_READ_DIRDEPS:U}} == ""
|
||||||
.if !empty(_build_all_dirs)
|
.if !empty(_build_all_dirs)
|
||||||
.if ${BUILD_DIRDEPS_CACHE} == "yes"
|
.if ${BUILD_DIRDEPS_CACHE} == "yes"
|
||||||
x!= echo; { echo; echo '\# ${DEP_RELDIR}.${DEP_TARGET_SPEC}'; } >&3
|
# we use _cache_script to minimize the number of times we fork the shell
|
||||||
|
_cache_script = echo '\# ${DEP_RELDIR}.${DEP_TARGET_SPEC}';
|
||||||
# guard against _new_dirdeps being too big for a single command line
|
# guard against _new_dirdeps being too big for a single command line
|
||||||
_new_dirdeps := ${_build_all_dirs:@x@${target($x):?:$x}@:S,^${SRCTOP}/,,}
|
_new_dirdeps := ${_build_all_dirs:@x@${target($x):?:$x}@:S,^${SRCTOP}/,,}
|
||||||
_cache_xtra_deps := ${_build_xtra_dirs:S,^${SRCTOP}/,,}
|
_cache_xtra_deps := ${_build_xtra_dirs:S,^${SRCTOP}/,,}
|
||||||
.export _cache_xtra_deps _new_dirdeps
|
.export _cache_xtra_deps _new_dirdeps
|
||||||
.if !empty(DEP_EXPORT_VARS)
|
.if !empty(DIRDEPS_EXPORT_VARS) || !empty(DEP_EXPORT_VARS)
|
||||||
# Discouraged, but there are always exceptions.
|
# Discouraged, but there are always exceptions.
|
||||||
# Handle it here rather than explain how.
|
# Handle it here rather than explain how.
|
||||||
x!= echo; { echo; ${DEP_EXPORT_VARS:@v@echo '$v=${$v}';@} echo '.export ${DEP_EXPORT_VARS}'; echo; } >&3
|
DIRDEPS_EXPORT_VARS ?= ${DEP_EXPORT_VARS}
|
||||||
|
_cache_xvars := echo; ${DIRDEPS_EXPORT_VARS:@v@echo '$v = ${$v}';@} echo '.export ${DIRDEPS_EXPORT_VARS}'; echo;
|
||||||
|
_cache_script += ${_cache_xvars}
|
||||||
.endif
|
.endif
|
||||||
.else
|
.else
|
||||||
# this makes it all happen
|
# this makes it all happen
|
||||||
@ -721,16 +735,17 @@ ${_build_all_dirs}: _DIRDEP_USE
|
|||||||
.info ${DEP_RELDIR}.${DEP_TARGET_SPEC}: needs: ${_build_dirs:S,^${SRCTOP}/,,}
|
.info ${DEP_RELDIR}.${DEP_TARGET_SPEC}: needs: ${_build_dirs:S,^${SRCTOP}/,,}
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
.if !empty(DEP_EXPORT_VARS)
|
.if !empty(DIRDEPS_EXPORT_VARS) || !empty(DEP_EXPORT_VARS)
|
||||||
.export ${DEP_EXPORT_VARS}
|
.export ${DIRDEPS_EXPORT_VARS} ${DEP_EXPORT_VARS}
|
||||||
DEP_EXPORT_VARS=
|
DIRDEPS_EXPORT_VARS =
|
||||||
|
DEP_EXPORT_VARS =
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# this builds the dependency graph
|
# this builds the dependency graph
|
||||||
.for m in ${_machines}
|
.for m in ${_machines}
|
||||||
.if ${BUILD_DIRDEPS_CACHE} == "yes" && !empty(_build_dirs)
|
.if ${BUILD_DIRDEPS_CACHE} == "yes" && !empty(_build_dirs)
|
||||||
_cache_deps =
|
_cache_deps =
|
||||||
x!= echo; { echo; echo 'DIRDEPS.${_this_dir}.$m = \'; } >&3
|
_cache_script += echo; echo 'DIRDEPS.${_this_dir}.$m = \';
|
||||||
.endif
|
.endif
|
||||||
# it would be nice to do :N${.TARGET}
|
# it would be nice to do :N${.TARGET}
|
||||||
.if !empty(__qual_depdirs)
|
.if !empty(__qual_depdirs)
|
||||||
@ -753,10 +768,10 @@ ${_this_dir}.$m: ${_build_dirs:M*.$q}
|
|||||||
_cache_deps += ${_build_dirs:M*.$m:N${_this_dir}.$m:S,^${SRCTOP}/,,}
|
_cache_deps += ${_build_dirs:M*.$m:N${_this_dir}.$m:S,^${SRCTOP}/,,}
|
||||||
.if !empty(_cache_deps)
|
.if !empty(_cache_deps)
|
||||||
.export _cache_deps
|
.export _cache_deps
|
||||||
x!= echo; for x in $$_cache_deps; do echo " _{SRCTOP}/$$x \\"; done >&3
|
_cache_script += for x in $$_cache_deps; do echo " _{SRCTOP}/$$x \\"; done;
|
||||||
.endif
|
.endif
|
||||||
# anything in _{build,env}_xtra_dirs is hooked to dirdeps: only
|
# anything in _{build,env}_xtra_dirs is hooked to dirdeps: only
|
||||||
x!= echo; { echo; echo '${_this_dir}.$m: $${DIRDEPS.${_this_dir}.$m}'; \
|
x!= echo; { echo; ${_cache_script} echo; echo '${_this_dir}.$m: $${DIRDEPS.${_this_dir}.$m}'; \
|
||||||
echo; echo 'dirdeps: ${_this_dir}.$m \'; \
|
echo; echo 'dirdeps: ${_this_dir}.$m \'; \
|
||||||
for x in $$_cache_xtra_deps; do echo " _{SRCTOP}/$$x \\"; done; \
|
for x in $$_cache_xtra_deps; do echo " _{SRCTOP}/$$x \\"; done; \
|
||||||
echo; for x in $$_new_dirdeps; do echo "_{SRCTOP}/$$x: _DIRDEP_USE"; done; } >&3
|
echo; for x in $$_new_dirdeps; do echo "_{SRCTOP}/$$x: _DIRDEP_USE"; done; } >&3
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
# RCSid:
|
# RCSid:
|
||||||
# $Id: host-target.mk,v 1.13 2020/08/05 23:32:08 sjg Exp $
|
# $Id: host-target.mk,v 1.14 2022/02/04 18:05:22 sjg Exp $
|
||||||
|
|
||||||
# Host platform information; may be overridden
|
# Host platform information; may be overridden
|
||||||
.if !defined(_HOST_OSNAME)
|
.if !defined(_HOST_OSNAME)
|
||||||
_HOST_OSNAME != uname -s
|
# use .MAKE.OS if available
|
||||||
|
_HOST_OSNAME := ${.MAKE.OS:U${uname -s:L:sh}}
|
||||||
.export _HOST_OSNAME
|
.export _HOST_OSNAME
|
||||||
.endif
|
.endif
|
||||||
.if !defined(_HOST_OSREL)
|
.if !defined(_HOST_OSREL)
|
||||||
@ -15,7 +16,7 @@ _HOST_MACHINE != uname -m
|
|||||||
.export _HOST_MACHINE
|
.export _HOST_MACHINE
|
||||||
.endif
|
.endif
|
||||||
.if !defined(_HOST_ARCH)
|
.if !defined(_HOST_ARCH)
|
||||||
# for NetBSD prefer $MACHINE (amd64 rather than x86_64)
|
# for Darwin and NetBSD prefer $MACHINE (amd64 rather than x86_64)
|
||||||
.if ${_HOST_OSNAME:NDarwin:NNetBSD} == ""
|
.if ${_HOST_OSNAME:NDarwin:NNetBSD} == ""
|
||||||
_HOST_ARCH := ${_HOST_MACHINE}
|
_HOST_ARCH := ${_HOST_MACHINE}
|
||||||
.else
|
.else
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# $Id: init.mk,v 1.26 2021/12/08 05:56:50 sjg Exp $
|
# $Id: init.mk,v 1.27 2022/01/01 17:32:18 sjg Exp $
|
||||||
#
|
#
|
||||||
# @(#) Copyright (c) 2002, Simon J. Gerraty
|
# @(#) Copyright (c) 2002, Simon J. Gerraty
|
||||||
#
|
#
|
||||||
@ -66,13 +66,17 @@ CXX_PIC?= ${CC_PIC}
|
|||||||
PROFFLAGS?= -DGPROF -DPROF
|
PROFFLAGS?= -DGPROF -DPROF
|
||||||
|
|
||||||
.if ${.MAKE.LEVEL:U1} == 0 && ${MK_DIRDEPS_BUILD:Uno} == "yes"
|
.if ${.MAKE.LEVEL:U1} == 0 && ${MK_DIRDEPS_BUILD:Uno} == "yes"
|
||||||
# targets that are ok at level 0
|
.if ${RELDIR} == "."
|
||||||
|
# top-level targets that are ok at level 0
|
||||||
DIRDEPS_BUILD_LEVEL0_TARGETS += clean* destroy*
|
DIRDEPS_BUILD_LEVEL0_TARGETS += clean* destroy*
|
||||||
M_ListToSkip?= O:u:S,^,N,:ts:
|
M_ListToSkip?= O:u:S,^,N,:ts:
|
||||||
.if ${.TARGETS:Uall:${DIRDEPS_BUILD_LEVEL0_TARGETS:${M_ListToSkip}}} != ""
|
.if ${.TARGETS:Uall:${DIRDEPS_BUILD_LEVEL0_TARGETS:${M_ListToSkip}}} != ""
|
||||||
# this tells lib.mk and prog.mk to not actually build anything
|
# this tells lib.mk and prog.mk to not actually build anything
|
||||||
_SKIP_BUILD = not building at level 0
|
_SKIP_BUILD = not building at level 0
|
||||||
.endif
|
.endif
|
||||||
|
.elif ${.TARGETS:U:Nall} == ""
|
||||||
|
_SKIP_BUILD = not building at level 0
|
||||||
|
.endif
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
.if !defined(.PARSEDIR)
|
.if !defined(.PARSEDIR)
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
# Simon J. Gerraty <sjg@crufty.net>
|
# Simon J. Gerraty <sjg@crufty.net>
|
||||||
|
|
||||||
# RCSid:
|
# RCSid:
|
||||||
# $Id: install-mk,v 1.206 2021/12/11 18:57:41 sjg Exp $
|
# $Id: install-mk,v 1.213 2022/02/05 01:39:12 sjg Exp $
|
||||||
#
|
#
|
||||||
# @(#) Copyright (c) 1994 Simon J. Gerraty
|
# @(#) Copyright (c) 1994 Simon J. Gerraty
|
||||||
#
|
#
|
||||||
@ -70,7 +70,7 @@
|
|||||||
# sjg@crufty.net
|
# sjg@crufty.net
|
||||||
#
|
#
|
||||||
|
|
||||||
MK_VERSION=20211212
|
MK_VERSION=20220204
|
||||||
OWNER=
|
OWNER=
|
||||||
GROUP=
|
GROUP=
|
||||||
MODE=444
|
MODE=444
|
||||||
|
@ -37,7 +37,7 @@ We only pay attention to a subset of the information in the
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
RCSid:
|
RCSid:
|
||||||
$Id: meta2deps.py,v 1.40 2021/12/13 19:32:46 sjg Exp $
|
$Id: meta2deps.py,v 1.44 2022/01/29 02:42:01 sjg Exp $
|
||||||
|
|
||||||
Copyright (c) 2011-2020, Simon J. Gerraty
|
Copyright (c) 2011-2020, Simon J. Gerraty
|
||||||
Copyright (c) 2011-2017, Juniper Networks, Inc.
|
Copyright (c) 2011-2017, Juniper Networks, Inc.
|
||||||
@ -66,7 +66,10 @@ RCSid:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os, re, sys
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import stat
|
||||||
|
|
||||||
def resolve(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr):
|
def resolve(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr):
|
||||||
"""
|
"""
|
||||||
@ -244,6 +247,7 @@ class MetaFile:
|
|||||||
self.curdir = conf.get('CURDIR')
|
self.curdir = conf.get('CURDIR')
|
||||||
self.reldir = conf.get('RELDIR')
|
self.reldir = conf.get('RELDIR')
|
||||||
self.dpdeps = conf.get('DPDEPS')
|
self.dpdeps = conf.get('DPDEPS')
|
||||||
|
self.pids = {}
|
||||||
self.line = 0
|
self.line = 0
|
||||||
|
|
||||||
if not self.conf:
|
if not self.conf:
|
||||||
@ -449,7 +453,7 @@ class MetaFile:
|
|||||||
if self.curdir:
|
if self.curdir:
|
||||||
self.seenit(self.curdir) # we ignore this
|
self.seenit(self.curdir) # we ignore this
|
||||||
|
|
||||||
interesting = 'CEFLRV'
|
interesting = 'CEFLRVX'
|
||||||
for line in f:
|
for line in f:
|
||||||
self.line += 1
|
self.line += 1
|
||||||
# ignore anything we don't care about
|
# ignore anything we don't care about
|
||||||
@ -505,6 +509,13 @@ class MetaFile:
|
|||||||
print("cwd=", cwd, file=self.debug_out)
|
print("cwd=", cwd, file=self.debug_out)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if w[0] == 'X':
|
||||||
|
try:
|
||||||
|
del self.pids[pid]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
continue
|
||||||
|
|
||||||
if w[2] in self.seen:
|
if w[2] in self.seen:
|
||||||
if self.debug > 2:
|
if self.debug > 2:
|
||||||
print("seen:", w[2], file=self.debug_out)
|
print("seen:", w[2], file=self.debug_out)
|
||||||
@ -518,11 +529,30 @@ class MetaFile:
|
|||||||
continue
|
continue
|
||||||
elif w[0] in 'ERWS':
|
elif w[0] in 'ERWS':
|
||||||
path = w[2]
|
path = w[2]
|
||||||
if path == '.':
|
if w[0] == 'E':
|
||||||
|
self.pids[pid] = path
|
||||||
|
elif path == '.':
|
||||||
continue
|
continue
|
||||||
self.parse_path(path, cwd, w[0], w)
|
self.parse_path(path, cwd, w[0], w)
|
||||||
|
|
||||||
assert(version > 0)
|
assert(version > 0)
|
||||||
|
setid_pids = []
|
||||||
|
# self.pids should be empty!
|
||||||
|
for pid,path in self.pids.items():
|
||||||
|
try:
|
||||||
|
# no guarantee that path is still valid
|
||||||
|
if os.stat(path).st_mode & (stat.S_ISUID|stat.S_ISGID):
|
||||||
|
# we do not expect anything after Exec
|
||||||
|
setid_pids.append(pid)
|
||||||
|
continue
|
||||||
|
except:
|
||||||
|
# we do not care why the above fails,
|
||||||
|
# we do not want to miss the ERROR below.
|
||||||
|
pass
|
||||||
|
print("ERROR: missing eXit for {} pid {}".format(path, pid))
|
||||||
|
for pid in setid_pids:
|
||||||
|
del self.pids[pid]
|
||||||
|
assert(len(self.pids) == 0)
|
||||||
if not file:
|
if not file:
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@
|
|||||||
|
|
||||||
|
|
||||||
# RCSid:
|
# RCSid:
|
||||||
# $Id: meta2deps.sh,v 1.15 2020/11/08 06:31:08 sjg Exp $
|
# $Id: meta2deps.sh,v 1.18 2022/01/28 21:17:43 sjg Exp $
|
||||||
|
|
||||||
# Copyright (c) 2010-2013, Juniper Networks, Inc.
|
# Copyright (c) 2010-2013, Juniper Networks, Inc.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
@ -239,8 +239,8 @@ meta2deps() {
|
|||||||
;;
|
;;
|
||||||
*) cat /dev/null "$@";;
|
*) cat /dev/null "$@";;
|
||||||
esac 2> /dev/null |
|
esac 2> /dev/null |
|
||||||
sed -e 's,^CWD,C C,;/^[CREFLMV] /!d' -e "s,',,g" |
|
sed -e 's,^CWD,C C,;/^[CREFLMVX] /!d' -e "s,',,g" |
|
||||||
$_excludes | ( version=no
|
$_excludes | ( version=no epids= xpids=
|
||||||
while read op pid path junk
|
while read op pid path junk
|
||||||
do
|
do
|
||||||
: op=$op pid=$pid path=$path
|
: op=$op pid=$pid path=$path
|
||||||
@ -271,8 +271,9 @@ meta2deps() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
: op=$op path=$path
|
||||||
case "$op,$path" in
|
case "$op,$path" in
|
||||||
V,*) version=$path; continue;;
|
V,*) version=$pid; continue;;
|
||||||
W,*srcrel|*.dirdep) continue;;
|
W,*srcrel|*.dirdep) continue;;
|
||||||
C,*)
|
C,*)
|
||||||
case "$path" in
|
case "$path" in
|
||||||
@ -289,6 +290,15 @@ meta2deps() {
|
|||||||
continue
|
continue
|
||||||
;;
|
;;
|
||||||
*) dir=${path%/*}
|
*) dir=${path%/*}
|
||||||
|
case "$op" in
|
||||||
|
E) # setid apps get no tracing so we won't see eXit
|
||||||
|
case `'ls' -l $path 2> /dev/null | sed 's, .*,,'` in
|
||||||
|
*s*) ;;
|
||||||
|
*) epids="$epids $pid";;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
X) xpids="$xpids $pid"; continue;;
|
||||||
|
esac
|
||||||
case "$path" in
|
case "$path" in
|
||||||
$src_re|$obj_re) ;;
|
$src_re|$obj_re) ;;
|
||||||
/*/stage/*) ;;
|
/*/stage/*) ;;
|
||||||
@ -378,9 +388,18 @@ meta2deps() {
|
|||||||
echo $dir;;
|
echo $dir;;
|
||||||
esac
|
esac
|
||||||
done > $tf.dirdep
|
done > $tf.dirdep
|
||||||
|
: version=$version
|
||||||
case "$version" in
|
case "$version" in
|
||||||
0) error "no filemon data";;
|
0) error "no filemon data";;
|
||||||
esac ) || exit 1
|
esac
|
||||||
|
for p in $epids
|
||||||
|
do
|
||||||
|
: p=$p
|
||||||
|
case " $xpids " in
|
||||||
|
*" $p "*) ;;
|
||||||
|
*) error "missing eXit for pid $p";;
|
||||||
|
esac
|
||||||
|
done ) || exit 1
|
||||||
_nl=echo
|
_nl=echo
|
||||||
for f in $tf.dirdep $tf.qual $tf.srcdep
|
for f in $tf.dirdep $tf.qual $tf.srcdep
|
||||||
do
|
do
|
||||||
|
@ -143,6 +143,8 @@ examples/sys.clean-env.mk
|
|||||||
host-target.mk
|
host-target.mk
|
||||||
Is used to set macros like ``HOST_TARGET``, ``HOST_OS`` and
|
Is used to set macros like ``HOST_TARGET``, ``HOST_OS`` and
|
||||||
``host_os`` which are used to find the next step.
|
``host_os`` which are used to find the next step.
|
||||||
|
Note: since 20130303 bmake provides ``.MAKE.OS`` set to
|
||||||
|
the equivalent of ``HOST_OS``.
|
||||||
|
|
||||||
sys/\*.mk
|
sys/\*.mk
|
||||||
Platform specific additions, such as ``Darwin.mk`` or ``SunOS.mk``
|
Platform specific additions, such as ``Darwin.mk`` or ``SunOS.mk``
|
||||||
@ -159,27 +161,40 @@ local.sys.mk
|
|||||||
The above arrangement makes it easy for the mk files to be part of a
|
The above arrangement makes it easy for the mk files to be part of a
|
||||||
src tree on an NFS volume and to allow building on multiple platforms.
|
src tree on an NFS volume and to allow building on multiple platforms.
|
||||||
|
|
||||||
|
options.mk
|
||||||
|
----------
|
||||||
|
|
||||||
|
Inspired by FreeBSD's ``bsd.own.mk`` but more flexible.
|
||||||
|
FreeBSD now have similar functionality in ``bsd.mkopt.mk``.
|
||||||
|
|
||||||
|
It allows users to express their intent with respect to options
|
||||||
|
``MK_*`` by setting ``WITH_*`` or ``WITHOUT_*``.
|
||||||
|
|
||||||
|
Note: ``WITHOUT_*`` wins if both are set, and makefiles can set
|
||||||
|
``NO_*`` to say they cannot handle that option, or even ``MK_*`` if
|
||||||
|
they really need to.
|
||||||
|
|
||||||
lib.mk
|
lib.mk
|
||||||
------
|
------
|
||||||
|
|
||||||
This file is used to build a number of different libraries from the
|
This file is used to build a number of different libraries from the
|
||||||
same SRCS.
|
same SRCS.
|
||||||
|
|
||||||
lib${LIB}.a
|
``lib${LIB}.a``
|
||||||
An archive lib of ``.o`` files, this is the default
|
An archive lib of ``.o`` files, this is the default
|
||||||
|
|
||||||
lib${LIB}_p.a
|
``lib${LIB}_p.a``
|
||||||
A profiled lib of ``.po`` files.
|
A profiled lib of ``.po`` files.
|
||||||
Still an archive lib, but all the objects are built with
|
Still an archive lib, but all the objects are built with
|
||||||
profiling in mind - hence the different extension.
|
profiling in mind - hence the different extension.
|
||||||
It is skipped if ``MKPROFILE`` is "no".
|
It is skipped if ``MK_PROFILE`` is "no".
|
||||||
|
|
||||||
lib${LIB}_pic.a
|
``lib${LIB}_pic.a``
|
||||||
An archive of ``.so`` objects compiled for relocation.
|
An archive of ``.so`` objects compiled for relocation.
|
||||||
On NetBSD this is the input to ``lib${LIB}.${LD_so}``, it is
|
On NetBSD this is the input to ``lib${LIB}.${LD_so}``, it is
|
||||||
skipped if ``MKPICLIB`` is "no".
|
skipped if ``MK_PIC`` or ``MK_PICLIB`` are "no".
|
||||||
|
|
||||||
lib${LIB}.${LD_so}
|
``lib${LIB}.${LD_so}``
|
||||||
A shared library. The value of ``LD_so`` is very platform
|
A shared library. The value of ``LD_so`` is very platform
|
||||||
specific. For example::
|
specific. For example::
|
||||||
|
|
||||||
@ -190,7 +205,7 @@ lib${LIB}.${LD_so}
|
|||||||
libsslfd.1.dylib
|
libsslfd.1.dylib
|
||||||
|
|
||||||
This library will only be built if ``SHLIB_MAJOR`` has
|
This library will only be built if ``SHLIB_MAJOR`` has
|
||||||
a value, and ``MKPIC`` is not set to "no".
|
a value, and ``MK_PIC`` is not set to "no".
|
||||||
|
|
||||||
There is a lot of platform specific tweaking in ``lib.mk``, largely the
|
There is a lot of platform specific tweaking in ``lib.mk``, largely the
|
||||||
result of the original distributions trying to avoid interfering with
|
result of the original distributions trying to avoid interfering with
|
||||||
@ -202,7 +217,7 @@ libnames.mk
|
|||||||
This is included by both ``prog.mk`` and ``lib.mk`` and tries to
|
This is included by both ``prog.mk`` and ``lib.mk`` and tries to
|
||||||
include ``*.libnames.mk`` of which:
|
include ``*.libnames.mk`` of which:
|
||||||
|
|
||||||
local.libnames.mk
|
``local.libnames.mk``
|
||||||
does not exist unless you create it. It is a handy way for you
|
does not exist unless you create it. It is a handy way for you
|
||||||
to customize without touching the distributed files.
|
to customize without touching the distributed files.
|
||||||
For example, on a test machine I needed to build openssl but
|
For example, on a test machine I needed to build openssl but
|
||||||
@ -217,7 +232,7 @@ local.libnames.mk
|
|||||||
The makefile created an openssl dir in ``${OBJ_libcrypto}`` to
|
The makefile created an openssl dir in ``${OBJ_libcrypto}`` to
|
||||||
gather all the headers. dpadd.mk_ did the rest.
|
gather all the headers. dpadd.mk_ did the rest.
|
||||||
|
|
||||||
host.libnames.mk
|
``host.libnames.mk``
|
||||||
contains logic to find any libs named in ``HOST_LIBS`` in
|
contains logic to find any libs named in ``HOST_LIBS`` in
|
||||||
``HOST_LIBDIRS``.
|
``HOST_LIBDIRS``.
|
||||||
|
|
||||||
@ -256,15 +271,15 @@ else in various ways::
|
|||||||
Any library (referenced by its full path) in any of the above, is
|
Any library (referenced by its full path) in any of the above, is
|
||||||
added to ``DPMAGIC_LIBS`` with the following results, for each lib *foo*.
|
added to ``DPMAGIC_LIBS`` with the following results, for each lib *foo*.
|
||||||
|
|
||||||
SRC_libfoo
|
``SRC_libfoo``
|
||||||
Is set to indicate where the src for libfoo is.
|
Is set to indicate where the src for libfoo is.
|
||||||
By default it is derived from ``LIBFOO`` by replacing
|
By default it is derived from ``LIBFOO`` by replacing
|
||||||
``${OBJTOP}`` with ``${SRCTOP}``.
|
``${OBJTOP}`` with ``${SRCTOP}``.
|
||||||
|
|
||||||
OBJ_libfoo
|
``OBJ_libfoo``
|
||||||
Not very exciting, is just the dir where libfoo lives.
|
Not very exciting, is just the dir where libfoo lives.
|
||||||
|
|
||||||
INCLUDES_libfoo
|
``INCLUDES_libfoo``
|
||||||
What to add to ``CFLAGS`` to find the public headers.
|
What to add to ``CFLAGS`` to find the public headers.
|
||||||
The default varies. If ``${SRC_libfoo}/h`` exists, it is assumed
|
The default varies. If ``${SRC_libfoo}/h`` exists, it is assumed
|
||||||
to be the home of all public headers and thus the default is
|
to be the home of all public headers and thus the default is
|
||||||
@ -273,7 +288,7 @@ INCLUDES_libfoo
|
|||||||
Otherwise we make no assumptions and the default is
|
Otherwise we make no assumptions and the default is
|
||||||
``-I${SRC_libfoo} -I${OBJ_libfoo}``
|
``-I${SRC_libfoo} -I${OBJ_libfoo}``
|
||||||
|
|
||||||
LDADD_libfoo
|
``LDADD_libfoo``
|
||||||
This only applies to libs reference via ``DPLIBS``.
|
This only applies to libs reference via ``DPLIBS``.
|
||||||
The default is ``-lfoo``, ``LDADD_*`` provides a hook to
|
The default is ``-lfoo``, ``LDADD_*`` provides a hook to
|
||||||
instantiate other linker flags at the appropriate point
|
instantiate other linker flags at the appropriate point
|
||||||
@ -303,13 +318,16 @@ object files from the src tree. This is also the source of much
|
|||||||
confusion to some.
|
confusion to some.
|
||||||
|
|
||||||
Traditionally one had to do a separate ``make obj`` pass through the
|
Traditionally one had to do a separate ``make obj`` pass through the
|
||||||
tree. If ``MKOBJDIRS`` is "auto", we include auto.obj.mk_.
|
tree. If ``MK_AUTO_OBJ`` is set we include auto.obj.mk_.
|
||||||
|
|
||||||
|
In fact if ``MKOBJDIRS`` is set to "auto", `sys.mk`_ will set
|
||||||
|
``MK_AUTO_OBJ=yes`` and include auto.obj.mk_ since it is best done early.
|
||||||
|
|
||||||
auto.obj.mk
|
auto.obj.mk
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
This leverages the ``.OBJDIR`` target introduced some years ago to
|
This leverages the ``.OBJDIR`` target introduced some years ago to
|
||||||
NetBSD make, to automatically create the desired object dir.
|
NetBSD make, to automatically create and use the desired object dir.
|
||||||
|
|
||||||
subdir.mk
|
subdir.mk
|
||||||
---------
|
---------
|
||||||
@ -334,6 +352,8 @@ you can suppress that - or enhance it by setting ``ECHO_DIR``::
|
|||||||
# print time stamps
|
# print time stamps
|
||||||
ECHO_DIR=echo @ `date "+%s [%Y-%m-%d %T] "`
|
ECHO_DIR=echo @ `date "+%s [%Y-%m-%d %T] "`
|
||||||
|
|
||||||
|
I prefer to use `dirdeps.mk`_ which makes ``subdir.mk`` irrelevant.
|
||||||
|
|
||||||
links.mk
|
links.mk
|
||||||
--------
|
--------
|
||||||
|
|
||||||
@ -367,9 +387,12 @@ dep.mk
|
|||||||
|
|
||||||
Deals with collecting dependencies. Another useful feature of BSD
|
Deals with collecting dependencies. Another useful feature of BSD
|
||||||
make is the separation of this sort of information into a ``.depend``
|
make is the separation of this sort of information into a ``.depend``
|
||||||
file. ``MKDEP`` needs to point to a suitable tool (like mkdeps.sh_)
|
file. ``MKDEP_CMD`` needs to point to a suitable tool (like mkdeps.sh_)
|
||||||
|
|
||||||
If ``USE_AUTODEP_MK`` is "yes" includes autodep.mk_
|
If ``MK_AUTODEP`` is "yes" it sets ``MKDEP_MK`` to autodep.mk_ by default.
|
||||||
|
|
||||||
|
``MKDEP_MK`` can also be set to `auto.dep.mk`_ which is more efficient
|
||||||
|
but does not support an explicit ``depend`` target.
|
||||||
|
|
||||||
autodep.mk
|
autodep.mk
|
||||||
----------
|
----------
|
||||||
@ -397,19 +420,9 @@ to avoid possible conflicts during parallel builds.
|
|||||||
This precludes the use of suffix rules to drive ``make depend``, so
|
This precludes the use of suffix rules to drive ``make depend``, so
|
||||||
dep.mk_ handles that if specifically requested.
|
dep.mk_ handles that if specifically requested.
|
||||||
|
|
||||||
options.mk
|
If ``bmake`` is 20160218 or newer, ``auto.dep.mk`` uses ``.dinclude``
|
||||||
----------
|
to includes the ``*.d`` files directly thus avoiding the need to
|
||||||
|
create a ``.depend`` file from them.
|
||||||
Inspired by FreeBSD's ``bsd.own.mk`` more flexible.
|
|
||||||
FreeBSD now have similar functionality in ``bsd.mkopt.mk``.
|
|
||||||
|
|
||||||
It allows users to express their intent with respect to options
|
|
||||||
``MK_*`` by setting ``WITH_*`` or ``WITHOUT_*``.
|
|
||||||
|
|
||||||
Note: ``WITHOUT_*`` wins if both are set, and makefiles can set
|
|
||||||
``NO_*`` to say they cannot handle that option, or even ``MK_*`` if
|
|
||||||
they really need to.
|
|
||||||
|
|
||||||
|
|
||||||
own.mk
|
own.mk
|
||||||
------
|
------
|
||||||
@ -424,7 +437,7 @@ ldorder.mk
|
|||||||
|
|
||||||
Leverages ``bmake`` to compute optimal link order for libraries.
|
Leverages ``bmake`` to compute optimal link order for libraries.
|
||||||
This works nicely and makes refactoring a breeze - so long as you
|
This works nicely and makes refactoring a breeze - so long as you
|
||||||
have not (or few) cicular dependencies between libraries.
|
have no (or few) cicular dependencies between libraries.
|
||||||
|
|
||||||
man.mk
|
man.mk
|
||||||
------
|
------
|
||||||
@ -463,6 +476,22 @@ Logic to build Python C interface modules using Cython_
|
|||||||
|
|
||||||
.. _Cython: http://www.cython.org/
|
.. _Cython: http://www.cython.org/
|
||||||
|
|
||||||
|
cc-wrap.mk
|
||||||
|
----------
|
||||||
|
|
||||||
|
This makefile leverages two new features in bmake 20220126 and later.
|
||||||
|
|
||||||
|
First is the ablity to set target local variables (GNU make has done
|
||||||
|
this for ages).
|
||||||
|
|
||||||
|
The second (only intersting if using `meta mode`_)
|
||||||
|
allows filtering commands before comparison with previous run to
|
||||||
|
decide if a target is out-of-date.
|
||||||
|
|
||||||
|
In the past, making use of compiler wrappers like ``ccache``,
|
||||||
|
``distcc`` or the newer ``icecc`` could get quite ugly.
|
||||||
|
Using ``cc-wrap.mk`` it could not be simpler.
|
||||||
|
|
||||||
Meta mode
|
Meta mode
|
||||||
=========
|
=========
|
||||||
|
|
||||||
@ -496,5 +525,5 @@ where you unpacked the tar file, you can::
|
|||||||
.. _mk.tar.gz: http://www.crufty.net/ftp/pub/sjg/mk.tar.gz
|
.. _mk.tar.gz: http://www.crufty.net/ftp/pub/sjg/mk.tar.gz
|
||||||
|
|
||||||
:Author: sjg@crufty.net
|
:Author: sjg@crufty.net
|
||||||
:Revision: $Id: mk-files.txt,v 1.20 2020/08/19 17:51:53 sjg Exp $
|
:Revision: $Id: mk-files.txt,v 1.21 2022/02/04 19:01:05 sjg Exp $
|
||||||
:Copyright: Crufty.NET
|
:Copyright: Crufty.NET
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# $Id: sys.clean-env.mk,v 1.23 2020/08/19 17:51:53 sjg Exp $
|
# $Id: sys.clean-env.mk,v 1.24 2022/01/15 17:34:42 sjg Exp $
|
||||||
#
|
#
|
||||||
# @(#) Copyright (c) 2009, Simon J. Gerraty
|
# @(#) Copyright (c) 2009, Simon J. Gerraty
|
||||||
#
|
#
|
||||||
@ -52,7 +52,7 @@ MAKE_ENV_SAVE_PREFIX_LIST += \
|
|||||||
|
|
||||||
|
|
||||||
# This could be a list of vars or patterns to explicitly exclude.
|
# This could be a list of vars or patterns to explicitly exclude.
|
||||||
MAKE_ENV_SAVE_EXCLUDE_LIST ?= _
|
MAKE_ENV_SAVE_EXCLUDE_LIST += _
|
||||||
|
|
||||||
# This is the actual list that we will save
|
# This is the actual list that we will save
|
||||||
# HOME is probably something worth clobbering eg.
|
# HOME is probably something worth clobbering eg.
|
||||||
@ -115,7 +115,7 @@ MAKEOBJDIR = $${.CURDIR:S,${_srctop},$${OBJTOP},}
|
|||||||
$v := ${$v}
|
$v := ${$v}
|
||||||
.endfor
|
.endfor
|
||||||
.else
|
.else
|
||||||
# we cannot use the '$$' trick, anymore
|
# we cannot rely on the '$$' trick (depending on .MAKE.SAVE_DOLLARS)
|
||||||
# but we can export a literal (unexpanded) value
|
# but we can export a literal (unexpanded) value
|
||||||
SRCTOP := ${_srctop}
|
SRCTOP := ${_srctop}
|
||||||
OBJROOT := ${_objroot}
|
OBJROOT := ${_objroot}
|
||||||
|
@ -1,348 +0,0 @@
|
|||||||
/* $NetBSD: nonints.h,v 1.217 2021/12/12 20:45:48 sjg Exp $ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
* This code is derived from software contributed to Berkeley by
|
|
||||||
* Adam de Boor.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the University nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* from: @(#)nonints.h 8.3 (Berkeley) 3/19/94
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 1989 by Berkeley Softworks
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This code is derived from software contributed to Berkeley by
|
|
||||||
* Adam de Boor.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. All advertising materials mentioning features or use of this software
|
|
||||||
* must display the following acknowledgement:
|
|
||||||
* This product includes software developed by the University of
|
|
||||||
* California, Berkeley and its contributors.
|
|
||||||
* 4. Neither the name of the University nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* from: @(#)nonints.h 8.3 (Berkeley) 3/19/94
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* arch.c */
|
|
||||||
void Arch_Init(void);
|
|
||||||
void Arch_End(void);
|
|
||||||
|
|
||||||
bool Arch_ParseArchive(char **, GNodeList *, GNode *);
|
|
||||||
void Arch_Touch(GNode *);
|
|
||||||
void Arch_TouchLib(GNode *);
|
|
||||||
void Arch_UpdateMTime(GNode *gn);
|
|
||||||
void Arch_UpdateMemberMTime(GNode *gn);
|
|
||||||
void Arch_FindLib(GNode *, SearchPath *);
|
|
||||||
bool Arch_LibOODate(GNode *);
|
|
||||||
bool Arch_IsLib(GNode *);
|
|
||||||
|
|
||||||
/* compat.c */
|
|
||||||
int Compat_RunCommand(const char *, GNode *, StringListNode *);
|
|
||||||
void Compat_Run(GNodeList *);
|
|
||||||
void Compat_Make(GNode *, GNode *);
|
|
||||||
|
|
||||||
/* cond.c */
|
|
||||||
CondEvalResult Cond_EvalCondition(const char *, bool *);
|
|
||||||
CondEvalResult Cond_EvalLine(const char *);
|
|
||||||
void Cond_restore_depth(unsigned int);
|
|
||||||
unsigned int Cond_save_depth(void);
|
|
||||||
|
|
||||||
/* dir.c; see also dir.h */
|
|
||||||
|
|
||||||
MAKE_INLINE const char *
|
|
||||||
str_basename(const char *pathname)
|
|
||||||
{
|
|
||||||
const char *lastSlash = strrchr(pathname, '/');
|
|
||||||
return lastSlash != NULL ? lastSlash + 1 : pathname;
|
|
||||||
}
|
|
||||||
|
|
||||||
MAKE_INLINE SearchPath *
|
|
||||||
SearchPath_New(void)
|
|
||||||
{
|
|
||||||
SearchPath *path = bmake_malloc(sizeof *path);
|
|
||||||
Lst_Init(&path->dirs);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SearchPath_Free(SearchPath *);
|
|
||||||
|
|
||||||
/* for.c */
|
|
||||||
int For_Eval(const char *);
|
|
||||||
bool For_Accum(const char *);
|
|
||||||
void For_Run(int);
|
|
||||||
|
|
||||||
/* job.c */
|
|
||||||
#ifdef WAIT_T
|
|
||||||
void JobReapChild(pid_t, WAIT_T, bool);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* main.c */
|
|
||||||
bool GetBooleanExpr(const char *, bool);
|
|
||||||
void Main_ParseArgLine(const char *);
|
|
||||||
char *Cmd_Exec(const char *, const char **);
|
|
||||||
void Error(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
|
|
||||||
void Fatal(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2) MAKE_ATTR_DEAD;
|
|
||||||
void Punt(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2) MAKE_ATTR_DEAD;
|
|
||||||
void DieHorribly(void) MAKE_ATTR_DEAD;
|
|
||||||
void Finish(int) MAKE_ATTR_DEAD;
|
|
||||||
int eunlink(const char *);
|
|
||||||
void execDie(const char *, const char *);
|
|
||||||
char *getTmpdir(void);
|
|
||||||
bool ParseBoolean(const char *, bool);
|
|
||||||
char *cached_realpath(const char *, char *);
|
|
||||||
|
|
||||||
/* parse.c */
|
|
||||||
void Parse_Init(void);
|
|
||||||
void Parse_End(void);
|
|
||||||
|
|
||||||
typedef enum VarAssignOp {
|
|
||||||
VAR_NORMAL, /* = */
|
|
||||||
VAR_SUBST, /* := */
|
|
||||||
VAR_SHELL, /* != or :sh= */
|
|
||||||
VAR_APPEND, /* += */
|
|
||||||
VAR_DEFAULT /* ?= */
|
|
||||||
} VarAssignOp;
|
|
||||||
|
|
||||||
typedef struct VarAssign {
|
|
||||||
char *varname; /* unexpanded */
|
|
||||||
VarAssignOp op;
|
|
||||||
const char *value; /* unexpanded */
|
|
||||||
} VarAssign;
|
|
||||||
|
|
||||||
typedef char *(*ReadMoreProc)(void *, size_t *);
|
|
||||||
|
|
||||||
void Parse_Error(ParseErrorLevel, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3);
|
|
||||||
bool Parse_IsVar(const char *, VarAssign *out_var);
|
|
||||||
void Parse_Var(VarAssign *, GNode *);
|
|
||||||
void Parse_AddIncludeDir(const char *);
|
|
||||||
void Parse_File(const char *, int);
|
|
||||||
void Parse_PushInput(const char *, int, int, ReadMoreProc, void *);
|
|
||||||
void Parse_MainName(GNodeList *);
|
|
||||||
int Parse_NumErrors(void);
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef HAVE_STRLCPY
|
|
||||||
/* strlcpy.c */
|
|
||||||
size_t strlcpy(char *, const char *, size_t);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* suff.c */
|
|
||||||
void Suff_Init(void);
|
|
||||||
void Suff_End(void);
|
|
||||||
|
|
||||||
void Suff_ClearSuffixes(void);
|
|
||||||
bool Suff_IsTransform(const char *);
|
|
||||||
GNode *Suff_AddTransform(const char *);
|
|
||||||
void Suff_EndTransform(GNode *);
|
|
||||||
void Suff_AddSuffix(const char *, GNode **);
|
|
||||||
SearchPath *Suff_GetPath(const char *);
|
|
||||||
void Suff_ExtendPaths(void);
|
|
||||||
void Suff_AddInclude(const char *);
|
|
||||||
void Suff_AddLib(const char *);
|
|
||||||
void Suff_FindDeps(GNode *);
|
|
||||||
SearchPath *Suff_FindPath(GNode *);
|
|
||||||
void Suff_SetNull(const char *);
|
|
||||||
void Suff_PrintAll(void);
|
|
||||||
const char *Suff_NamesStr(void);
|
|
||||||
|
|
||||||
/* targ.c */
|
|
||||||
void Targ_Init(void);
|
|
||||||
void Targ_End(void);
|
|
||||||
|
|
||||||
void Targ_Stats(void);
|
|
||||||
GNodeList *Targ_List(void);
|
|
||||||
GNode *GNode_New(const char *);
|
|
||||||
GNode *Targ_FindNode(const char *);
|
|
||||||
GNode *Targ_GetNode(const char *);
|
|
||||||
GNode *Targ_NewInternalNode(const char *);
|
|
||||||
GNode *Targ_GetEndNode(void);
|
|
||||||
void Targ_FindList(GNodeList *, StringList *);
|
|
||||||
bool Targ_Precious(const GNode *);
|
|
||||||
void Targ_SetMain(GNode *);
|
|
||||||
void Targ_PrintCmds(GNode *);
|
|
||||||
void Targ_PrintNode(GNode *, int);
|
|
||||||
void Targ_PrintNodes(GNodeList *, int);
|
|
||||||
const char *Targ_FmtTime(time_t);
|
|
||||||
void Targ_PrintType(GNodeType);
|
|
||||||
void Targ_PrintGraph(int);
|
|
||||||
void Targ_Propagate(void);
|
|
||||||
const char *GNodeMade_Name(GNodeMade);
|
|
||||||
|
|
||||||
/* var.c */
|
|
||||||
void Var_Init(void);
|
|
||||||
void Var_End(void);
|
|
||||||
|
|
||||||
typedef enum VarEvalMode {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Only parse the expression but don't evaluate any part of it.
|
|
||||||
*
|
|
||||||
* TODO: Document what Var_Parse and Var_Subst return in this mode.
|
|
||||||
* As of 2021-03-15, they return unspecified, inconsistent results.
|
|
||||||
*/
|
|
||||||
VARE_PARSE_ONLY,
|
|
||||||
|
|
||||||
/* Parse and evaluate the expression. */
|
|
||||||
VARE_WANTRES,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse and evaluate the expression. It is an error if a
|
|
||||||
* subexpression evaluates to undefined.
|
|
||||||
*/
|
|
||||||
VARE_UNDEFERR,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse and evaluate the expression. Keep '$$' as '$$' instead of
|
|
||||||
* reducing it to a single '$'. Subexpressions that evaluate to
|
|
||||||
* undefined expand to an empty string.
|
|
||||||
*
|
|
||||||
* Used in variable assignments using the ':=' operator. It allows
|
|
||||||
* multiple such assignments to be chained without accidentally
|
|
||||||
* expanding '$$file' to '$file' in the first assignment and
|
|
||||||
* interpreting it as '${f}' followed by 'ile' in the next assignment.
|
|
||||||
*/
|
|
||||||
VARE_EVAL_KEEP_DOLLAR,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse and evaluate the expression. Keep undefined variables as-is
|
|
||||||
* instead of expanding them to an empty string.
|
|
||||||
*
|
|
||||||
* Example for a ':=' assignment:
|
|
||||||
* CFLAGS = $(.INCLUDES)
|
|
||||||
* CFLAGS := -I.. $(CFLAGS)
|
|
||||||
* # If .INCLUDES (an undocumented special variable, by the
|
|
||||||
* # way) is still undefined, the updated CFLAGS becomes
|
|
||||||
* # "-I.. $(.INCLUDES)".
|
|
||||||
*/
|
|
||||||
VARE_EVAL_KEEP_UNDEF,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse and evaluate the expression. Keep '$$' as '$$' and preserve
|
|
||||||
* undefined subexpressions.
|
|
||||||
*/
|
|
||||||
VARE_KEEP_DOLLAR_UNDEF
|
|
||||||
} VarEvalMode;
|
|
||||||
|
|
||||||
typedef enum VarSetFlags {
|
|
||||||
VAR_SET_NONE = 0,
|
|
||||||
|
|
||||||
/* do not export */
|
|
||||||
VAR_SET_NO_EXPORT = 1 << 0,
|
|
||||||
|
|
||||||
/* Make the variable read-only. No further modification is possible,
|
|
||||||
* except for another call to Var_Set with the same flag. */
|
|
||||||
VAR_SET_READONLY = 1 << 1
|
|
||||||
} VarSetFlags;
|
|
||||||
|
|
||||||
/* The state of error handling returned by Var_Parse. */
|
|
||||||
typedef enum VarParseResult {
|
|
||||||
|
|
||||||
/* Both parsing and evaluation succeeded. */
|
|
||||||
VPR_OK,
|
|
||||||
|
|
||||||
/* Parsing or evaluating failed, with an error message. */
|
|
||||||
VPR_ERR,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parsing succeeded, undefined expressions are allowed and the
|
|
||||||
* expression was still undefined after applying all modifiers.
|
|
||||||
* No error message is printed in this case.
|
|
||||||
*
|
|
||||||
* Some callers handle this case differently, so return this
|
|
||||||
* information to them, for now.
|
|
||||||
*
|
|
||||||
* TODO: Instead of having this special return value, rather ensure
|
|
||||||
* that VARE_EVAL_KEEP_UNDEF is processed properly.
|
|
||||||
*/
|
|
||||||
VPR_UNDEF
|
|
||||||
|
|
||||||
} VarParseResult;
|
|
||||||
|
|
||||||
typedef enum VarExportMode {
|
|
||||||
/* .export-env */
|
|
||||||
VEM_ENV,
|
|
||||||
/* .export: Initial export or update an already exported variable. */
|
|
||||||
VEM_PLAIN,
|
|
||||||
/* .export-literal: Do not expand the variable value. */
|
|
||||||
VEM_LITERAL
|
|
||||||
} VarExportMode;
|
|
||||||
|
|
||||||
void Var_Delete(GNode *, const char *);
|
|
||||||
void Var_DeleteExpand(GNode *, const char *);
|
|
||||||
void Var_Undef(const char *);
|
|
||||||
void Var_Set(GNode *, const char *, const char *);
|
|
||||||
void Var_SetExpand(GNode *, const char *, const char *);
|
|
||||||
void Var_SetWithFlags(GNode *, const char *, const char *, VarSetFlags);
|
|
||||||
void Var_SetExpandWithFlags(GNode *, const char *, const char *, VarSetFlags);
|
|
||||||
void Var_Append(GNode *, const char *, const char *);
|
|
||||||
void Var_AppendExpand(GNode *, const char *, const char *);
|
|
||||||
bool Var_Exists(GNode *, const char *);
|
|
||||||
bool Var_ExistsExpand(GNode *, const char *);
|
|
||||||
FStr Var_Value(GNode *, const char *);
|
|
||||||
const char *GNode_ValueDirect(GNode *, const char *);
|
|
||||||
VarParseResult Var_Parse(const char **, GNode *, VarEvalMode, FStr *);
|
|
||||||
VarParseResult Var_Subst(const char *, GNode *, VarEvalMode, char **);
|
|
||||||
void Var_Stats(void);
|
|
||||||
void Var_Dump(GNode *);
|
|
||||||
void Var_ReexportVars(void);
|
|
||||||
void Var_Export(VarExportMode, const char *);
|
|
||||||
void Var_ExportVars(const char *);
|
|
||||||
void Var_UnExport(bool, const char *);
|
|
||||||
|
|
||||||
void Global_Set(const char *, const char *);
|
|
||||||
void Global_SetExpand(const char *, const char *);
|
|
||||||
void Global_Append(const char *, const char *);
|
|
||||||
void Global_Delete(const char *);
|
|
||||||
|
|
||||||
/* util.c */
|
|
||||||
typedef void (*SignalProc)(int);
|
|
||||||
SignalProc bmake_signal(int, SignalProc);
|
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: str.c,v 1.86 2021/06/21 16:59:18 rillig Exp $ */
|
/* $NetBSD: str.c,v 1.88 2021/12/15 10:57:01 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
* Copyright (c) 1988, 1989, 1990, 1993
|
||||||
@ -71,7 +71,11 @@
|
|||||||
#include "make.h"
|
#include "make.h"
|
||||||
|
|
||||||
/* "@(#)str.c 5.8 (Berkeley) 6/1/90" */
|
/* "@(#)str.c 5.8 (Berkeley) 6/1/90" */
|
||||||
MAKE_RCSID("$NetBSD: str.c,v 1.86 2021/06/21 16:59:18 rillig Exp $");
|
MAKE_RCSID("$NetBSD: str.c,v 1.88 2021/12/15 10:57:01 rillig Exp $");
|
||||||
|
|
||||||
|
|
||||||
|
static HashTable interned_strings;
|
||||||
|
|
||||||
|
|
||||||
/* Return the concatenation of s1 and s2, freshly allocated. */
|
/* Return the concatenation of s1 and s2, freshly allocated. */
|
||||||
char *
|
char *
|
||||||
@ -395,3 +399,24 @@ Str_Match(const char *str, const char *pat)
|
|||||||
str++;
|
str++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Str_Intern_Init(void)
|
||||||
|
{
|
||||||
|
HashTable_Init(&interned_strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Str_Intern_End(void)
|
||||||
|
{
|
||||||
|
#ifdef CLEANUP
|
||||||
|
HashTable_Done(&interned_strings);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a canonical instance of str, with unlimited lifetime. */
|
||||||
|
const char *
|
||||||
|
Str_Intern(const char *str)
|
||||||
|
{
|
||||||
|
return HashTable_CreateEntry(&interned_strings, str, NULL)->key;
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: str.h,v 1.12 2021/12/12 13:43:47 rillig Exp $ */
|
/* $NetBSD: str.h,v 1.15 2021/12/15 10:57:01 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2021 Roland Illig <rillig@NetBSD.org>
|
Copyright (c) 2021 Roland Illig <rillig@NetBSD.org>
|
||||||
@ -39,12 +39,6 @@ typedef struct FStr {
|
|||||||
void *freeIt;
|
void *freeIt;
|
||||||
} FStr;
|
} FStr;
|
||||||
|
|
||||||
/* A modifiable string that may need to be freed after use. */
|
|
||||||
typedef struct MFStr {
|
|
||||||
char *str;
|
|
||||||
void *freeIt;
|
|
||||||
} MFStr;
|
|
||||||
|
|
||||||
/* A read-only range of a character array, NOT null-terminated. */
|
/* A read-only range of a character array, NOT null-terminated. */
|
||||||
typedef struct Substring {
|
typedef struct Substring {
|
||||||
const char *start;
|
const char *start;
|
||||||
@ -111,40 +105,6 @@ FStr_Done(FStr *fstr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MAKE_INLINE MFStr
|
|
||||||
MFStr_Init(char *str, void *freeIt)
|
|
||||||
{
|
|
||||||
MFStr mfstr;
|
|
||||||
mfstr.str = str;
|
|
||||||
mfstr.freeIt = freeIt;
|
|
||||||
return mfstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return a string that is the sole owner of str. */
|
|
||||||
MAKE_INLINE MFStr
|
|
||||||
MFStr_InitOwn(char *str)
|
|
||||||
{
|
|
||||||
return MFStr_Init(str, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return a string that refers to the shared str. */
|
|
||||||
MAKE_INLINE MFStr
|
|
||||||
MFStr_InitRefer(char *str)
|
|
||||||
{
|
|
||||||
return MFStr_Init(str, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
MAKE_INLINE void
|
|
||||||
MFStr_Done(MFStr *mfstr)
|
|
||||||
{
|
|
||||||
free(mfstr->freeIt);
|
|
||||||
#ifdef CLEANUP
|
|
||||||
mfstr->str = NULL;
|
|
||||||
mfstr->freeIt = NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MAKE_STATIC Substring
|
MAKE_STATIC Substring
|
||||||
Substring_Init(const char *start, const char *end)
|
Substring_Init(const char *start, const char *end)
|
||||||
{
|
{
|
||||||
@ -383,3 +343,7 @@ char *str_concat2(const char *, const char *);
|
|||||||
char *str_concat3(const char *, const char *, const char *);
|
char *str_concat3(const char *, const char *, const char *);
|
||||||
|
|
||||||
bool Str_Match(const char *, const char *);
|
bool Str_Match(const char *, const char *);
|
||||||
|
|
||||||
|
void Str_Intern_Init(void);
|
||||||
|
void Str_Intern_End(void);
|
||||||
|
const char *Str_Intern(const char *);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: suff.c,v 1.357 2021/12/12 20:45:48 sjg Exp $ */
|
/* $NetBSD: suff.c,v 1.364 2022/01/07 20:54:45 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
* Copyright (c) 1988, 1989, 1990, 1993
|
||||||
@ -115,7 +115,7 @@
|
|||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
|
|
||||||
/* "@(#)suff.c 8.4 (Berkeley) 3/21/94" */
|
/* "@(#)suff.c 8.4 (Berkeley) 3/21/94" */
|
||||||
MAKE_RCSID("$NetBSD: suff.c,v 1.357 2021/12/12 20:45:48 sjg Exp $");
|
MAKE_RCSID("$NetBSD: suff.c,v 1.364 2022/01/07 20:54:45 rillig Exp $");
|
||||||
|
|
||||||
typedef List SuffixList;
|
typedef List SuffixList;
|
||||||
typedef ListNode SuffixListNode;
|
typedef ListNode SuffixListNode;
|
||||||
@ -207,20 +207,26 @@ typedef struct Suffix {
|
|||||||
typedef struct Candidate {
|
typedef struct Candidate {
|
||||||
/* The file or node to look for. */
|
/* The file or node to look for. */
|
||||||
char *file;
|
char *file;
|
||||||
/* The prefix from which file was formed.
|
/*
|
||||||
* Its memory is shared among all candidates. */
|
* The prefix from which file was formed. Its memory is shared among
|
||||||
|
* all candidates.
|
||||||
|
*/
|
||||||
char *prefix;
|
char *prefix;
|
||||||
/* The suffix on the file. */
|
/* The suffix on the file. */
|
||||||
Suffix *suff;
|
Suffix *suff;
|
||||||
|
|
||||||
/* The candidate that can be made from this,
|
/*
|
||||||
* or NULL for the top-level candidate. */
|
* The candidate that can be made from this, or NULL for the
|
||||||
|
* top-level candidate.
|
||||||
|
*/
|
||||||
struct Candidate *parent;
|
struct Candidate *parent;
|
||||||
/* The node describing the file. */
|
/* The node describing the file. */
|
||||||
GNode *node;
|
GNode *node;
|
||||||
|
|
||||||
/* Count of existing children, only used for memory management, so we
|
/*
|
||||||
* don't free this candidate too early or too late. */
|
* Count of existing children, only used for memory management, so we
|
||||||
|
* don't free this candidate too early or too late.
|
||||||
|
*/
|
||||||
int numChildren;
|
int numChildren;
|
||||||
#ifdef DEBUG_SRC
|
#ifdef DEBUG_SRC
|
||||||
CandidateList childrenList;
|
CandidateList childrenList;
|
||||||
@ -240,7 +246,7 @@ typedef struct CandidateSearcher {
|
|||||||
|
|
||||||
|
|
||||||
/* TODO: Document the difference between nullSuff and emptySuff. */
|
/* TODO: Document the difference between nullSuff and emptySuff. */
|
||||||
/* The NULL suffix for this run */
|
/* The NULL suffix is used when a file has no known suffix */
|
||||||
static Suffix *nullSuff;
|
static Suffix *nullSuff;
|
||||||
/* The empty suffix required for POSIX single-suffix transformation rules */
|
/* The empty suffix required for POSIX single-suffix transformation rules */
|
||||||
static Suffix *emptySuff;
|
static Suffix *emptySuff;
|
||||||
@ -692,7 +698,9 @@ RebuildGraph(GNode *transform, Suffix *suff)
|
|||||||
size_t nameLen = strlen(name);
|
size_t nameLen = strlen(name);
|
||||||
const char *toName;
|
const char *toName;
|
||||||
|
|
||||||
/* See if it is a transformation from this suffix to another suffix. */
|
/*
|
||||||
|
* See if it is a transformation from this suffix to another suffix.
|
||||||
|
*/
|
||||||
toName = StrTrimPrefix(suff->name, name);
|
toName = StrTrimPrefix(suff->name, name);
|
||||||
if (toName != NULL) {
|
if (toName != NULL) {
|
||||||
Suffix *to = FindSuffixByName(toName);
|
Suffix *to = FindSuffixByName(toName);
|
||||||
@ -702,7 +710,9 @@ RebuildGraph(GNode *transform, Suffix *suff)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if it is a transformation from another suffix to this suffix. */
|
/*
|
||||||
|
* See if it is a transformation from another suffix to this suffix.
|
||||||
|
*/
|
||||||
toName = Suffix_TrimSuffix(suff, nameLen, name + nameLen);
|
toName = Suffix_TrimSuffix(suff, nameLen, name + nameLen);
|
||||||
if (toName != NULL) {
|
if (toName != NULL) {
|
||||||
Suffix *from = FindSuffixByNameLen(name,
|
Suffix *from = FindSuffixByNameLen(name,
|
||||||
@ -724,17 +734,15 @@ RebuildGraph(GNode *transform, Suffix *suff)
|
|||||||
* true iff a new main target has been selected.
|
* true iff a new main target has been selected.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
UpdateTarget(GNode *target, GNode **inout_main, Suffix *suff,
|
UpdateTarget(GNode *target, Suffix *suff, bool *inout_removedMain)
|
||||||
bool *inout_removedMain)
|
|
||||||
{
|
{
|
||||||
Suffix *srcSuff, *targSuff;
|
Suffix *srcSuff, *targSuff;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
||||||
if (*inout_main == NULL && *inout_removedMain &&
|
if (mainNode == NULL && *inout_removedMain &&
|
||||||
!(target->type & OP_NOTARGET)) {
|
GNode_IsMainCandidate(target)) {
|
||||||
DEBUG1(MAKE, "Setting main node to \"%s\"\n", target->name);
|
DEBUG1(MAKE, "Setting main node to \"%s\"\n", target->name);
|
||||||
*inout_main = target;
|
mainNode = target;
|
||||||
Targ_SetMain(target);
|
|
||||||
/*
|
/*
|
||||||
* XXX: Why could it be a good idea to return true here?
|
* XXX: Why could it be a good idea to return true here?
|
||||||
* The main task of this function is to turn ordinary nodes
|
* The main task of this function is to turn ordinary nodes
|
||||||
@ -772,13 +780,12 @@ UpdateTarget(GNode *target, GNode **inout_main, Suffix *suff,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (ParseTransform(target->name, &srcSuff, &targSuff)) {
|
if (ParseTransform(target->name, &srcSuff, &targSuff)) {
|
||||||
if (*inout_main == target) {
|
if (mainNode == target) {
|
||||||
DEBUG1(MAKE,
|
DEBUG1(MAKE,
|
||||||
"Setting main node from \"%s\" back to null\n",
|
"Setting main node from \"%s\" back to null\n",
|
||||||
target->name);
|
target->name);
|
||||||
*inout_removedMain = true;
|
*inout_removedMain = true;
|
||||||
*inout_main = NULL;
|
mainNode = NULL;
|
||||||
Targ_SetMain(NULL);
|
|
||||||
}
|
}
|
||||||
Lst_Done(&target->children);
|
Lst_Done(&target->children);
|
||||||
Lst_Init(&target->children);
|
Lst_Init(&target->children);
|
||||||
@ -802,14 +809,14 @@ UpdateTarget(GNode *target, GNode **inout_main, Suffix *suff,
|
|||||||
* suffix rules.
|
* suffix rules.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
UpdateTargets(GNode **inout_main, Suffix *suff)
|
UpdateTargets(Suffix *suff)
|
||||||
{
|
{
|
||||||
bool removedMain = false;
|
bool removedMain = false;
|
||||||
GNodeListNode *ln;
|
GNodeListNode *ln;
|
||||||
|
|
||||||
for (ln = Targ_List()->first; ln != NULL; ln = ln->next) {
|
for (ln = Targ_List()->first; ln != NULL; ln = ln->next) {
|
||||||
GNode *gn = ln->datum;
|
GNode *gn = ln->datum;
|
||||||
if (UpdateTarget(gn, inout_main, suff, &removedMain))
|
if (UpdateTarget(gn, suff, &removedMain))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -828,7 +835,7 @@ UpdateTargets(GNode **inout_main, Suffix *suff)
|
|||||||
* name the name of the suffix to add
|
* name the name of the suffix to add
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
Suff_AddSuffix(const char *name, GNode **inout_main)
|
Suff_AddSuffix(const char *name)
|
||||||
{
|
{
|
||||||
GNodeListNode *ln;
|
GNodeListNode *ln;
|
||||||
|
|
||||||
@ -840,7 +847,7 @@ Suff_AddSuffix(const char *name, GNode **inout_main)
|
|||||||
Lst_Append(&sufflist, suff);
|
Lst_Append(&sufflist, suff);
|
||||||
DEBUG1(SUFF, "Adding suffix \"%s\"\n", suff->name);
|
DEBUG1(SUFF, "Adding suffix \"%s\"\n", suff->name);
|
||||||
|
|
||||||
UpdateTargets(inout_main, suff);
|
UpdateTargets(suff);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look for any existing transformations from or to this suffix.
|
* Look for any existing transformations from or to this suffix.
|
||||||
@ -1197,7 +1204,9 @@ FindCmds(Candidate *targ, CandidateSearcher *cs)
|
|||||||
base = str_basename(sgn->name);
|
base = str_basename(sgn->name);
|
||||||
if (strncmp(base, targ->prefix, prefLen) != 0)
|
if (strncmp(base, targ->prefix, prefLen) != 0)
|
||||||
continue;
|
continue;
|
||||||
/* The node matches the prefix, see if it has a known suffix. */
|
/*
|
||||||
|
* The node matches the prefix, see if it has a known suffix.
|
||||||
|
*/
|
||||||
suff = FindSuffixByName(base + prefLen);
|
suff = FindSuffixByName(base + prefLen);
|
||||||
if (suff == NULL)
|
if (suff == NULL)
|
||||||
continue;
|
continue;
|
||||||
@ -1254,7 +1263,7 @@ ExpandWildcards(GNodeListNode *cln, GNode *pgn)
|
|||||||
DEBUG1(SUFF, "%s...", cp);
|
DEBUG1(SUFF, "%s...", cp);
|
||||||
gn = Targ_GetNode(cp);
|
gn = Targ_GetNode(cp);
|
||||||
|
|
||||||
/* Add gn to the parents child list before the original child */
|
/* Insert gn before the original child. */
|
||||||
Lst_InsertBefore(&pgn->children, cln, gn);
|
Lst_InsertBefore(&pgn->children, cln, gn);
|
||||||
Lst_Append(&gn->parents, pgn);
|
Lst_Append(&gn->parents, pgn);
|
||||||
pgn->unmade++;
|
pgn->unmade++;
|
||||||
@ -1767,8 +1776,7 @@ FindDepsRegularPath(GNode *gn, Candidate *targ)
|
|||||||
|
|
||||||
free(gn->path);
|
free(gn->path);
|
||||||
gn->path = Dir_FindFile(gn->name,
|
gn->path = Dir_FindFile(gn->name,
|
||||||
(targ == NULL ? &dirSearchPath :
|
targ == NULL ? &dirSearchPath : targ->suff->searchPath);
|
||||||
targ->suff->searchPath));
|
|
||||||
if (gn->path == NULL)
|
if (gn->path == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -2178,7 +2186,7 @@ Suff_PrintAll(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
char *
|
||||||
Suff_NamesStr(void)
|
Suff_NamesStr(void)
|
||||||
{
|
{
|
||||||
Buffer buf;
|
Buffer buf;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: targ.c,v 1.173 2021/11/28 19:51:06 rillig Exp $ */
|
/* $NetBSD: targ.c,v 1.176 2022/01/07 20:50:35 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
* Copyright (c) 1988, 1989, 1990, 1993
|
||||||
@ -78,10 +78,8 @@
|
|||||||
*
|
*
|
||||||
* Targ_List Return the list of all targets so far.
|
* Targ_List Return the list of all targets so far.
|
||||||
*
|
*
|
||||||
* GNode_New Create a new GNode for the passed target
|
* GNode_New Create a new GNode with the given name, don't add it
|
||||||
* (string). The node is *not* placed in the
|
* to allNodes.
|
||||||
* hash table, though all its fields are
|
|
||||||
* initialized.
|
|
||||||
*
|
*
|
||||||
* Targ_FindNode Find the node, or return NULL.
|
* Targ_FindNode Find the node, or return NULL.
|
||||||
*
|
*
|
||||||
@ -93,9 +91,6 @@
|
|||||||
* Targ_FindList Given a list of names, find nodes for all
|
* Targ_FindList Given a list of names, find nodes for all
|
||||||
* of them, creating them as necessary.
|
* of them, creating them as necessary.
|
||||||
*
|
*
|
||||||
* Targ_Precious Return true if the target is precious and
|
|
||||||
* should not be removed if we are interrupted.
|
|
||||||
*
|
|
||||||
* Targ_Propagate Propagate information between related nodes.
|
* Targ_Propagate Propagate information between related nodes.
|
||||||
* Should be called after the makefiles are parsed
|
* Should be called after the makefiles are parsed
|
||||||
* but before any action is taken.
|
* but before any action is taken.
|
||||||
@ -103,8 +98,7 @@
|
|||||||
* Debugging:
|
* Debugging:
|
||||||
* Targ_PrintGraph
|
* Targ_PrintGraph
|
||||||
* Print out the entire graph, all variables and
|
* Print out the entire graph, all variables and
|
||||||
* statistics for the directory cache. Should print
|
* statistics for the directory cache.
|
||||||
* something for suffixes, too, but...
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@ -113,7 +107,7 @@
|
|||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
|
|
||||||
/* "@(#)targ.c 8.2 (Berkeley) 3/19/94" */
|
/* "@(#)targ.c 8.2 (Berkeley) 3/19/94" */
|
||||||
MAKE_RCSID("$NetBSD: targ.c,v 1.173 2021/11/28 19:51:06 rillig Exp $");
|
MAKE_RCSID("$NetBSD: targ.c,v 1.176 2022/01/07 20:50:35 rillig Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All target nodes that appeared on the left-hand side of one of the
|
* All target nodes that appeared on the left-hand side of one of the
|
||||||
@ -346,27 +340,6 @@ Targ_FindList(GNodeList *gns, StringList *names)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if the given target is precious. */
|
|
||||||
bool
|
|
||||||
Targ_Precious(const GNode *gn)
|
|
||||||
{
|
|
||||||
/* XXX: Why are '::' targets precious? */
|
|
||||||
return allPrecious || gn->type & (OP_PRECIOUS | OP_DOUBLEDEP);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The main target to be made; only for debugging output.
|
|
||||||
* See mainNode in parse.c for the definitive source.
|
|
||||||
*/
|
|
||||||
static GNode *mainTarg;
|
|
||||||
|
|
||||||
/* Remember the main target to make; only used for debugging. */
|
|
||||||
void
|
|
||||||
Targ_SetMain(GNode *gn)
|
|
||||||
{
|
|
||||||
mainTarg = gn;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
PrintNodeNames(GNodeList *gnodes)
|
PrintNodeNames(GNodeList *gnodes)
|
||||||
{
|
{
|
||||||
@ -508,7 +481,7 @@ Targ_PrintNode(GNode *gn, int pass)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
debug_printf("#\n");
|
debug_printf("#\n");
|
||||||
if (gn == mainTarg)
|
if (gn == mainNode)
|
||||||
debug_printf("# *** MAIN TARGET ***\n");
|
debug_printf("# *** MAIN TARGET ***\n");
|
||||||
|
|
||||||
if (pass >= 2) {
|
if (pass >= 2) {
|
||||||
@ -556,7 +529,6 @@ Targ_PrintNodes(GNodeList *gnodes, int pass)
|
|||||||
Targ_PrintNode(ln->datum, pass);
|
Targ_PrintNode(ln->datum, pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print only those targets that are just a source. */
|
|
||||||
static void
|
static void
|
||||||
PrintOnlySources(void)
|
PrintOnlySources(void)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: trace.c,v 1.29 2021/09/21 23:06:18 rillig Exp $ */
|
/* $NetBSD: trace.c,v 1.31 2022/02/05 00:26:21 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||||
@ -48,7 +48,7 @@
|
|||||||
#include "job.h"
|
#include "job.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
MAKE_RCSID("$NetBSD: trace.c,v 1.29 2021/09/21 23:06:18 rillig Exp $");
|
MAKE_RCSID("$NetBSD: trace.c,v 1.31 2022/02/05 00:26:21 rillig Exp $");
|
||||||
|
|
||||||
static FILE *trfile;
|
static FILE *trfile;
|
||||||
static pid_t trpid;
|
static pid_t trpid;
|
||||||
@ -69,8 +69,10 @@ Trace_Init(const char *pathname)
|
|||||||
if (pathname != NULL) {
|
if (pathname != NULL) {
|
||||||
FStr curDir;
|
FStr curDir;
|
||||||
trpid = getpid();
|
trpid = getpid();
|
||||||
/* XXX: This variable may get overwritten later, which
|
/*
|
||||||
* would make trwd point to undefined behavior. */
|
* XXX: This variable may get overwritten later, which would
|
||||||
|
* make trwd point to undefined behavior.
|
||||||
|
*/
|
||||||
curDir = Var_Value(SCOPE_GLOBAL, ".CURDIR");
|
curDir = Var_Value(SCOPE_GLOBAL, ".CURDIR");
|
||||||
trwd = curDir.str;
|
trwd = curDir.str;
|
||||||
|
|
||||||
@ -88,10 +90,17 @@ Trace_Log(TrEvent event, Job *job)
|
|||||||
|
|
||||||
gettimeofday(&rightnow, NULL);
|
gettimeofday(&rightnow, NULL);
|
||||||
|
|
||||||
|
#if __STDC__ >= 199901L
|
||||||
fprintf(trfile, "%lld.%06ld %d %s %d %s",
|
fprintf(trfile, "%lld.%06ld %d %s %d %s",
|
||||||
(long long)rightnow.tv_sec, (long)rightnow.tv_usec,
|
(long long)rightnow.tv_sec, (long)rightnow.tv_usec,
|
||||||
jobTokensRunning,
|
jobTokensRunning,
|
||||||
evname[event], trpid, trwd);
|
evname[event], trpid, trwd);
|
||||||
|
#else
|
||||||
|
fprintf(trfile, "%ld.%06ld %d %s %d %s",
|
||||||
|
(long)rightnow.tv_sec, (long)rightnow.tv_usec,
|
||||||
|
jobTokensRunning,
|
||||||
|
evname[event], trpid, trwd);
|
||||||
|
#endif
|
||||||
if (job != NULL) {
|
if (job != NULL) {
|
||||||
char flags[4];
|
char flags[4];
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# $Id: Makefile,v 1.164 2021/12/12 22:50:00 sjg Exp $
|
# $Id: Makefile,v 1.171 2022/01/28 21:33:18 sjg Exp $
|
||||||
#
|
#
|
||||||
# $NetBSD: Makefile,v 1.288 2021/12/12 22:16:48 rillig Exp $
|
# $NetBSD: Makefile,v 1.302 2022/01/27 21:50:50 sjg Exp $
|
||||||
#
|
#
|
||||||
# Unit tests for make(1)
|
# Unit tests for make(1)
|
||||||
#
|
#
|
||||||
@ -91,8 +91,10 @@ TESTS+= dep-colon
|
|||||||
TESTS+= dep-colon-bug-cross-file
|
TESTS+= dep-colon-bug-cross-file
|
||||||
TESTS+= dep-double-colon
|
TESTS+= dep-double-colon
|
||||||
TESTS+= dep-double-colon-indep
|
TESTS+= dep-double-colon-indep
|
||||||
|
TESTS+= dep-duplicate
|
||||||
TESTS+= dep-exclam
|
TESTS+= dep-exclam
|
||||||
TESTS+= dep-none
|
TESTS+= dep-none
|
||||||
|
TESTS+= dep-op-missing
|
||||||
TESTS+= dep-percent
|
TESTS+= dep-percent
|
||||||
TESTS+= dep-var
|
TESTS+= dep-var
|
||||||
TESTS+= dep-wildcards
|
TESTS+= dep-wildcards
|
||||||
@ -189,7 +191,6 @@ TESTS+= directive-warning
|
|||||||
TESTS+= dollar
|
TESTS+= dollar
|
||||||
TESTS+= doterror
|
TESTS+= doterror
|
||||||
TESTS+= dotwait
|
TESTS+= dotwait
|
||||||
TESTS+= envfirst
|
|
||||||
TESTS+= error
|
TESTS+= error
|
||||||
TESTS+= # escape # broken by reverting POSIX changes
|
TESTS+= # escape # broken by reverting POSIX changes
|
||||||
TESTS+= export
|
TESTS+= export
|
||||||
@ -216,8 +217,6 @@ TESTS+= meta-cmd-cmp
|
|||||||
TESTS+= moderrs
|
TESTS+= moderrs
|
||||||
TESTS+= modmatch
|
TESTS+= modmatch
|
||||||
TESTS+= modmisc
|
TESTS+= modmisc
|
||||||
TESTS+= modts
|
|
||||||
TESTS+= modword
|
|
||||||
.if ${.MAKE.UID} > 0
|
.if ${.MAKE.UID} > 0
|
||||||
TESTS+= objdir-writable
|
TESTS+= objdir-writable
|
||||||
.endif
|
.endif
|
||||||
@ -273,10 +272,12 @@ TESTS+= opt-touch-jobs
|
|||||||
TESTS+= opt-tracefile
|
TESTS+= opt-tracefile
|
||||||
TESTS+= opt-var-expanded
|
TESTS+= opt-var-expanded
|
||||||
TESTS+= opt-var-literal
|
TESTS+= opt-var-literal
|
||||||
|
TESTS+= opt-version
|
||||||
TESTS+= opt-warnings-as-errors
|
TESTS+= opt-warnings-as-errors
|
||||||
TESTS+= opt-where-am-i
|
TESTS+= opt-where-am-i
|
||||||
TESTS+= opt-x-reduce-exported
|
TESTS+= opt-x-reduce-exported
|
||||||
TESTS+= order
|
TESTS+= order
|
||||||
|
TESTS+= parse
|
||||||
TESTS+= parse-var
|
TESTS+= parse-var
|
||||||
TESTS+= phony-end
|
TESTS+= phony-end
|
||||||
TESTS+= posix
|
TESTS+= posix
|
||||||
@ -319,12 +320,12 @@ TESTS+= ternary
|
|||||||
TESTS+= unexport
|
TESTS+= unexport
|
||||||
TESTS+= unexport-env
|
TESTS+= unexport-env
|
||||||
TESTS+= use-inference
|
TESTS+= use-inference
|
||||||
TESTS+= var-class
|
TESTS+= var-scope
|
||||||
TESTS+= var-class-cmdline
|
TESTS+= var-scope-cmdline
|
||||||
TESTS+= var-class-env
|
TESTS+= var-scope-env
|
||||||
TESTS+= var-class-global
|
TESTS+= var-scope-global
|
||||||
TESTS+= var-class-local
|
TESTS+= var-scope-local
|
||||||
TESTS+= var-class-local-legacy
|
TESTS+= var-scope-local-legacy
|
||||||
TESTS+= var-eval-short
|
TESTS+= var-eval-short
|
||||||
TESTS+= var-op
|
TESTS+= var-op
|
||||||
TESTS+= var-op-append
|
TESTS+= var-op-append
|
||||||
@ -340,6 +341,7 @@ TESTS+= varfind
|
|||||||
TESTS+= varmisc
|
TESTS+= varmisc
|
||||||
TESTS+= varmod
|
TESTS+= varmod
|
||||||
TESTS+= varmod-assign
|
TESTS+= varmod-assign
|
||||||
|
TESTS+= varmod-assign-shell
|
||||||
TESTS+= varmod-defined
|
TESTS+= varmod-defined
|
||||||
TESTS+= varmod-edge
|
TESTS+= varmod-edge
|
||||||
TESTS+= varmod-exclam-shell
|
TESTS+= varmod-exclam-shell
|
||||||
@ -498,7 +500,6 @@ ENV.varname-vpath+= VPATH=varname-vpath.dir:varname-vpath.dir2
|
|||||||
# If possible, write ".MAKEFLAGS: -dv" in the test .mk file instead of
|
# If possible, write ".MAKEFLAGS: -dv" in the test .mk file instead of
|
||||||
# settings FLAGS.test=-dv here, since that is closer to the test code.
|
# settings FLAGS.test=-dv here, since that is closer to the test code.
|
||||||
FLAGS.cond-func-make= via-cmdline
|
FLAGS.cond-func-make= via-cmdline
|
||||||
FLAGS.directive-ifmake= first second
|
|
||||||
FLAGS.doterror= # none, especially not -k
|
FLAGS.doterror= # none, especially not -k
|
||||||
FLAGS.jobs-error-indirect= # none, especially not -k
|
FLAGS.jobs-error-indirect= # none, especially not -k
|
||||||
FLAGS.jobs-error-nested= # none, especially not -k
|
FLAGS.jobs-error-nested= # none, especially not -k
|
||||||
@ -531,6 +532,7 @@ SED_CMDS.opt-chdir= -e 's,\(nonexistent\).[1-9][0-9]*,\1,' \
|
|||||||
SED_CMDS.opt-debug-graph1= ${STD_SED_CMDS.dg1}
|
SED_CMDS.opt-debug-graph1= ${STD_SED_CMDS.dg1}
|
||||||
SED_CMDS.opt-debug-graph2= ${STD_SED_CMDS.dg2}
|
SED_CMDS.opt-debug-graph2= ${STD_SED_CMDS.dg2}
|
||||||
SED_CMDS.opt-debug-graph3= ${STD_SED_CMDS.dg3}
|
SED_CMDS.opt-debug-graph3= ${STD_SED_CMDS.dg3}
|
||||||
|
SED_CMDS.opt-debug-hash= -e 's,\(numEntries\)=[1-9][0-9],\1=<entries>,'
|
||||||
SED_CMDS.opt-debug-jobs= -e 's,([0-9][0-9]*),(<pid>),'
|
SED_CMDS.opt-debug-jobs= -e 's,([0-9][0-9]*),(<pid>),'
|
||||||
SED_CMDS.opt-debug-jobs+= -e 's,pid [0-9][0-9]*,pid <pid>,'
|
SED_CMDS.opt-debug-jobs+= -e 's,pid [0-9][0-9]*,pid <pid>,'
|
||||||
SED_CMDS.opt-debug-jobs+= -e 's,Process [0-9][0-9]*,Process <pid>,'
|
SED_CMDS.opt-debug-jobs+= -e 's,Process [0-9][0-9]*,Process <pid>,'
|
||||||
@ -541,6 +543,7 @@ SED_CMDS.opt-debug-jobs+= -e 's,^\(.Command: <shell>\) -q,\1,'
|
|||||||
SED_CMDS.opt-debug-lint+= ${STD_SED_CMDS.regex}
|
SED_CMDS.opt-debug-lint+= ${STD_SED_CMDS.regex}
|
||||||
SED_CMDS.opt-jobs-no-action= ${STD_SED_CMDS.hide-from-output}
|
SED_CMDS.opt-jobs-no-action= ${STD_SED_CMDS.hide-from-output}
|
||||||
SED_CMDS.opt-no-action-runflags= ${STD_SED_CMDS.hide-from-output}
|
SED_CMDS.opt-no-action-runflags= ${STD_SED_CMDS.hide-from-output}
|
||||||
|
SED_CMDS.opt-where-am-i= -e '/usr.obj/d'
|
||||||
# For Compat_RunCommand, useShell == false.
|
# For Compat_RunCommand, useShell == false.
|
||||||
SED_CMDS.sh-dots= -e 's,^.*\.\.\.:.*,<not found: ...>,'
|
SED_CMDS.sh-dots= -e 's,^.*\.\.\.:.*,<not found: ...>,'
|
||||||
# For Compat_RunCommand, useShell == true.
|
# For Compat_RunCommand, useShell == true.
|
||||||
@ -736,6 +739,9 @@ _SED_CMDS+= -e 's,${TEST_MAKE:T:S,.,\\.,g}[][0-9]* warning,make warning,'
|
|||||||
_SED_CMDS+= -e 's,^usage: ${TEST_MAKE:T:S,.,\\.,g} ,usage: make ,'
|
_SED_CMDS+= -e 's,^usage: ${TEST_MAKE:T:S,.,\\.,g} ,usage: make ,'
|
||||||
# replace anything after 'stopped in' with unit-tests
|
# replace anything after 'stopped in' with unit-tests
|
||||||
_SED_CMDS+= -e '/stopped/s, /.*, unit-tests,'
|
_SED_CMDS+= -e '/stopped/s, /.*, unit-tests,'
|
||||||
|
# Allow the test files to be placed anywhere.
|
||||||
|
_SED_CMDS+= -e 's,\(\.PARSEDIR}\) = `'"/[^']*'"',\1 = <some-dir>,'
|
||||||
|
_SED_CMDS+= -e 's,\(\.INCLUDEDFROMDIR}\) = `'"/[^']*'"',\1 = <some-dir>,'
|
||||||
_SED_CMDS+= -e 's,${TMPDIR},TMPDIR,g'
|
_SED_CMDS+= -e 's,${TMPDIR},TMPDIR,g'
|
||||||
# canonicalize ${.OBJDIR} and ${.CURDIR}
|
# canonicalize ${.OBJDIR} and ${.CURDIR}
|
||||||
.if ${.OBJDIR} != ${.CURDIR}
|
.if ${.OBJDIR} != ${.CURDIR}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# $NetBSD: comment.mk,v 1.3 2020/11/15 14:07:53 rillig Exp $
|
# $NetBSD: comment.mk,v 1.4 2022/01/23 18:00:53 rillig Exp $
|
||||||
#
|
#
|
||||||
# Demonstrate how comments are written in makefiles.
|
# Demonstrate how comments are written in makefiles.
|
||||||
|
|
||||||
@ -15,7 +15,9 @@ on and on.
|
|||||||
# Comments can be indented with spaces, but that is rather unusual.
|
# Comments can be indented with spaces, but that is rather unusual.
|
||||||
|
|
||||||
# Comments can be indented with a tab.
|
# Comments can be indented with a tab.
|
||||||
# These are not shell commands, they are just makefile comments.
|
# Since parse.c 1.127 from 2007-01-01, these are not shell commands,
|
||||||
|
# they are just makefile comments. Before that commit, these comments
|
||||||
|
# triggered the error message "Unassociated shell command".
|
||||||
|
|
||||||
.if 1 # There can be comments after conditions.
|
.if 1 # There can be comments after conditions.
|
||||||
.endif # And after the closing directive.
|
.endif # And after the closing directive.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# $NetBSD: cond-func-empty.mk,v 1.16 2021/12/11 10:41:31 rillig Exp $
|
# $NetBSD: cond-func-empty.mk,v 1.17 2021/12/28 22:13:56 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the empty() function in .if conditions, which tests a variable
|
# Tests for the empty() function in .if conditions, which tests a variable
|
||||||
# expression for emptiness.
|
# expression for emptiness.
|
||||||
@ -189,5 +189,16 @@ VARNAME= ${VARNAME${:U1}}
|
|||||||
.if defined(VARNAME${:U2}) && !empty(VARNAME${:U2})
|
.if defined(VARNAME${:U2}) && !empty(VARNAME${:U2})
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
all:
|
|
||||||
@:;
|
# If the word 'empty' is not followed by '(', it is not a function call but an
|
||||||
|
# ordinary bare word. This bare word is interpreted as 'defined(empty)', and
|
||||||
|
# since there is no variable named 'empty', the condition evaluates to false.
|
||||||
|
.if empty
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
|
empty= # defined but empty
|
||||||
|
.if empty
|
||||||
|
.else
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
@ -2,11 +2,11 @@ make: "cond-func.mk" line 36: Missing closing parenthesis for defined()
|
|||||||
make: "cond-func.mk" line 51: Missing closing parenthesis for defined()
|
make: "cond-func.mk" line 51: Missing closing parenthesis for defined()
|
||||||
make: "cond-func.mk" line 54: Missing closing parenthesis for defined()
|
make: "cond-func.mk" line 54: Missing closing parenthesis for defined()
|
||||||
make: "cond-func.mk" line 94: The empty variable is never defined.
|
make: "cond-func.mk" line 94: The empty variable is never defined.
|
||||||
make: "cond-func.mk" line 102: A plain function name is parsed as !empty(...).
|
make: "cond-func.mk" line 103: A plain function name is parsed as defined(...).
|
||||||
make: "cond-func.mk" line 109: A plain function name is parsed as !empty(...).
|
make: "cond-func.mk" line 110: A plain function name is parsed as defined(...).
|
||||||
make: "cond-func.mk" line 119: Symbols may start with a function name.
|
make: "cond-func.mk" line 120: Symbols may start with a function name.
|
||||||
make: "cond-func.mk" line 124: Symbols may start with a function name.
|
make: "cond-func.mk" line 125: Symbols may start with a function name.
|
||||||
make: "cond-func.mk" line 130: Missing closing parenthesis for defined()
|
make: "cond-func.mk" line 131: Missing closing parenthesis for defined()
|
||||||
make: Fatal errors encountered -- cannot continue
|
make: Fatal errors encountered -- cannot continue
|
||||||
make: stopped in unit-tests
|
make: stopped in unit-tests
|
||||||
exit status 1
|
exit status 1
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# $NetBSD: cond-func.mk,v 1.9 2020/11/15 14:07:53 rillig Exp $
|
# $NetBSD: cond-func.mk,v 1.11 2022/01/07 19:30:17 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for those parts of the functions in .if conditions that are common
|
# Tests for those parts of the functions in .if conditions that are common
|
||||||
# among several functions.
|
# among several functions.
|
||||||
@ -94,19 +94,20 @@ ${VARNAME_UNBALANCED_BRACES}= variable name with unbalanced braces
|
|||||||
. info The empty variable is never defined.
|
. info The empty variable is never defined.
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# The plain word 'defined' is interpreted as '!empty(defined)'.
|
# The plain word 'defined' is interpreted as 'defined(defined)', see
|
||||||
|
# CondParser_ComparisonOrLeaf.
|
||||||
# That variable is not defined (yet).
|
# That variable is not defined (yet).
|
||||||
.if defined
|
.if defined
|
||||||
. error
|
. error
|
||||||
.else
|
.else
|
||||||
. info A plain function name is parsed as !empty(...).
|
. info A plain function name is parsed as defined(...).
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# If a variable named 'defined' is actually defined and not empty, the plain
|
# If a variable named 'defined' is actually defined, the bare word 'defined'
|
||||||
# symbol 'defined' evaluates to true.
|
# is interpreted as 'defined(defined)', and the condition evaluates to true.
|
||||||
defined= non-empty
|
defined= # defined but empty
|
||||||
.if defined
|
.if defined
|
||||||
. info A plain function name is parsed as !empty(...).
|
. info A plain function name is parsed as defined(...).
|
||||||
.else
|
.else
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
@ -119,7 +120,7 @@ defined= non-empty
|
|||||||
. info Symbols may start with a function name.
|
. info Symbols may start with a function name.
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
defined-var= non-empty
|
defined-var= # defined but empty
|
||||||
.if defined-var
|
.if defined-var
|
||||||
. info Symbols may start with a function name.
|
. info Symbols may start with a function name.
|
||||||
.else
|
.else
|
||||||
@ -132,6 +133,3 @@ defined-var= non-empty
|
|||||||
.else
|
.else
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
all:
|
|
||||||
@:;
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
make: "cond-op-parentheses.mk" line 13: Parentheses can be nested at least to depth 112.
|
make: "cond-op-parentheses.mk" line 19: String comparison operator must be either == or !=
|
||||||
make: "cond-op-parentheses.mk" line 19: Malformed conditional (()
|
make: "cond-op-parentheses.mk" line 22: Malformed conditional ((3) > 2)
|
||||||
make: "cond-op-parentheses.mk" line 29: Malformed conditional ())
|
make: "cond-op-parentheses.mk" line 40: Malformed conditional (()
|
||||||
|
make: "cond-op-parentheses.mk" line 53: Malformed conditional ())
|
||||||
make: Fatal errors encountered -- cannot continue
|
make: Fatal errors encountered -- cannot continue
|
||||||
make: stopped in unit-tests
|
make: stopped in unit-tests
|
||||||
exit status 1
|
exit status 1
|
||||||
|
@ -1,8 +1,26 @@
|
|||||||
# $NetBSD: cond-op-parentheses.mk,v 1.4 2021/01/19 17:49:13 rillig Exp $
|
# $NetBSD: cond-op-parentheses.mk,v 1.5 2022/01/22 21:50:41 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for parentheses in .if conditions.
|
# Tests for parentheses in .if conditions, which group expressions to override
|
||||||
|
# the precedence of the operators '!', '&&' and '||'. Parentheses cannot be
|
||||||
|
# used to form arithmetic expressions such as '(3+4)' though.
|
||||||
|
|
||||||
# TODO: Implementation
|
# Contrary to the C family of programming languages, the outermost condition
|
||||||
|
# does not have to be enclosed in parentheses.
|
||||||
|
.if defined(VAR)
|
||||||
|
. error
|
||||||
|
.elif !1
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
|
# Parentheses cannot enclose numbers as there is no need for it. Make does
|
||||||
|
# not implement any arithmetic functions in its condition parser. If
|
||||||
|
# absolutely necessary, use expr(1).
|
||||||
|
# expect+1: String comparison operator must be either == or !=
|
||||||
|
.if 3 > (2)
|
||||||
|
.endif
|
||||||
|
# expect+1: Malformed conditional ((3) > 2)
|
||||||
|
.if (3) > 2
|
||||||
|
.endif
|
||||||
|
|
||||||
# Test for deeply nested conditions.
|
# Test for deeply nested conditions.
|
||||||
.if (((((((((((((((((((((((((((((((((((((((((((((((((((((((( \
|
.if (((((((((((((((((((((((((((((((((((((((((((((((((((((((( \
|
||||||
@ -10,7 +28,10 @@
|
|||||||
1 \
|
1 \
|
||||||
)))))))))))))))))))))))))))))))))))))))))))))))))))))))) \
|
)))))))))))))))))))))))))))))))))))))))))))))))))))))))) \
|
||||||
))))))))))))))))))))))))))))))))))))))))))))))))))))))))
|
))))))))))))))))))))))))))))))))))))))))))))))))))))))))
|
||||||
. info Parentheses can be nested at least to depth 112.
|
# Parentheses can be nested at least to depth 112. There is nothing special
|
||||||
|
# about this number though, much higher numbers work as well, at least on
|
||||||
|
# NetBSD. The actual limit depends on the allowed call stack depth for C code
|
||||||
|
# of the platform. Anyway, 112 should be enough for all practical purposes.
|
||||||
.else
|
.else
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
@ -24,8 +45,11 @@
|
|||||||
|
|
||||||
# An unbalanced closing parenthesis is a parse error.
|
# An unbalanced closing parenthesis is a parse error.
|
||||||
#
|
#
|
||||||
# As of 2021-01-19, CondParser_Term returned TOK_RPAREN even though this
|
# Before cond.c 1.237 from 2021-01-19, CondParser_Term returned TOK_RPAREN
|
||||||
# function promised to only ever return TOK_TRUE, TOK_FALSE or TOK_ERROR.
|
# even though the documentation of that function promised to only ever return
|
||||||
|
# TOK_TRUE, TOK_FALSE or TOK_ERROR. In cond.c 1.241, the return type of that
|
||||||
|
# function was changed to a properly restricted enum type, to prevent this bug
|
||||||
|
# from occurring again.
|
||||||
.if )
|
.if )
|
||||||
. error
|
. error
|
||||||
.else
|
.else
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# $NetBSD: cond-short.mk,v 1.18 2021/12/12 09:49:09 rillig Exp $
|
# $NetBSD: cond-short.mk,v 1.19 2021/12/27 18:54:19 rillig Exp $
|
||||||
#
|
#
|
||||||
# Demonstrates that in conditions, the right-hand side of an && or ||
|
# Demonstrates that in conditions, the right-hand side of an && or ||
|
||||||
# is only evaluated if it can actually influence the result.
|
# is only evaluated if it can actually influence the result.
|
||||||
@ -14,14 +14,14 @@
|
|||||||
# relevant variable expressions was that in the irrelevant variable
|
# relevant variable expressions was that in the irrelevant variable
|
||||||
# expressions, undefined variables were allowed. This allowed for conditions
|
# expressions, undefined variables were allowed. This allowed for conditions
|
||||||
# like 'defined(VAR) && ${VAR:S,from,to,} != ""', which no longer produced an
|
# like 'defined(VAR) && ${VAR:S,from,to,} != ""', which no longer produced an
|
||||||
# error message 'Malformed conditional', but it still evaluated the
|
# error message 'Malformed conditional', but the irrelevant expression was
|
||||||
# expression, even though the expression was irrelevant.
|
# still evaluated.
|
||||||
#
|
#
|
||||||
# Since the initial commit on 1993-03-21, the manual page has been saying that
|
# Since the initial commit on 1993-03-21, the manual page has been saying that
|
||||||
# make 'will only evaluate a conditional as far as is necessary to determine',
|
# make 'will only evaluate a conditional as far as is necessary to determine',
|
||||||
# but that was wrong. The code in cond.c 1.1 from 1993-03-21 looks good since
|
# but that was wrong. The code in cond.c 1.1 from 1993-03-21 looks good since
|
||||||
# it calls Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree), but the
|
# it calls Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree), but the
|
||||||
# definition of Var_Parse does not call the third parameter 'doEval', as would
|
# definition of Var_Parse did not call the third parameter 'doEval', as would
|
||||||
# be expected, but instead 'err', accompanied by the comment 'TRUE if
|
# be expected, but instead 'err', accompanied by the comment 'TRUE if
|
||||||
# undefined variables are an error'. This subtle difference between 'do not
|
# undefined variables are an error'. This subtle difference between 'do not
|
||||||
# evaluate at all' and 'allow undefined variables' led to the unexpected
|
# evaluate at all' and 'allow undefined variables' led to the unexpected
|
||||||
@ -122,7 +122,9 @@ VAR= # empty again, for the following tests
|
|||||||
.if 0 || empty(${echo "expected or empty" 1>&2 :L:sh})
|
.if 0 || empty(${echo "expected or empty" 1>&2 :L:sh})
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# Unreachable nested conditions are skipped completely as well.
|
# Unreachable nested conditions are skipped completely as well. These skipped
|
||||||
|
# lines may even contain syntax errors. This allows to skip syntactically
|
||||||
|
# incompatible new features in older versions of make.
|
||||||
|
|
||||||
.if 0
|
.if 0
|
||||||
. if ${echo "unexpected nested and" 1>&2 :L:sh}
|
. if ${echo "unexpected nested and" 1>&2 :L:sh}
|
||||||
|
@ -2,7 +2,7 @@ make: "cond-token-number.mk" line 15: Malformed conditional (-0)
|
|||||||
make: "cond-token-number.mk" line 25: Malformed conditional (+0)
|
make: "cond-token-number.mk" line 25: Malformed conditional (+0)
|
||||||
make: "cond-token-number.mk" line 35: Malformed conditional (!-1)
|
make: "cond-token-number.mk" line 35: Malformed conditional (!-1)
|
||||||
make: "cond-token-number.mk" line 45: Malformed conditional (!+1)
|
make: "cond-token-number.mk" line 45: Malformed conditional (!+1)
|
||||||
make: "cond-token-number.mk" line 80: End of the tests.
|
make: "cond-token-number.mk" line 89: End of the tests.
|
||||||
make: Fatal errors encountered -- cannot continue
|
make: Fatal errors encountered -- cannot continue
|
||||||
make: stopped in unit-tests
|
make: stopped in unit-tests
|
||||||
exit status 1
|
exit status 1
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# $NetBSD: cond-token-number.mk,v 1.5 2020/11/15 14:58:14 rillig Exp $
|
# $NetBSD: cond-token-number.mk,v 1.7 2022/01/02 02:57:39 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for number tokens in .if conditions.
|
# Tests for number tokens in .if conditions.
|
||||||
#
|
#
|
||||||
@ -69,13 +69,22 @@
|
|||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# This is not a hexadecimal number, even though it has an x.
|
# This is not a hexadecimal number, even though it has an x. It is
|
||||||
# It is interpreted as a string instead, effectively meaning defined(3x4).
|
# interpreted as a string instead. In a plain '.if', such a token evaluates
|
||||||
|
# to true if it is non-empty. In other '.if' directives, such a token is
|
||||||
|
# evaluated by either FuncDefined or FuncMake.
|
||||||
.if 3x4
|
.if 3x4
|
||||||
.else
|
.else
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
|
# Make can do radix conversion from hex.
|
||||||
|
HEX= dead
|
||||||
|
.if 0x${HEX} == 57005
|
||||||
|
.else
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
# Ensure that parsing continues until here.
|
# Ensure that parsing continues until here.
|
||||||
.info End of the tests.
|
.info End of the tests.
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ lhs = "var&&name", rhs = "var&&name", op = !=
|
|||||||
CondParser_Eval: ${:Uvar}||name != "var||name"
|
CondParser_Eval: ${:Uvar}||name != "var||name"
|
||||||
lhs = "var||name", rhs = "var||name", op = !=
|
lhs = "var||name", rhs = "var||name", op = !=
|
||||||
CondParser_Eval: bare
|
CondParser_Eval: bare
|
||||||
make: "cond-token-plain.mk" line 106: A bare word is treated like defined(...), and the variable 'bare' is not defined.
|
make: "cond-token-plain.mk" line 105: A bare word is treated like defined(...), and the variable 'bare' is not defined.
|
||||||
CondParser_Eval: VAR
|
CondParser_Eval: VAR
|
||||||
make: "cond-token-plain.mk" line 111: A bare word is treated like defined(...).
|
make: "cond-token-plain.mk" line 111: A bare word is treated like defined(...).
|
||||||
CondParser_Eval: V${:UA}R
|
CondParser_Eval: V${:UA}R
|
||||||
@ -56,6 +56,7 @@ CondParser_Eval: 0
|
|||||||
make: "cond-token-plain.mk" line 201: Malformed conditional (${0:?:} || left == right)
|
make: "cond-token-plain.mk" line 201: Malformed conditional (${0:?:} || left == right)
|
||||||
CondParser_Eval: left == right || ${0:?:}
|
CondParser_Eval: left == right || ${0:?:}
|
||||||
make: "cond-token-plain.mk" line 206: Malformed conditional (left == right || ${0:?:})
|
make: "cond-token-plain.mk" line 206: Malformed conditional (left == right || ${0:?:})
|
||||||
|
make: "cond-token-plain.mk" line 225: Malformed conditional (VAR.${IF_COUNT::+=1} != "")
|
||||||
make: Fatal errors encountered -- cannot continue
|
make: Fatal errors encountered -- cannot continue
|
||||||
make: stopped in unit-tests
|
make: stopped in unit-tests
|
||||||
exit status 1
|
exit status 1
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# $NetBSD: cond-token-plain.mk,v 1.14 2021/12/12 09:36:00 rillig Exp $
|
# $NetBSD: cond-token-plain.mk,v 1.15 2021/12/30 02:14:55 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for plain tokens (that is, string literals without quotes)
|
# Tests for plain tokens (that is, string literals without quotes)
|
||||||
# in .if conditions. These are also called bare words.
|
# in .if conditions. These are also called bare words.
|
||||||
@ -209,5 +209,48 @@ ${:U\\\\}= backslash
|
|||||||
# See cond-token-string.mk for similar tests where the condition is enclosed
|
# See cond-token-string.mk for similar tests where the condition is enclosed
|
||||||
# in "quotes".
|
# in "quotes".
|
||||||
|
|
||||||
all:
|
.MAKEFLAGS: -d0
|
||||||
@:;
|
|
||||||
|
|
||||||
|
# As of cond.c 1.320 from 2021-12-30, the code in CondParser_ComparisonOrLeaf
|
||||||
|
# looks suspicious of evaluating the expression twice: first for parsing a
|
||||||
|
# bare word and second for parsing the left-hand side of a comparison.
|
||||||
|
#
|
||||||
|
# In '.if' directives, the left-hand side of a comparison must not be a bare
|
||||||
|
# word though, and this keeps CondParser_Leaf from evaluating the expression
|
||||||
|
# for the second time. The right-hand side of a comparison may be a bare
|
||||||
|
# word, but that side has no risk of being parsed more than once.
|
||||||
|
#
|
||||||
|
# expect+1: Malformed conditional (VAR.${IF_COUNT::+=1} != "")
|
||||||
|
.if VAR.${IF_COUNT::+=1} != ""
|
||||||
|
. error
|
||||||
|
.else
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
.if ${IF_COUNT} != "1"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
|
# A different situation is when CondParser.leftUnquotedOK is true. This
|
||||||
|
# situation arises in expressions of the form ${cond:?yes:no}. As of
|
||||||
|
# 2021-12-30, the condition in such an expression is evaluated before parsing
|
||||||
|
# the condition, see varmod-ifelse.mk. To pass a variable expression to the
|
||||||
|
# condition parser, it needs to be escaped. This rarely happens in practice,
|
||||||
|
# in most cases the conditions are simple enough that it doesn't matter
|
||||||
|
# whether the condition is first evaluated and then parsed, or vice versa.
|
||||||
|
# A half-baked attempt at hiding this implementation detail is
|
||||||
|
# CondParser.leftUnquotedOK, but that is a rather leaky abstraction.
|
||||||
|
|
||||||
|
#.MAKEFLAGS: -dcv
|
||||||
|
COND= VAR.$${MOD_COUNT::+=1}
|
||||||
|
.if ${${COND} == "VAR.":?yes:no} != "yes"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
|
# The value "1 1" demonstrates that the expression ${MOD_COUNT::+=1} was
|
||||||
|
# evaluated twice. In practice, expressions that occur in conditions do not
|
||||||
|
# have side effects, making this problem rather academic, but it is there.
|
||||||
|
.if ${MOD_COUNT} != "1 1"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
#.MAKEFLAGS: -d0
|
||||||
|
@ -6,9 +6,9 @@ make: "cond-token-string.mk" line 37: Expected.
|
|||||||
CondParser_Eval: "UNDEF"
|
CondParser_Eval: "UNDEF"
|
||||||
make: "cond-token-string.mk" line 46: The string literal "UNDEF" is not empty.
|
make: "cond-token-string.mk" line 46: The string literal "UNDEF" is not empty.
|
||||||
CondParser_Eval: " "
|
CondParser_Eval: " "
|
||||||
make: "cond-token-string.mk" line 55: The string literal " " is not empty, even though it consists of whitespace only.
|
make: "cond-token-string.mk" line 54: The string literal " " is not empty, even though it consists of whitespace only.
|
||||||
CondParser_Eval: "${UNDEF}"
|
CondParser_Eval: "${UNDEF}"
|
||||||
make: "cond-token-string.mk" line 64: An undefined variable in quotes expands to an empty string, which then evaluates to false.
|
make: "cond-token-string.mk" line 63: An undefined variable in quotes expands to an empty string, which then evaluates to false.
|
||||||
CondParser_Eval: "${:Uvalue}"
|
CondParser_Eval: "${:Uvalue}"
|
||||||
make: "cond-token-string.mk" line 68: A nonempty variable expression evaluates to true.
|
make: "cond-token-string.mk" line 68: A nonempty variable expression evaluates to true.
|
||||||
CondParser_Eval: "${:U}"
|
CondParser_Eval: "${:U}"
|
||||||
|
4
contrib/bmake/unit-tests/dep-duplicate.exp
Normal file
4
contrib/bmake/unit-tests/dep-duplicate.exp
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
make: "dep-duplicate.inc" line 1: warning: duplicate script for target "all" ignored
|
||||||
|
make: "dep-duplicate.main" line 3: warning: using previous script for "all" defined here
|
||||||
|
main-output
|
||||||
|
exit status 0
|
27
contrib/bmake/unit-tests/dep-duplicate.mk
Normal file
27
contrib/bmake/unit-tests/dep-duplicate.mk
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# $NetBSD: dep-duplicate.mk,v 1.3 2022/01/20 19:24:53 rillig Exp $
|
||||||
|
#
|
||||||
|
# Test for a target whose commands are defined twice. This generates a
|
||||||
|
# warning, not an error, so ensure that the correct commands are kept.
|
||||||
|
#
|
||||||
|
# Also ensure that the diagnostics mention the correct file in case of
|
||||||
|
# included files. Since parse.c 1.231 from 2018-12-22 and before parse.c
|
||||||
|
# 1.653 from 2022-01-20, the wrong filename had been printed if the file of
|
||||||
|
# the first commands section was included by its relative path.
|
||||||
|
|
||||||
|
all: .PHONY
|
||||||
|
@exec > dep-duplicate.main; \
|
||||||
|
echo '# empty line 1'; \
|
||||||
|
echo '# empty line 2'; \
|
||||||
|
echo 'all:; @echo main-output'; \
|
||||||
|
echo '.include "dep-duplicate.inc"'
|
||||||
|
|
||||||
|
@exec > dep-duplicate.inc; \
|
||||||
|
echo 'all:; @echo inc-output'
|
||||||
|
|
||||||
|
# The main file must be specified using a relative path, just like the
|
||||||
|
# default 'makefile' or 'Makefile', to produce the same result when
|
||||||
|
# run via ATF or 'make test'.
|
||||||
|
@${MAKE} -r -f dep-duplicate.main
|
||||||
|
|
||||||
|
@rm -f dep-duplicate.main
|
||||||
|
@rm -f dep-duplicate.inc
|
4
contrib/bmake/unit-tests/dep-op-missing.exp
Normal file
4
contrib/bmake/unit-tests/dep-op-missing.exp
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
make: "dep-op-missing.tmp" line 1: Invalid line type
|
||||||
|
make: Fatal errors encountered -- cannot continue
|
||||||
|
make: stopped in unit-tests
|
||||||
|
exit status 0
|
13
contrib/bmake/unit-tests/dep-op-missing.mk
Normal file
13
contrib/bmake/unit-tests/dep-op-missing.mk
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# $NetBSD: dep-op-missing.mk,v 1.1 2021/12/14 00:02:57 rillig Exp $
|
||||||
|
#
|
||||||
|
# Test for a missing dependency operator, in a line with trailing whitespace.
|
||||||
|
|
||||||
|
# Before parse.c 1.578 from 2021-12-14, there was some unreachable error
|
||||||
|
# handling code in ParseDependencyOp. This test tried to reach it and failed.
|
||||||
|
# To reach that point, there would have to be trailing whitespace in the line,
|
||||||
|
# but that is removed in an early stage of parsing.
|
||||||
|
|
||||||
|
all: .PHONY
|
||||||
|
@printf 'target ' > dep-op-missing.tmp
|
||||||
|
@${MAKE} -r -f dep-op-missing.tmp || exit 0
|
||||||
|
@rm dep-op-missing.tmp
|
@ -2,8 +2,10 @@ dep-colon-bug-cross-file.mk
|
|||||||
dep-colon.mk
|
dep-colon.mk
|
||||||
dep-double-colon-indep.mk
|
dep-double-colon-indep.mk
|
||||||
dep-double-colon.mk
|
dep-double-colon.mk
|
||||||
|
dep-duplicate.mk
|
||||||
dep-exclam.mk
|
dep-exclam.mk
|
||||||
dep-none.mk
|
dep-none.mk
|
||||||
|
dep-op-missing.mk
|
||||||
dep-percent.mk
|
dep-percent.mk
|
||||||
dep-var.mk
|
dep-var.mk
|
||||||
dep-wildcards.mk
|
dep-wildcards.mk
|
||||||
|
@ -1 +1,5 @@
|
|||||||
exit status 0
|
make: "dep.mk" line 11: Inconsistent operator for only-colon
|
||||||
|
make: "dep.mk" line 13: Inconsistent operator for only-colon
|
||||||
|
make: Fatal errors encountered -- cannot continue
|
||||||
|
make: stopped in unit-tests
|
||||||
|
exit status 1
|
||||||
|
@ -1,8 +1,18 @@
|
|||||||
# $NetBSD: dep.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $
|
# $NetBSD: dep.mk,v 1.3 2021/12/13 23:38:54 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for dependency declarations, such as "target: sources".
|
# Tests for dependency declarations, such as "target: sources".
|
||||||
|
|
||||||
# TODO: Implementation
|
.MAIN: all
|
||||||
|
|
||||||
|
# As soon as a target is defined using one of the dependency operators, it is
|
||||||
|
# restricted to this dependency operator and cannot use the others anymore.
|
||||||
|
only-colon:
|
||||||
|
# expect+1: Inconsistent operator for only-colon
|
||||||
|
only-colon!
|
||||||
|
# expect+1: Inconsistent operator for only-colon
|
||||||
|
only-colon::
|
||||||
|
# Ensure that the target still has the original operator. If it hadn't, there
|
||||||
|
# would be another error message.
|
||||||
|
only-colon:
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@:;
|
|
||||||
|
@ -2,4 +2,6 @@ Skipping meta for actual-test: no commands
|
|||||||
Skipping meta for .END: .SPECIAL
|
Skipping meta for .END: .SPECIAL
|
||||||
Targets from meta mode:
|
Targets from meta mode:
|
||||||
| TARGET depsrc-meta-target
|
| TARGET depsrc-meta-target
|
||||||
|
Targets from meta mode in jobs mode:
|
||||||
|
| TARGET depsrc-meta-target
|
||||||
exit status 0
|
exit status 0
|
||||||
|
@ -1,31 +1,30 @@
|
|||||||
# $NetBSD: depsrc-meta.mk,v 1.4 2020/11/27 08:39:07 rillig Exp $
|
# $NetBSD: depsrc-meta.mk,v 1.6 2022/01/26 22:47:03 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the special source .META in dependency declarations.
|
# Tests for the special source .META in dependency declarations.
|
||||||
|
|
||||||
# TODO: Implementation
|
# TODO: Implementation
|
||||||
# TODO: Explanation
|
# TODO: Explanation
|
||||||
|
|
||||||
.if make(actual-test)
|
.MAIN: all
|
||||||
|
|
||||||
|
.if make(actual-test)
|
||||||
.MAKEFLAGS: -dM
|
.MAKEFLAGS: -dM
|
||||||
.MAKE.MODE= meta curDirOk=true
|
.MAKE.MODE= meta curDirOk=true
|
||||||
|
.endif
|
||||||
|
|
||||||
actual-test: depsrc-meta-target
|
actual-test: depsrc-meta-target
|
||||||
depsrc-meta-target: .META
|
depsrc-meta-target: .META
|
||||||
@> ${.TARGET}-file
|
@> ${.TARGET}-file
|
||||||
@rm -f ${.TARGET}-file
|
@rm -f ${.TARGET}-file
|
||||||
|
|
||||||
.elif make(check-results)
|
|
||||||
|
|
||||||
check-results:
|
check-results:
|
||||||
@echo 'Targets from meta mode:'
|
@echo 'Targets from meta mode${.MAKE.JOBS:D in jobs mode}:'
|
||||||
@awk '/^TARGET/ { print "| " $$0 }' depsrc-meta-target.meta
|
@awk '/^TARGET/ { print "| " $$0 }' depsrc-meta-target.meta
|
||||||
@rm depsrc-meta-target.meta
|
@rm depsrc-meta-target.meta
|
||||||
|
|
||||||
.else
|
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@${MAKE} -f ${MAKEFILE} actual-test
|
@${MAKE} -r -f ${MAKEFILE} actual-test
|
||||||
@${MAKE} -f ${MAKEFILE} check-results
|
@${MAKE} -r -f ${MAKEFILE} check-results
|
||||||
|
|
||||||
.endif
|
@${MAKE} -r -f ${MAKEFILE} actual-test -j1
|
||||||
|
@${MAKE} -r -f ${MAKEFILE} check-results -j1
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
# $NetBSD: depsrc-use.mk,v 1.4 2020/08/22 12:30:57 rillig Exp $
|
# $NetBSD: depsrc-use.mk,v 1.5 2021/12/28 14:22:51 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the special source .USE in dependency declarations,
|
# Tests for the special source .USE in dependency declarations,
|
||||||
# which allows to append common commands to other targets.
|
# which allows to append common commands to other targets.
|
||||||
|
|
||||||
|
# Before make.h 1.280 from 2021-12-28, a .USEBEFORE target was accidentally
|
||||||
|
# regarded as a candidate for the main target. On the other hand, a .USE
|
||||||
|
# target was not.
|
||||||
|
not-a-main-candidate: .USE
|
||||||
|
|
||||||
all: action directly
|
all: action directly
|
||||||
|
|
||||||
first: .USE
|
first: .USE
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# $NetBSD: depsrc-usebefore.mk,v 1.6 2020/11/15 20:20:58 rillig Exp $
|
# $NetBSD: depsrc-usebefore.mk,v 1.7 2021/12/28 14:22:51 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the special source .USEBEFORE in dependency declarations,
|
# Tests for the special source .USEBEFORE in dependency declarations,
|
||||||
# which allows to prepend common commands to other targets.
|
# which allows to prepend common commands to other targets.
|
||||||
@ -7,6 +7,11 @@
|
|||||||
# .USE
|
# .USE
|
||||||
# depsrc-use.mk
|
# depsrc-use.mk
|
||||||
|
|
||||||
|
# Before make.h 1.280 from 2021-12-28, a .USEBEFORE target was accidentally
|
||||||
|
# regarded as a candidate for the main target. On the other hand, a .USE
|
||||||
|
# target was not.
|
||||||
|
not-a-main-candidate: .USEBEFORE
|
||||||
|
|
||||||
all: action directly
|
all: action directly
|
||||||
|
|
||||||
first: .USEBEFORE
|
first: .USEBEFORE
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
: 'Undefined variables are expanded directly in the dependency'
|
: 'Undefined variables are expanded directly in the dependency'
|
||||||
: 'declaration. They are not preserved and maybe expanded later.'
|
: 'declaration. They are not preserved and maybe expanded later.'
|
||||||
: 'This is in contrast to local variables such as ${.TARGET}.'
|
: 'This is in contrast to local variables such as ${.TARGET}.'
|
||||||
|
: Making .UNKNOWN from nothing.
|
||||||
exit status 0
|
exit status 0
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# $NetBSD: depsrc.mk,v 1.4 2020/12/22 19:38:44 rillig Exp $
|
# $NetBSD: depsrc.mk,v 1.5 2021/12/13 23:38:54 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for special sources (those starting with a dot, followed by
|
# Tests for special sources (those starting with a dot, followed by
|
||||||
# uppercase letters) in dependency declarations, such as .PHONY.
|
# uppercase letters) in dependency declarations, such as '.PHONY'.
|
||||||
|
|
||||||
# TODO: Implementation
|
# TODO: Implementation
|
||||||
|
|
||||||
@ -14,13 +14,19 @@ target: .PHONY source-${DEFINED_LATER}
|
|||||||
DEFINED_LATER= later
|
DEFINED_LATER= later
|
||||||
#
|
#
|
||||||
source-: .PHONY
|
source-: .PHONY
|
||||||
|
# This section applies.
|
||||||
: 'Undefined variables are expanded directly in the dependency'
|
: 'Undefined variables are expanded directly in the dependency'
|
||||||
: 'declaration. They are not preserved and maybe expanded later.'
|
: 'declaration. They are not preserved and maybe expanded later.'
|
||||||
: 'This is in contrast to local variables such as $${.TARGET}.'
|
: 'This is in contrast to local variables such as $${.TARGET}.'
|
||||||
source-later: .PHONY
|
source-later: .PHONY
|
||||||
|
# This section doesn't apply.
|
||||||
: 'Undefined variables are tried to be expanded in a dependency'
|
: 'Undefined variables are tried to be expanded in a dependency'
|
||||||
: 'declaration. If that fails because the variable is undefined,'
|
: 'declaration. If that fails because the variable is undefined,'
|
||||||
: 'the expression is preserved and tried to be expanded later.'
|
: 'the expression is preserved and tried to be expanded later.'
|
||||||
|
|
||||||
all:
|
# Sources that look like keywords but are not known are interpreted as
|
||||||
@:;
|
# ordinary sources.
|
||||||
|
target: .UNKNOWN
|
||||||
|
|
||||||
|
.UNKNOWN:
|
||||||
|
: Making ${.TARGET} from ${.ALLSRC:S,^$,nothing,W}.
|
||||||
|
@ -1 +1,9 @@
|
|||||||
exit status 0
|
false fails
|
||||||
|
*** Error code 1 (continuing)
|
||||||
|
|
||||||
|
Stop.
|
||||||
|
make: stopped in unit-tests
|
||||||
|
ERROR_INFO='This information is printed on 'errors'.'
|
||||||
|
Making sub-error as prerequisite.
|
||||||
|
Making .ERROR out of nothing.
|
||||||
|
exit status 1
|
||||||
|
@ -1,9 +1,21 @@
|
|||||||
# $NetBSD: deptgt-error.mk,v 1.3 2020/11/15 20:20:58 rillig Exp $
|
# $NetBSD: deptgt-error.mk,v 1.4 2022/01/22 21:50:41 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the special target .ERROR in dependency declarations, which
|
# Tests for the special target .ERROR in dependency declarations, which
|
||||||
# collects commands that are run when another target fails.
|
# is made when another target fails.
|
||||||
|
|
||||||
# TODO: Implementation
|
all: .PHONY
|
||||||
|
false fails
|
||||||
|
|
||||||
all:
|
.ERROR:
|
||||||
@:;
|
@echo 'Making ${.TARGET} out of nothing.'
|
||||||
|
|
||||||
|
.ERROR: sub-error
|
||||||
|
sub-error: .PHONY
|
||||||
|
@echo 'Making ${.TARGET} as prerequisite.'
|
||||||
|
|
||||||
|
# Before making the '.ERROR' target, these variable values are printed.
|
||||||
|
MAKE_PRINT_VAR_ON_ERROR= ERROR_INFO
|
||||||
|
|
||||||
|
# Use single quotes to demonstrate that the output is only informational, it
|
||||||
|
# does not use any established escaping mechanism.
|
||||||
|
ERROR_INFO= This information is ${:Uprinted} on 'errors'.
|
||||||
|
@ -1 +1,11 @@
|
|||||||
exit status 0
|
error-failed before
|
||||||
|
*** Error code 1 (continuing)
|
||||||
|
error-ignored before
|
||||||
|
*** Error code 1 (ignored)
|
||||||
|
error-ignored after
|
||||||
|
Making depends-on-ignored from error-ignored.
|
||||||
|
`all' not remade because of errors.
|
||||||
|
|
||||||
|
Stop.
|
||||||
|
make: stopped in unit-tests
|
||||||
|
exit status 1
|
||||||
|
@ -1,9 +1,31 @@
|
|||||||
# $NetBSD: deptgt-ignore.mk,v 1.3 2020/11/15 20:20:58 rillig Exp $
|
# $NetBSD: deptgt-ignore.mk,v 1.4 2022/01/22 21:50:41 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the special target .IGNORE in dependency declarations, which
|
# Tests for the special target .IGNORE in dependency declarations, which
|
||||||
# does not stop if a command from this target exits with a non-zero status.
|
# does not stop if a command from this target exits with a non-zero status.
|
||||||
|
#
|
||||||
|
# This test only applies to compatibility mode. In jobs mode such as with
|
||||||
|
# '-j1', all commands for a single target are bundled into a single shell
|
||||||
|
# program, which is a different implementation technique, the .IGNORE applies
|
||||||
|
# there as well.
|
||||||
|
|
||||||
# TODO: Implementation
|
.MAKEFLAGS: -d0 # force stdout to be unbuffered
|
||||||
|
|
||||||
all:
|
all: depends-on-failed depends-on-ignored
|
||||||
@:;
|
.PHONY: all depends-on-failed depends-on-ignored error-failed error-ignored
|
||||||
|
|
||||||
|
error-failed error-ignored:
|
||||||
|
@echo '${.TARGET} before'
|
||||||
|
@false
|
||||||
|
@echo '${.TARGET} after'
|
||||||
|
|
||||||
|
depends-on-failed: error-failed
|
||||||
|
@echo 'Making ${.TARGET} from ${.ALLSRC}.'
|
||||||
|
depends-on-ignored: error-ignored
|
||||||
|
@echo 'Making ${.TARGET} from ${.ALLSRC}.'
|
||||||
|
|
||||||
|
# Even though the command 'false' in the middle fails, the remaining commands
|
||||||
|
# are still run. After that, the target is marked made, so targets depending
|
||||||
|
# on the target with the ignored commands are made.
|
||||||
|
.IGNORE: error-ignored
|
||||||
|
|
||||||
|
#.MAKEFLAGS: -dg2
|
||||||
|
@ -1 +1,2 @@
|
|||||||
exit status 0
|
Ctrl-C
|
||||||
|
exit status 130
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
# $NetBSD: deptgt-interrupt.mk,v 1.3 2020/11/15 20:20:58 rillig Exp $
|
# $NetBSD: deptgt-interrupt.mk,v 1.4 2022/01/22 21:50:41 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the special target .INTERRUPT in dependency declarations, which
|
# Tests for the special target .INTERRUPT in dependency declarations, which
|
||||||
# collects commands to be run when make is interrupted while building another
|
# collects commands to be run when make is interrupted while building another
|
||||||
# target.
|
# target.
|
||||||
|
|
||||||
# TODO: Implementation
|
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@:;
|
@kill -INT ${.MAKE.PID}
|
||||||
|
|
||||||
|
.INTERRUPT:
|
||||||
|
@echo 'Ctrl-C'
|
||||||
|
@ -1 +1,2 @@
|
|||||||
|
This target real-main is the one that is made.
|
||||||
exit status 0
|
exit status 0
|
||||||
|
@ -1,10 +1,29 @@
|
|||||||
# $NetBSD: deptgt-main.mk,v 1.3 2020/11/15 20:20:58 rillig Exp $
|
# $NetBSD: deptgt-main.mk,v 1.4 2022/01/23 21:48:59 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the special target .MAIN in dependency declarations, which defines
|
# Tests for the special target .MAIN in dependency declarations, which defines
|
||||||
# the main target. This main target is built if no target has been specified
|
# the main target. This main target is built if no target has been specified
|
||||||
# on the command line or via MAKEFLAGS.
|
# on the command line or via MAKEFLAGS.
|
||||||
|
|
||||||
# TODO: Implementation
|
# The first target becomes the main target by default. It can be overridden
|
||||||
|
# though.
|
||||||
|
all: .PHONY
|
||||||
|
@echo 'This target is not made.'
|
||||||
|
|
||||||
all:
|
# This target is not the first to be defined, but it lists '.MAIN' as one of
|
||||||
@:;
|
# its sources. The word '.MAIN' only has a special meaning when it appears as
|
||||||
|
# a _target_ in a dependency declaration, not as a _source_. It is thus
|
||||||
|
# ignored.
|
||||||
|
depsrc-main: .PHONY .MAIN
|
||||||
|
@echo 'This target is not made either.'
|
||||||
|
|
||||||
|
# This target is the first to be marked with '.MAIN', so it replaces the
|
||||||
|
# previous main target, which was 'all'.
|
||||||
|
.MAIN: real-main
|
||||||
|
real-main: .PHONY
|
||||||
|
@echo 'This target ${.TARGET} is the one that is made.'
|
||||||
|
|
||||||
|
# This target is marked with '.MAIN' but there already is a main target. The
|
||||||
|
# attribute '.MAIN' is thus ignored.
|
||||||
|
.MAIN: too-late
|
||||||
|
too-late: .PHONY
|
||||||
|
@echo 'This target comes too late, there is already a .MAIN target.'
|
||||||
|
@ -1 +1,9 @@
|
|||||||
|
: Making 1 out of nothing.
|
||||||
|
: Making 2 out of nothing.
|
||||||
|
: Making 3 out of nothing.
|
||||||
|
: Making 4 out of nothing.
|
||||||
|
: Making 5 out of nothing.
|
||||||
|
: Making 6 out of nothing.
|
||||||
|
: Making 7 out of nothing.
|
||||||
|
: Making 8 out of nothing.
|
||||||
exit status 0
|
exit status 0
|
||||||
|
@ -1,8 +1,16 @@
|
|||||||
# $NetBSD: deptgt-notparallel.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $
|
# $NetBSD: deptgt-notparallel.mk,v 1.3 2021/12/13 23:38:54 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the special target .NOTPARALLEL in dependency declarations.
|
# Tests for the special target .NOTPARALLEL in dependency declarations, which
|
||||||
|
# prevents the job module from doing anything in parallel, by setting the
|
||||||
|
# maximum jobs to 1. This only applies to the current make, it is not
|
||||||
|
# exported to submakes.
|
||||||
|
|
||||||
# TODO: Implementation
|
.MAKEFLAGS: -j4
|
||||||
|
|
||||||
all:
|
# Set opts.maxJobs back to 1. Without this line, the output would be in
|
||||||
@:;
|
# random order, interleaved with separators like '--- 1 ---'.
|
||||||
|
.NOTPARALLEL:
|
||||||
|
|
||||||
|
all: 1 2 3 4 5 6 7 8
|
||||||
|
1 2 3 4 5 6 7 8: .PHONY
|
||||||
|
: Making ${.TARGET} out of nothing.
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
Parsing line 15: .ORDER: three one
|
||||||
|
ParseDependency(.ORDER: three one)
|
||||||
|
# .ORDER forces 'three' to be made before 'one'
|
||||||
|
# three, unmade, type OP_DEPENDS|OP_PHONY|OP_HAS_COMMANDS, flags none
|
||||||
|
# one, unmade, type OP_DEPENDS|OP_PHONY, flags none
|
||||||
|
Parsing line 16: .MAKEFLAGS: -d0
|
||||||
|
ParseDependency(.MAKEFLAGS: -d0)
|
||||||
: 'Making two out of one.'
|
: 'Making two out of one.'
|
||||||
: 'Making three out of two.'
|
: 'Making three out of two.'
|
||||||
: 'Making all out of three.'
|
: 'Making all out of three.'
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# $NetBSD: deptgt-order.mk,v 1.3 2021/06/17 15:25:33 rillig Exp $
|
# $NetBSD: deptgt-order.mk,v 1.4 2021/12/13 23:38:54 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the special target .ORDER in dependency declarations.
|
# Tests for the special target .ORDER in dependency declarations.
|
||||||
|
|
||||||
@ -11,7 +11,9 @@ three: two
|
|||||||
|
|
||||||
# This .ORDER creates a circular dependency since 'three' depends on 'one'
|
# This .ORDER creates a circular dependency since 'three' depends on 'one'
|
||||||
# but 'one' is supposed to be built after 'three'.
|
# but 'one' is supposed to be built after 'three'.
|
||||||
|
.MAKEFLAGS: -dp
|
||||||
.ORDER: three one
|
.ORDER: three one
|
||||||
|
.MAKEFLAGS: -d0
|
||||||
|
|
||||||
# XXX: The circular dependency should be detected here.
|
# XXX: The circular dependency should be detected here.
|
||||||
all: three
|
all: three
|
||||||
|
@ -1 +1,4 @@
|
|||||||
exit status 0
|
make: "deptgt-path-suffix.mk" line 8: Suffix '.c' not defined (yet)
|
||||||
|
make: Fatal errors encountered -- cannot continue
|
||||||
|
make: stopped in unit-tests
|
||||||
|
exit status 1
|
||||||
|
@ -1,8 +1,16 @@
|
|||||||
# $NetBSD: deptgt-path-suffix.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $
|
# $NetBSD: deptgt-path-suffix.mk,v 1.3 2021/12/13 23:38:54 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the special target .PATH.suffix in dependency declarations.
|
# Tests for the special target .PATH.suffix in dependency declarations.
|
||||||
|
|
||||||
# TODO: Implementation
|
# TODO: Implementation
|
||||||
|
|
||||||
|
# expect+1: Suffix '.c' not defined (yet)
|
||||||
|
.PATH.c: ..
|
||||||
|
|
||||||
|
.SUFFIXES: .c
|
||||||
|
|
||||||
|
# Now the suffix is defined, and the path is recorded.
|
||||||
|
.PATH.c: ..
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@:;
|
@:;
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
make: "deptgt.mk" line 10: warning: Extra target ignored
|
make: "deptgt.mk" line 10: warning: Extra target ignored
|
||||||
make: "deptgt.mk" line 28: Unassociated shell command ": command3 # parse error, since targets == NULL"
|
make: "deptgt.mk" line 28: Unassociated shell command ": command3 # parse error, since targets == NULL"
|
||||||
ParseReadLine (34): '${:U}: empty-source'
|
Parsing line 34: ${:U}: empty-source
|
||||||
ParseDependency(: empty-source)
|
ParseDependency(: empty-source)
|
||||||
ParseReadLine (35): ' : command for empty targets list'
|
Parsing line 35: : command for empty targets list
|
||||||
ParseReadLine (36): ': empty-source'
|
Parsing line 36: : empty-source
|
||||||
ParseDependency(: empty-source)
|
ParseDependency(: empty-source)
|
||||||
ParseReadLine (37): ' : command for empty targets list'
|
Parsing line 37: : command for empty targets list
|
||||||
ParseReadLine (38): '.MAKEFLAGS: -d0'
|
Parsing line 38: .MAKEFLAGS: -d0
|
||||||
ParseDependency(.MAKEFLAGS: -d0)
|
ParseDependency(.MAKEFLAGS: -d0)
|
||||||
make: "deptgt.mk" line 46: Unknown modifier "Z"
|
make: "deptgt.mk" line 46: Unknown modifier "Z"
|
||||||
|
make: "deptgt.mk" line 49: warning: Extra target ignored
|
||||||
|
make: "deptgt.mk" line 52: warning: Extra target (ordinary) ignored
|
||||||
|
make: "deptgt.mk" line 55: warning: Special and mundane targets don't mix. Mundane ones ignored
|
||||||
make: Fatal errors encountered -- cannot continue
|
make: Fatal errors encountered -- cannot continue
|
||||||
make: stopped in unit-tests
|
make: stopped in unit-tests
|
||||||
exit status 1
|
exit status 1
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# $NetBSD: deptgt.mk,v 1.11 2021/04/04 10:13:09 rillig Exp $
|
# $NetBSD: deptgt.mk,v 1.12 2021/12/13 23:38:54 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for special targets like .BEGIN or .SUFFIXES in dependency
|
# Tests for special targets like .BEGIN or .SUFFIXES in dependency
|
||||||
# declarations.
|
# declarations.
|
||||||
@ -45,5 +45,14 @@ ${:U}: empty-source
|
|||||||
# that nobody uses it.
|
# that nobody uses it.
|
||||||
$$$$$$$${:U:Z}:
|
$$$$$$$${:U:Z}:
|
||||||
|
|
||||||
|
# expect+1: warning: Extra target ignored
|
||||||
|
.END ordinary:
|
||||||
|
|
||||||
|
# expect+1: warning: Extra target (ordinary) ignored
|
||||||
|
.PATH ordinary:
|
||||||
|
|
||||||
|
# expect+1: Special and mundane targets don't mix. Mundane ones ignored
|
||||||
|
ordinary .PATH:
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@:;
|
@:;
|
||||||
|
@ -1 +1,4 @@
|
|||||||
exit status 0
|
make: "directive-dinclude-error.inc" line 1: Invalid line type
|
||||||
|
make: Fatal errors encountered -- cannot continue
|
||||||
|
make: stopped in unit-tests
|
||||||
|
exit status 1
|
||||||
|
@ -1,9 +1,24 @@
|
|||||||
# $NetBSD: directive-dinclude.mk,v 1.1 2020/09/13 09:20:23 rillig Exp $
|
# $NetBSD: directive-dinclude.mk,v 1.2 2022/01/23 21:48:59 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the .dinclude directive, which includes another file,
|
# Tests for the .dinclude directive, which includes another file,
|
||||||
# typically named .depend.
|
# silently skipping it if it cannot be opened. This is primarily used for
|
||||||
|
# including '.depend' files, that's where the 'd' comes from.
|
||||||
|
#
|
||||||
|
# The 'silently skipping' only applies to the case where the file cannot be
|
||||||
|
# opened. Parse errors and other errors are handled the same way as in the
|
||||||
|
# other .include directives.
|
||||||
|
|
||||||
# TODO: Implementation
|
# No complaint that there is no such file.
|
||||||
|
.dinclude "${.CURDIR}/directive-dinclude-nonexistent.inc"
|
||||||
|
|
||||||
all:
|
# No complaint either, even though the operating system error is ENOTDIR, not
|
||||||
@:;
|
# ENOENT.
|
||||||
|
.dinclude "${MAKEFILE}/subdir"
|
||||||
|
|
||||||
|
# Errors that are not related to opening the file are still reported.
|
||||||
|
# expect: make: "directive-dinclude-error.inc" line 1: Invalid line type
|
||||||
|
_!= echo 'syntax error' > directive-dinclude-error.inc
|
||||||
|
.dinclude "${.CURDIR}/directive-dinclude-error.inc"
|
||||||
|
_!= rm directive-dinclude-error.inc
|
||||||
|
|
||||||
|
all: .PHONY
|
||||||
|
@ -1,8 +1,21 @@
|
|||||||
# $NetBSD: directive-elifdef.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $
|
# $NetBSD: directive-elifdef.mk,v 1.3 2022/01/22 16:23:56 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the .elifdef directive.
|
# Tests for the .elifdef directive, which is seldom used. Instead of writing
|
||||||
|
# '.elifdef VAR', the usual form is the more versatile '.elif defined(VAR)'.
|
||||||
|
|
||||||
# TODO: Implementation
|
# At this point, VAR is not defined, so the condition evaluates to false.
|
||||||
|
.if 0
|
||||||
|
.elifdef VAR
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
|
VAR= # defined
|
||||||
|
|
||||||
|
# At this point, VAR is defined, so the condition evaluates to true.
|
||||||
|
.if 0
|
||||||
|
.elifdef VAR
|
||||||
|
.else
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@:;
|
|
||||||
|
@ -1,8 +1,23 @@
|
|||||||
# $NetBSD: directive-elifndef.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $
|
# $NetBSD: directive-elifndef.mk,v 1.3 2022/01/22 21:50:41 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the .elifndef directive.
|
# Tests for the .elifndef directive, which is an obscure form of writing the
|
||||||
|
# more usual '.elif !defined(VAR)'.
|
||||||
|
|
||||||
# TODO: Implementation
|
# At this point, VAR is not yet defined, and due to the 'n' in 'elifndef' the
|
||||||
|
# condition evaluates to true.
|
||||||
|
.if 0
|
||||||
|
.elifndef VAR && VAR || VAR
|
||||||
|
.else
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
|
VAR= # defined
|
||||||
|
|
||||||
|
# At this point, VAR is defined, and due to the 'n' in 'elifndef' the
|
||||||
|
# condition evaluates to false.
|
||||||
|
.if 0
|
||||||
|
.elifndef VAR && VAR || VAR
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@:;
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
ParseReadLine (21): 'UT_VAR= <${REF}>'
|
Parsing line 21: UT_VAR= <${REF}>
|
||||||
Global: UT_VAR = <${REF}>
|
Global: UT_VAR = <${REF}>
|
||||||
ParseReadLine (28): '.export UT_VAR'
|
Parsing line 28: .export UT_VAR
|
||||||
Global: .MAKE.EXPORTED = UT_VAR
|
Global: .MAKE.EXPORTED = UT_VAR
|
||||||
ParseReadLine (32): ': ${UT_VAR:N*}'
|
Parsing line 32: : ${UT_VAR:N*}
|
||||||
Var_Parse: ${UT_VAR:N*} (eval-defined)
|
Var_Parse: ${UT_VAR:N*} (eval-defined)
|
||||||
Var_Parse: ${REF}> (eval-defined)
|
Var_Parse: ${REF}> (eval-defined)
|
||||||
Evaluating modifier ${UT_VAR:N...} on value "<>"
|
Evaluating modifier ${UT_VAR:N...} on value "<>"
|
||||||
@ -14,6 +14,7 @@ CondParser_Eval: ${:!echo "\$UT_VAR"!} != "<>"
|
|||||||
Var_Parse: ${:!echo "\$UT_VAR"!} != "<>" (eval-defined)
|
Var_Parse: ${:!echo "\$UT_VAR"!} != "<>" (eval-defined)
|
||||||
Evaluating modifier ${:!...} on value "" (eval-defined, undefined)
|
Evaluating modifier ${:!...} on value "" (eval-defined, undefined)
|
||||||
Modifier part: "echo "$UT_VAR""
|
Modifier part: "echo "$UT_VAR""
|
||||||
|
Capturing the output of command "echo "$UT_VAR""
|
||||||
Var_Parse: ${.MAKE.EXPORTED:O:u} (eval)
|
Var_Parse: ${.MAKE.EXPORTED:O:u} (eval)
|
||||||
Evaluating modifier ${.MAKE.EXPORTED:O} on value "UT_VAR"
|
Evaluating modifier ${.MAKE.EXPORTED:O} on value "UT_VAR"
|
||||||
Result of ${.MAKE.EXPORTED:O} is "UT_VAR"
|
Result of ${.MAKE.EXPORTED:O} is "UT_VAR"
|
||||||
@ -23,7 +24,7 @@ Var_Parse: ${UT_VAR} (eval)
|
|||||||
Var_Parse: ${REF}> (eval)
|
Var_Parse: ${REF}> (eval)
|
||||||
Result of ${:!echo "\$UT_VAR"!} is "<>" (eval-defined, defined)
|
Result of ${:!echo "\$UT_VAR"!} is "<>" (eval-defined, defined)
|
||||||
lhs = "<>", rhs = "<>", op = !=
|
lhs = "<>", rhs = "<>", op = !=
|
||||||
ParseReadLine (50): ': ${UT_VAR:N*}'
|
Parsing line 50: : ${UT_VAR:N*}
|
||||||
Var_Parse: ${UT_VAR:N*} (eval-defined)
|
Var_Parse: ${UT_VAR:N*} (eval-defined)
|
||||||
Var_Parse: ${REF}> (eval-defined)
|
Var_Parse: ${REF}> (eval-defined)
|
||||||
Evaluating modifier ${UT_VAR:N...} on value "<>"
|
Evaluating modifier ${UT_VAR:N...} on value "<>"
|
||||||
@ -31,12 +32,13 @@ Pattern for ':N' is "*"
|
|||||||
ModifyWords: split "<>" into 1 word
|
ModifyWords: split "<>" into 1 word
|
||||||
Result of ${UT_VAR:N*} is ""
|
Result of ${UT_VAR:N*} is ""
|
||||||
ParseDependency(: )
|
ParseDependency(: )
|
||||||
ParseReadLine (54): 'REF= defined'
|
Parsing line 54: REF= defined
|
||||||
Global: REF = defined
|
Global: REF = defined
|
||||||
CondParser_Eval: ${:!echo "\$UT_VAR"!} != "<defined>"
|
CondParser_Eval: ${:!echo "\$UT_VAR"!} != "<defined>"
|
||||||
Var_Parse: ${:!echo "\$UT_VAR"!} != "<defined>" (eval-defined)
|
Var_Parse: ${:!echo "\$UT_VAR"!} != "<defined>" (eval-defined)
|
||||||
Evaluating modifier ${:!...} on value "" (eval-defined, undefined)
|
Evaluating modifier ${:!...} on value "" (eval-defined, undefined)
|
||||||
Modifier part: "echo "$UT_VAR""
|
Modifier part: "echo "$UT_VAR""
|
||||||
|
Capturing the output of command "echo "$UT_VAR""
|
||||||
Var_Parse: ${.MAKE.EXPORTED:O:u} (eval)
|
Var_Parse: ${.MAKE.EXPORTED:O:u} (eval)
|
||||||
Evaluating modifier ${.MAKE.EXPORTED:O} on value "UT_VAR"
|
Evaluating modifier ${.MAKE.EXPORTED:O} on value "UT_VAR"
|
||||||
Result of ${.MAKE.EXPORTED:O} is "UT_VAR"
|
Result of ${.MAKE.EXPORTED:O} is "UT_VAR"
|
||||||
@ -46,10 +48,10 @@ Var_Parse: ${UT_VAR} (eval)
|
|||||||
Var_Parse: ${REF}> (eval)
|
Var_Parse: ${REF}> (eval)
|
||||||
Result of ${:!echo "\$UT_VAR"!} is "<defined>" (eval-defined, defined)
|
Result of ${:!echo "\$UT_VAR"!} is "<defined>" (eval-defined, defined)
|
||||||
lhs = "<defined>", rhs = "<defined>", op = !=
|
lhs = "<defined>", rhs = "<defined>", op = !=
|
||||||
ParseReadLine (62): 'all:'
|
Parsing line 62: all:
|
||||||
ParseDependency(all:)
|
ParseDependency(all:)
|
||||||
Global: .ALLTARGETS = all
|
Global: .ALLTARGETS = all
|
||||||
ParseReadLine (63): '.MAKEFLAGS: -d0'
|
Parsing line 63: .MAKEFLAGS: -d0
|
||||||
ParseDependency(.MAKEFLAGS: -d0)
|
ParseDependency(.MAKEFLAGS: -d0)
|
||||||
Global: .MAKEFLAGS = -r -k -d cpv -d
|
Global: .MAKEFLAGS = -r -k -d cpv -d
|
||||||
Global: .MAKEFLAGS = -r -k -d cpv -d 0
|
Global: .MAKEFLAGS = -r -k -d cpv -d 0
|
||||||
|
@ -27,29 +27,29 @@ make: "directive-for-escape.mk" line 43: value-with-modifier
|
|||||||
For: end for 1
|
For: end for 1
|
||||||
For: loop body:
|
For: loop body:
|
||||||
. info ${:U\${UNDEF\:U\\$\\$}
|
. info ${:U\${UNDEF\:U\\$\\$}
|
||||||
make: "directive-for-escape.mk" line 57: ${UNDEF:U\$
|
make: "directive-for-escape.mk" line 72: ${UNDEF:U\backslash$
|
||||||
For: loop body:
|
For: loop body:
|
||||||
. info ${:U{{\}\}}
|
. info ${:U{{\}\}}
|
||||||
make: "directive-for-escape.mk" line 57: {{}}
|
make: "directive-for-escape.mk" line 72: {{}}
|
||||||
For: loop body:
|
For: loop body:
|
||||||
. info ${:Uend\}}
|
. info ${:Uend\}}
|
||||||
make: "directive-for-escape.mk" line 57: end}
|
make: "directive-for-escape.mk" line 72: end}
|
||||||
For: end for 1
|
For: end for 1
|
||||||
For: loop body:
|
For: loop body:
|
||||||
. info ${:Ubegin<${UNDEF:Ufallback:N{{{}}}}>end}
|
. info ${:Ubegin<${UNDEF:Ufallback:N{{{}}}}>end}
|
||||||
make: "directive-for-escape.mk" line 69: begin<fallback>end
|
make: "directive-for-escape.mk" line 84: begin<fallback>end
|
||||||
For: end for 1
|
For: end for 1
|
||||||
For: loop body:
|
For: loop body:
|
||||||
. info ${:U\$}
|
. info ${:U\$}
|
||||||
make: "directive-for-escape.mk" line 77: $
|
make: "directive-for-escape.mk" line 92: $
|
||||||
For: end for 1
|
For: end for 1
|
||||||
For: loop body:
|
For: loop body:
|
||||||
. info ${NUMBERS} ${:Ureplaced}
|
. info ${NUMBERS} ${:Ureplaced}
|
||||||
make: "directive-for-escape.mk" line 85: one two three replaced
|
make: "directive-for-escape.mk" line 100: one two three replaced
|
||||||
For: end for 1
|
For: end for 1
|
||||||
For: loop body:
|
For: loop body:
|
||||||
. info ${:Ureplaced}
|
. info ${:Ureplaced}
|
||||||
make: "directive-for-escape.mk" line 95: replaced
|
make: "directive-for-escape.mk" line 110: replaced
|
||||||
For: end for 1
|
For: end for 1
|
||||||
For: loop body:
|
For: loop body:
|
||||||
. info . $$i: ${:Uinner}
|
. info . $$i: ${:Uinner}
|
||||||
@ -62,31 +62,85 @@ For: loop body:
|
|||||||
. info . $${i2}: ${i2}
|
. info . $${i2}: ${i2}
|
||||||
. info . $${i,}: ${i,}
|
. info . $${i,}: ${i,}
|
||||||
. info . adjacent: ${:Uinner}${:Uinner}${:Uinner:M*}${:Uinner}
|
. info . adjacent: ${:Uinner}${:Uinner}${:Uinner:M*}${:Uinner}
|
||||||
make: "directive-for-escape.mk" line 103: . $i: inner
|
make: "directive-for-escape.mk" line 118: . $i: inner
|
||||||
make: "directive-for-escape.mk" line 104: . ${i}: inner
|
make: "directive-for-escape.mk" line 119: . ${i}: inner
|
||||||
make: "directive-for-escape.mk" line 105: . ${i:M*}: inner
|
make: "directive-for-escape.mk" line 120: . ${i:M*}: inner
|
||||||
make: "directive-for-escape.mk" line 106: . $(i): inner
|
make: "directive-for-escape.mk" line 121: . $(i): inner
|
||||||
make: "directive-for-escape.mk" line 107: . $(i:M*): inner
|
make: "directive-for-escape.mk" line 122: . $(i:M*): inner
|
||||||
make: "directive-for-escape.mk" line 108: . ${i${:U}}: outer
|
make: "directive-for-escape.mk" line 123: . ${i${:U}}: outer
|
||||||
make: "directive-for-escape.mk" line 109: . ${i\}}: inner}
|
make: "directive-for-escape.mk" line 124: . ${i\}}: inner}
|
||||||
make: "directive-for-escape.mk" line 110: . ${i2}: two
|
make: "directive-for-escape.mk" line 125: . ${i2}: two
|
||||||
make: "directive-for-escape.mk" line 111: . ${i,}: comma
|
make: "directive-for-escape.mk" line 126: . ${i,}: comma
|
||||||
make: "directive-for-escape.mk" line 112: . adjacent: innerinnerinnerinner
|
make: "directive-for-escape.mk" line 127: . adjacent: innerinnerinnerinner
|
||||||
For: end for 1
|
For: end for 1
|
||||||
For: loop body:
|
For: loop body:
|
||||||
. info eight $$$$$$$$ and no cents.
|
. info eight $$$$$$$$ and no cents.
|
||||||
. info eight ${:Udollar}${:Udollar}${:Udollar}${:Udollar} and no cents.
|
. info eight ${:Udollar}${:Udollar}${:Udollar}${:Udollar} and no cents.
|
||||||
make: "directive-for-escape.mk" line 120: eight $$$$ and no cents.
|
make: "directive-for-escape.mk" line 135: eight $$$$ and no cents.
|
||||||
make: "directive-for-escape.mk" line 121: eight dollardollardollardollar and no cents.
|
make: "directive-for-escape.mk" line 136: eight dollardollardollardollar and no cents.
|
||||||
make: "directive-for-escape.mk" line 130: eight and no cents.
|
make: "directive-for-escape.mk" line 145: eight and no cents.
|
||||||
For: end for 1
|
For: end for 1
|
||||||
make: "directive-for-escape.mk" line 137: newline in .for value
|
make: "directive-for-escape.mk" line 152: newline in .for value
|
||||||
make: "directive-for-escape.mk" line 137: newline in .for value
|
make: "directive-for-escape.mk" line 152: newline in .for value
|
||||||
For: loop body:
|
For: loop body:
|
||||||
. info short: ${:U" "}
|
. info short: ${:U" "}
|
||||||
. info long: ${:U" "}
|
. info long: ${:U" "}
|
||||||
make: "directive-for-escape.mk" line 138: short: " "
|
make: "directive-for-escape.mk" line 153: short: " "
|
||||||
make: "directive-for-escape.mk" line 139: long: " "
|
make: "directive-for-escape.mk" line 154: long: " "
|
||||||
|
For: end for 1
|
||||||
|
For: loop body:
|
||||||
|
For: end for 1
|
||||||
|
Parse_PushInput: .for loop in directive-for-escape.mk, line 167
|
||||||
|
make: "directive-for-escape.mk" line 167: newline in .for value
|
||||||
|
in .for loop from directive-for-escape.mk:167 with i = "
|
||||||
|
"
|
||||||
|
For: loop body:
|
||||||
|
: ${:U" "}
|
||||||
|
SetFilenameVars: ${.PARSEDIR} = <some-dir> ${.PARSEFILE} = `directive-for-escape.mk'
|
||||||
|
Parsing line 168: : ${:U" "}
|
||||||
|
ParseDependency(: " ")
|
||||||
|
ParseEOF: returning to file directive-for-escape.mk, line 170
|
||||||
|
SetFilenameVars: ${.PARSEDIR} = <some-dir> ${.PARSEFILE} = `directive-for-escape.mk'
|
||||||
|
Parsing line 170: .MAKEFLAGS: -d0
|
||||||
|
ParseDependency(.MAKEFLAGS: -d0)
|
||||||
|
For: end for 1
|
||||||
|
For: loop body:
|
||||||
|
# ${:U#}
|
||||||
|
For: loop body:
|
||||||
|
# ${:U\\\\#}
|
||||||
|
For: end for 1
|
||||||
|
For: loop body:
|
||||||
|
# ${:U\$}
|
||||||
|
For: loop body:
|
||||||
|
# ${:U$i}
|
||||||
|
For: loop body:
|
||||||
|
# ${:U$(i)}
|
||||||
|
For: loop body:
|
||||||
|
# ${:U${i}}
|
||||||
|
For: loop body:
|
||||||
|
# ${:U$$}
|
||||||
|
For: loop body:
|
||||||
|
# ${:U$$$$}
|
||||||
|
For: loop body:
|
||||||
|
# ${:U${:U\$\$}}
|
||||||
|
For: end for 1
|
||||||
|
For: loop body:
|
||||||
|
# ${:U${.TARGET}}
|
||||||
|
For: loop body:
|
||||||
|
# ${:U${.TARGET}}
|
||||||
|
For: loop body:
|
||||||
|
# ${:U$${.TARGET\}}
|
||||||
|
For: loop body:
|
||||||
|
# ${:U$${.TARGET\}}
|
||||||
|
For: end for 1
|
||||||
|
For: loop body:
|
||||||
|
# ${:U(((}
|
||||||
|
For: loop body:
|
||||||
|
# ${:U{{{}
|
||||||
|
For: loop body:
|
||||||
|
# ${:U)))}
|
||||||
|
For: loop body:
|
||||||
|
# ${:U\}\}\}}
|
||||||
make: Fatal errors encountered -- cannot continue
|
make: Fatal errors encountered -- cannot continue
|
||||||
make: stopped in unit-tests
|
make: stopped in unit-tests
|
||||||
exit status 1
|
exit status 1
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# $NetBSD: directive-for-escape.mk,v 1.12 2021/12/05 11:40:03 rillig Exp $
|
# $NetBSD: directive-for-escape.mk,v 1.15 2022/01/27 20:15:14 rillig Exp $
|
||||||
#
|
#
|
||||||
# Test escaping of special characters in the iteration values of a .for loop.
|
# Test escaping of special characters in the iteration values of a .for loop.
|
||||||
# These values get expanded later using the :U variable modifier, and this
|
# These values get expanded later using the :U variable modifier, and this
|
||||||
@ -50,7 +50,22 @@ VALUES= $$ $${V} $${V:=-with-modifier} $$(V) $$(V:=-with-modifier)
|
|||||||
# being that each '$' is written as '$$'.
|
# being that each '$' is written as '$$'.
|
||||||
#
|
#
|
||||||
# The .for loop splits ${VALUES} into 3 words, at the space characters, since
|
# The .for loop splits ${VALUES} into 3 words, at the space characters, since
|
||||||
# these are not escaped.
|
# the '$$' is an ordinary character and the spaces are not escaped.
|
||||||
|
# Word 1 is '${UNDEF:U\$\$'
|
||||||
|
# Word 2 is '{{}}'
|
||||||
|
# Word 3 is 'end}'
|
||||||
|
# The first iteration expands the body of the .for loop to:
|
||||||
|
# expect: . info ${:U\${UNDEF\:U\\$\\$}
|
||||||
|
# The modifier ':U' unescapes the '\$' to a simple '$'.
|
||||||
|
# The modifier ':U' unescapes the '\:' to a simple ':'.
|
||||||
|
# The modifier ':U' unescapes the '\\' to a simple '\'.
|
||||||
|
# The modifier ':U' resolves the expression '$\' to the word 'backslash', due
|
||||||
|
# to the following variable definition.
|
||||||
|
${:U\\}= backslash
|
||||||
|
# FIXME: There was no expression '$\' in the original text of the previous
|
||||||
|
# line, that's a surprise in the parser.
|
||||||
|
# The modifier ':U' unescapes the '\$' to a simple '$'.
|
||||||
|
# expect+4: ${UNDEF:U\backslash$
|
||||||
VALUES= $${UNDEF:U\$$\$$ {{}} end}
|
VALUES= $${UNDEF:U\$$\$$ {{}} end}
|
||||||
# XXX: Where in the code does the '\$\$' get converted into a single '\$'?
|
# XXX: Where in the code does the '\$\$' get converted into a single '\$'?
|
||||||
.for i in ${VALUES}
|
.for i in ${VALUES}
|
||||||
@ -139,4 +154,47 @@ ${closing-brace}= <closing-brace> # alternative interpretation
|
|||||||
. info long: ${i}
|
. info long: ${i}
|
||||||
.endfor
|
.endfor
|
||||||
|
|
||||||
|
# No error since the newline character is not actually used.
|
||||||
|
.for i in "${.newline}"
|
||||||
|
.endfor
|
||||||
|
|
||||||
|
# Between for.c 1.161 from 2022-01-08 and before for.c 1.163 from 2022-01-09,
|
||||||
|
# a newline character in a .for loop led to a crash since at the point where
|
||||||
|
# the error message including the stack trace is printed, the body of the .for
|
||||||
|
# loop is assembled, and at that point, ForLoop.nextItem had already been
|
||||||
|
# advanced.
|
||||||
|
.MAKEFLAGS: -dp
|
||||||
|
.for i in "${.newline}"
|
||||||
|
: $i
|
||||||
|
.endfor
|
||||||
|
.MAKEFLAGS: -d0
|
||||||
|
|
||||||
|
.MAKEFLAGS: -df
|
||||||
|
.for i in \# \\\#
|
||||||
|
# $i
|
||||||
|
.endfor
|
||||||
|
|
||||||
|
.for i in $$ $$i $$(i) $${i} $$$$ $$$$$$$$ $${:U\$$\$$}
|
||||||
|
# $i
|
||||||
|
.endfor
|
||||||
|
|
||||||
|
# The expression '${.TARGET}' must be preserved as it is one of the 7 built-in
|
||||||
|
# target-local variables. See for.c 1.45 from 2009-01-14.
|
||||||
|
.for i in ${.TARGET} $${.TARGET} $$${.TARGET} $$$${.TARGET}
|
||||||
|
# $i
|
||||||
|
.endfor
|
||||||
|
# expect: # ${:U${.TARGET}}
|
||||||
|
# XXX: Why does '$' result in the same text as '$$'?
|
||||||
|
# expect: # ${:U${.TARGET}}
|
||||||
|
# XXX: Why does the '$$' before the '${.TARGET}' lead to an escaped '}'?
|
||||||
|
# expect: # ${:U$${.TARGET\}}
|
||||||
|
# XXX: Why does '$' result in the same text as '$$'?
|
||||||
|
# XXX: Why does the '$$' before the '${.TARGET}' lead to an escaped '}'?
|
||||||
|
# expect: # ${:U$${.TARGET\}}
|
||||||
|
|
||||||
|
.for i in ((( {{{ ))) }}}
|
||||||
|
# $i
|
||||||
|
.endfor
|
||||||
|
.MAKEFLAGS: -d0
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
make: "directive-for-generating-endif.mk" line 21: if-less endif
|
make: "directive-for-generating-endif.mk" line 21: if-less endif
|
||||||
make: "directive-for-generating-endif.mk" line 21: if-less endif
|
make: "directive-for-generating-endif.mk" line 21: if-less endif
|
||||||
make: "directive-for-generating-endif.mk" line 21: if-less endif
|
make: "directive-for-generating-endif.mk" line 21: if-less endif
|
||||||
make: "directive-for-generating-endif.mk" line 0: 3 open conditionals
|
make: "directive-for-generating-endif.mk" line 26: 3 open conditionals
|
||||||
make: Fatal errors encountered -- cannot continue
|
make: Fatal errors encountered -- cannot continue
|
||||||
make: stopped in unit-tests
|
make: stopped in unit-tests
|
||||||
exit status 1
|
exit status 1
|
||||||
|
@ -19,6 +19,24 @@ make: "directive-for.mk" line 148: outer "quoted" \"quoted\"
|
|||||||
make: "directive-for.mk" line 154: Unknown modifier "Z"
|
make: "directive-for.mk" line 154: Unknown modifier "Z"
|
||||||
make: "directive-for.mk" line 155: XXX: Not reached word1
|
make: "directive-for.mk" line 155: XXX: Not reached word1
|
||||||
make: "directive-for.mk" line 155: XXX: Not reached word3
|
make: "directive-for.mk" line 155: XXX: Not reached word3
|
||||||
|
make: "directive-for.mk" line 160: no iteration variables in for
|
||||||
|
make: "directive-for.mk" line 162: Missing argument for ".error"
|
||||||
|
make: "directive-for.mk" line 163: for-less endfor
|
||||||
|
make: "directive-for.mk" line 187: 1 open conditional
|
||||||
|
make: "directive-for.mk" line 203: for-less endfor
|
||||||
|
make: "directive-for.mk" line 204: if-less endif
|
||||||
|
make: "directive-for.mk" line 212: if-less endif
|
||||||
|
For: end for 1
|
||||||
|
For: loop body:
|
||||||
|
.\
|
||||||
|
for inner in i
|
||||||
|
.\
|
||||||
|
endfor
|
||||||
|
make: "directive-for.mk" line 229: Unexpected end of file in .for loop
|
||||||
|
For: loop body:
|
||||||
|
.\
|
||||||
|
endfor
|
||||||
|
make: "directive-for.mk" line 227: for-less endfor
|
||||||
make: Fatal errors encountered -- cannot continue
|
make: Fatal errors encountered -- cannot continue
|
||||||
make: stopped in unit-tests
|
make: stopped in unit-tests
|
||||||
exit status 1
|
exit status 1
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# $NetBSD: directive-for.mk,v 1.10 2020/12/27 09:58:35 rillig Exp $
|
# $NetBSD: directive-for.mk,v 1.13 2022/01/15 12:35:18 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the .for directive.
|
# Tests for the .for directive.
|
||||||
#
|
#
|
||||||
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
# Using the .for loop, lists of values can be produced.
|
# Using the .for loop, lists of values can be produced.
|
||||||
# In simple cases, the :@var@${var}@ variable modifier can be used to
|
# In simple cases, the :@var@${var}@ variable modifier can be used to
|
||||||
# reach the same effects.
|
# achieve the same effects.
|
||||||
#
|
#
|
||||||
.undef NUMBERS
|
.undef NUMBERS
|
||||||
.for num in 1 2 3
|
.for num in 1 2 3
|
||||||
@ -135,7 +135,7 @@ EXPANSION${plus}= value
|
|||||||
|
|
||||||
# Ensure that braces and parentheses are properly escaped by the .for loop.
|
# Ensure that braces and parentheses are properly escaped by the .for loop.
|
||||||
# Each line must print the same word 3 times.
|
# Each line must print the same word 3 times.
|
||||||
# See GetEscapes.
|
# See ForLoop_SubstBody.
|
||||||
.for v in ( [ { ) ] } (()) [[]] {{}} )( ][ }{
|
.for v in ( [ { ) ] } (()) [[]] {{}} )( ][ }{
|
||||||
. info $v ${v} $(v)
|
. info $v ${v} $(v)
|
||||||
.endfor
|
.endfor
|
||||||
@ -155,5 +155,76 @@ var= outer
|
|||||||
. info XXX: Not reached ${var}
|
. info XXX: Not reached ${var}
|
||||||
.endfor
|
.endfor
|
||||||
|
|
||||||
all:
|
|
||||||
@:;
|
# An empty list of variables to the left of the 'in' is a parse error.
|
||||||
|
.for in value # expect+0: no iteration variables in for
|
||||||
|
# XXX: The loop body is evaluated once, even with the parse error above.
|
||||||
|
. error # expect+0: Missing argument for ".error"
|
||||||
|
.endfor # expect+0: for-less endfor
|
||||||
|
|
||||||
|
# An empty list of iteration values to the right of the 'in' is accepted.
|
||||||
|
# Unlike in the shell, it is not a parse error.
|
||||||
|
.for var in
|
||||||
|
. error
|
||||||
|
.endfor
|
||||||
|
|
||||||
|
# If the iteration values become empty after expanding the expressions, the
|
||||||
|
# body of the loop is not evaluated. It is not a parse error.
|
||||||
|
.for var in ${:U}
|
||||||
|
. error
|
||||||
|
.endfor
|
||||||
|
|
||||||
|
|
||||||
|
# The loop body can be empty.
|
||||||
|
.for var in 1 2 3
|
||||||
|
.endfor
|
||||||
|
|
||||||
|
|
||||||
|
# A mismatched .if inside a .for loop is detected each time when the loop body
|
||||||
|
# is processed.
|
||||||
|
.for var in value
|
||||||
|
. if 0
|
||||||
|
.endfor # expect+0: 1 open conditional
|
||||||
|
|
||||||
|
# If there are no iteration values, the loop body is not processed, and the
|
||||||
|
# check for mismatched conditionals is not performed.
|
||||||
|
.for var in ${:U}
|
||||||
|
. if 0
|
||||||
|
.endfor
|
||||||
|
|
||||||
|
|
||||||
|
# When a .for without the corresponding .endfor occurs in an inactive branch
|
||||||
|
# of an .if, the .for directive is just skipped, it does not even need a
|
||||||
|
# corresponding .endfor. In other words, the behavior of the parser depends
|
||||||
|
# on the actual values of the conditions in the .if clauses.
|
||||||
|
.if 0
|
||||||
|
. for var in value # does not need a corresponding .endfor
|
||||||
|
.endif
|
||||||
|
.endfor # expect+0: for-less endfor
|
||||||
|
.endif # expect+0: if-less endif
|
||||||
|
|
||||||
|
|
||||||
|
# When a .for without the corresponding .endfor occurs in an active branch of
|
||||||
|
# an .if, the parser just counts the number of .for and .endfor directives,
|
||||||
|
# without looking at any other directives.
|
||||||
|
.if 1
|
||||||
|
. for var in value
|
||||||
|
. endif # expect+0: if-less endif
|
||||||
|
. endfor # no 'for-less endfor'
|
||||||
|
.endif # no 'if-less endif'
|
||||||
|
|
||||||
|
|
||||||
|
# When make parses a .for loop, it assumes that there is no line break between
|
||||||
|
# the '.' and the 'for' or 'endfor', as there is no practical reason to break
|
||||||
|
# the line at this point. When make scans the outer .for loop, it does not
|
||||||
|
# recognize the inner directives as such. When make scans the inner .for
|
||||||
|
# loop, it recognizes the '.\n for' but does not recognize the '.\n endfor',
|
||||||
|
# as LK_FOR_BODY preserves the backslash-newline sequences.
|
||||||
|
.MAKEFLAGS: -df
|
||||||
|
.for outer in o
|
||||||
|
.\
|
||||||
|
for inner in i
|
||||||
|
.\
|
||||||
|
endfor
|
||||||
|
.endfor
|
||||||
|
.MAKEFLAGS: -d0
|
||||||
|
@ -1 +1,4 @@
|
|||||||
exit status 0
|
make: "directive-hyphen-include-error.inc" line 1: Invalid line type
|
||||||
|
make: Fatal errors encountered -- cannot continue
|
||||||
|
make: stopped in unit-tests
|
||||||
|
exit status 1
|
||||||
|
@ -1,9 +1,23 @@
|
|||||||
# $NetBSD: directive-hyphen-include.mk,v 1.1 2020/09/13 09:20:23 rillig Exp $
|
# $NetBSD: directive-hyphen-include.mk,v 1.2 2022/01/23 21:48:59 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the .-include directive, which includes another file,
|
# Tests for the .-include directive, which includes another file,
|
||||||
# silently skipping it if it cannot be opened.
|
# silently skipping it if it cannot be opened.
|
||||||
|
#
|
||||||
|
# The 'silently skipping' only applies to the case where the file cannot be
|
||||||
|
# opened. Parse errors and other errors are handled the same way as in the
|
||||||
|
# other .include directives.
|
||||||
|
|
||||||
# TODO: Implementation
|
# No complaint that there is no such file.
|
||||||
|
.-include "${.CURDIR}/directive-hyphen-include-nonexistent.inc"
|
||||||
|
|
||||||
all:
|
# No complaint either, even though the operating system error is ENOTDIR, not
|
||||||
@:;
|
# ENOENT.
|
||||||
|
.-include "${MAKEFILE}/subdir"
|
||||||
|
|
||||||
|
# Errors that are not related to opening the file are still reported.
|
||||||
|
# expect: make: "directive-hyphen-include-error.inc" line 1: Invalid line type
|
||||||
|
_!= echo 'syntax error' > directive-hyphen-include-error.inc
|
||||||
|
.-include "${.CURDIR}/directive-hyphen-include-error.inc"
|
||||||
|
_!= rm directive-hyphen-include-error.inc
|
||||||
|
|
||||||
|
all: .PHONY
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user