commit fe800e4efb67e6a5babcf2b5f51e764387501cc9
parent 72f29b44b8b37437c29f1c72cfab5a1624d85dd4
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Thu, 31 Oct 2024 21:39:37 +0100
make: Rework macro definitions
Macros can be defined from different sources, and there are precise
rules about when a source can ovveride other source. Definitions from
a Makefile cannot override ever the definition from the command line
or from MAKEFLAGS, but it was happening before this change.
Diffstat:
4 files changed, 120 insertions(+), 39 deletions(-)
diff --git a/src/cmd/scc-make/main.c b/src/cmd/scc-make/main.c
@@ -135,7 +135,7 @@ appendmakeflags(char *text)
t = emalloc(n+1);
snprintf(t, n+1, fmt, s, text);
- setmacro("MAKEFLAGS", t, EXPORT);
+ setmacro("MAKEFLAGS", t, MAKEFLAGS, EXPORT);
free(t);
}
@@ -205,7 +205,7 @@ parseflag(int flag, char **args, char ***argv)
}
static int
-assign(char *s, int export)
+assign(char *s, int where, int export)
{
int pos;
char *t;
@@ -219,20 +219,20 @@ assign(char *s, int export)
t = estrdup(s);
t[pos] = '\0';
- setmacro(t, t+pos+1, export);
+ setmacro(t, t+pos+1, where, export);
free(t);
return 1;
}
static void
-parseargv(char **argv, char ***targets, int export)
+parseargv(char **argv, char ***targets, int where, int export)
{
char *s;
for ( ; *argv; ++argv) {
s = *argv;
if (s[0] != '-') {
- if (!assign(s, export))
+ if (!assign(s, where, export))
break;
continue;
}
@@ -253,7 +253,7 @@ parsemakeflags(void)
if ((flags = getenv("MAKEFLAGS")) == NULL)
return;
- setmacro("MAKEFLAGS", "", EXPORT);
+ setmacro("MAKEFLAGS", "", MAKEFLAGS, EXPORT);
while (*flags == ' ' || *flags == '\t')
flags++;
@@ -274,7 +274,7 @@ parsemakeflags(void)
}
if (arr)
- parseargv(arr, NULL, NOEXPORT);
+ parseargv(arr, NULL, MAKEFLAGS, NOEXPORT);
free(arr);
}
}
@@ -334,33 +334,34 @@ enadebug(char *argv[])
int
main(int argc, char *argv[])
{
- char *arg0;
+ char *arg0, **targets;
signal(SIGINT, sighandler);
signal(SIGHUP, sighandler);
signal(SIGTERM, sighandler);
signal(SIGQUIT, sighandler);
+ targets = NULL;
arg0 = *argv++;
enadebug(argv);
inject(defaults);
- parsemakefiles(argv);
- parsemakeflags();
- parseargv(argv, &argv, EXPORT);
+ setmacro("MAKE", arg0, MAKEFILE, NOEXPORT);
- setmacro("MAKE", arg0, NOEXPORT);
+ parsemakeflags();
+ parseargv(argv, &targets, CMDLINE, EXPORT);
+ parsemakefiles(argv);
if (pflag) {
dumpmacros();
dumprules();
}
- if (!*argv) {
+ if (!*targets) {
build(NULL);
} else {
- while (*argv)
- build(*argv++);
+ while (*targets)
+ build(*targets++);
}
exit(exitstatus);
diff --git a/src/cmd/scc-make/make.h b/src/cmd/scc-make/make.h
@@ -8,6 +8,14 @@ enum {
EXPORT,
};
+enum {
+ UNDEF,
+ ENVIRON,
+ CMDLINE,
+ MAKEFILE,
+ MAKEFLAGS,
+};
+
struct target {
char *name;
char *target;
@@ -44,7 +52,7 @@ extern void adddep(char *, char *);
extern void addrule(char *, char **, int);
extern char *getmacro(char *);
-extern void setmacro(char *, char *, int);
+extern void setmacro(char *, char *, int, int);
/* system depdendant */
extern time_t stamp(char *);
diff --git a/src/cmd/scc-make/parser.c b/src/cmd/scc-make/parser.c
@@ -50,6 +50,7 @@ struct input {
struct macro {
char *name;
char *value;
+ int where;
struct macro *next;
};
@@ -84,31 +85,19 @@ lookup(char *name)
mp = emalloc(sizeof(*mp));
mp->name = estrdup(name);
- mp->value = NULL;
+ mp->value = estrdup("");
mp->next = htab[h];
+ mp->where = UNDEF;
htab[h] = mp;
return mp;
}
-void
-setmacro(char *name, char *val, int export)
-{
- Macro *mp;
-
- mp = lookup(name);
- free(mp->value);
- mp->value = estrdup(val);
-
- if (export && strcmp(name, "SHELL") != 0)
- exportvar(name, val);
-}
-
-char *
-getmacro(char *name)
+static char *
+macroinfo(char *name, int *pwhere, Macro **mpp)
{
- int hide;
char *s, *t;
+ int hide, where;
Macro *mp = lookup(name);
hide = 0;
@@ -116,20 +105,88 @@ getmacro(char *name)
hide = 1;
s = mp->value;
- if (!s && !hide)
+ where = mp->where;
+
+ if (!s && !hide) {
+ where = ENVIRON;
s = getenv(name);
- if (!s)
- s = "";
+ }
if (eflag && !hide) {
t = getenv(name);
- if (t)
+ if (t) {
+ where = ENVIRON;
s = t;
+ }
}
+ if (pwhere)
+ *pwhere = where;
+ if (mpp)
+ *mpp = mp;
+
return s;
}
+char *
+getmacro(char *name)
+{
+ return macroinfo(name, NULL, NULL);
+}
+
+void
+setmacro(char *name, char *val, int where, int export)
+{
+ int owhere, set;
+ char *s;
+ Macro *mp;
+
+ assert(where != ENVIRON);
+
+ s = macroinfo(name, &owhere, &mp);
+
+ /*
+ * Default values are defined before anything else, and marked
+ * as MAKEFILES because they are injected as parseable text, and
+ * MAKEFILE variables are always overriden. ENVIRON macros are
+ * generated in macroinfo() and this is why this function should
+ * not receive a where == ENVIRON ever.
+ */
+
+ switch (owhere) {
+ case UNDEF:
+ case MAKEFILE:
+ set = 1;
+ break;
+ case ENVIRON:
+ set = (where == MAKEFLAGS || where == CMDLINE);
+ set |= (where == MAKEFILE && !eflag);
+ break;
+ case MAKEFLAGS:
+ set = (where == CMDLINE || where == MAKEFLAGS);
+ break;
+ case CMDLINE:
+ set = (where == CMDLINE);
+ break;
+ default:
+ abort();
+ }
+
+ if (!set) {
+ debug("hidding override of %s from '%s' to '%s'", name, s, val);
+ } else {
+ debug("override %s from '%s' to '%s'", name, s, val);
+ free(mp->value);
+ mp->value = estrdup(val);
+ mp->where = where;
+
+ if (export && strcmp(name, "SHELL") != 0) {
+ debug("exporting macro %s", name);
+ exportvar(name, val);
+ }
+ }
+}
+
static struct loc *
getloc(void)
{
@@ -883,7 +940,6 @@ rule(char *targets[], int ntargets)
static void
assign(char *macros[], int n)
{
- int len, c;
char *defs;
if (n != 1)
@@ -891,7 +947,7 @@ assign(char *macros[], int n)
skipspaces();
defs = readmacrodef();
- setmacro(*macros, defs, NOEXPORT);
+ setmacro(*macros, defs, MAKEFILE, NOEXPORT);
free(defs);
}
diff --git a/tests/make/execute/0095-include.sh b/tests/make/execute/0095-include.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+trap 'rm -f $tmp1 $tmp2' EXIT INT TERM QUIT HUP
+
+tmp1=tmp1.$$
+tmp2=tmp2.$$
+
+cat > $tmp1 <<EOF
+Hello World!
+EOF
+
+scc-make -f- MK=test.mk hello <<'EOF' > $tmp2 2>&1
+MK = fail.mk
+include $(MK)
+EOF
+diff $tmp1 $tmp2