scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

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:
Msrc/cmd/scc-make/main.c | 31++++++++++++++++---------------
Msrc/cmd/scc-make/make.h | 10+++++++++-
Msrc/cmd/scc-make/parser.c | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Atests/make/execute/0095-include.sh | 16++++++++++++++++
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