make: Fix macro precedence - scc - simple c99 compiler (HTM) git clone git://git.simple-cc.org/scc (DIR) Log (DIR) Files (DIR) Refs (DIR) Submodules (DIR) README (DIR) LICENSE --- (DIR) commit 27c9f34bbbbbd150afef63255816ca0c40f24d95 (DIR) parent aff2954228ebe0e5bd04158caf3ea6bb5de26b7b (HTM) Author: Roberto E. Vargas Caballero <k0ga@shike2.com> Date: Sat, 20 Jan 2024 22:54:18 +0100 make: Fix macro precedence POSIX mandates the following precedence: 1- Macros specified on the make utility command line. 2- Macros defined by the MAKEFLAGS environment variable 3- The contents of the environment 4- Macros defined in the inference rules built into make. It means that macros defined in the makefiles has to read before macros from MAKEFLAGS and from the command line. The simplest solution passed by doing a first pass over all the options only to locate the -f options and read the makefiles. After that step we can parse the options from MAKEFLAGS and later from the command line and then we can be sure that the precedence is always correct. Diffstat: M src/cmd/make/main.c | 110 ++++++++++++++++--------------- M tests/make/execute/0004-fflag.sh | 2 +- M tests/make/execute/0005-fflag.sh | 2 +- 3 files changed, 59 insertions(+), 55 deletions(-) --- (DIR) diff --git a/src/cmd/make/main.c b/src/cmd/make/main.c @@ -28,8 +28,6 @@ int eflag, pflag, tflag, qflag; int exitstatus; sig_atomic_t stop; -static int hasmake; - void debug(char *fmt, ...) { @@ -96,15 +94,6 @@ sighandler(int signo) } static void -parsedefault(void) -{ - if (parse("makefile")) - return; - if (parse("Makefile")) - return; -} - -static void usage(void) { fputs("usage: make [-eiknprSstd] [-f file] [-j jobs] " @@ -156,13 +145,9 @@ parseflag(int flag, char **args, char ***argv) char *arg; switch (flag) { + case 'j': case 'f': - arg = getarg(args, argv); - if (strcmp(arg, "-") == 0) - arg = NULL; - if (!parse(arg)) - error("%s: %s", arg, strerror(errno)); - hasmake = 1; + getarg(args, argv); break; case 'e': eflag = 1; @@ -207,7 +192,6 @@ parseflag(int flag, char **args, char ***argv) dflag = 1; appendmakeflags("-d"); break; - case 'j': default: usage(); } @@ -234,29 +218,30 @@ assign(char *s, int export) } static void -parseargv(char ***argv, int export) +parseargv(char **argv, char ***targets, int export) { char *s; - for ( ; **argv; ++*argv) { - s = **argv; + for ( ; *argv; ++argv) { + s = *argv; if (s[0] != '-') { if (!assign(s, export)) break; continue; } while (*++s) - parseflag(*s, &s, argv); + parseflag(*s, &s, &argv); } -} - + if (targets) + *targets = argv; +} static void parsemakeflags(void) { - size_t len1, len2, n; - char *s, *t, **oargv, **argv, *flags; + int c, n; + char *s, *flags, **arr; if ((flags = getenv("MAKEFLAGS")) == NULL) return; @@ -272,49 +257,68 @@ parsemakeflags(void) flags++; } } else { - argv = emalloc(sizeof(char *) * 2); - argv[0] = flags; - argv[1] = NULL; - - s = flags; - for (n = 2; ; ++s) { - len1 = strcspn(s, " \t"); - if (s[len1] == '\0') - break; - len2 = strspn(s+len1, " \t"); - s[len1] = '\0'; - s += len1 + len2; - - argv = erealloc(argv, sizeof(char *) * (n+1)); - argv[n-1] = s; - argv[n] = NULL; + n = 0; + arr = NULL; + for (s = strtok(flags, " \t"); s; s = strtok(NULL, " \t")) { + n++; + arr = erealloc(arr, sizeof(char *) * (n+1)); + arr[n-1] = s; + arr[n] = NULL; } - oargv = argv; - parseargv(&argv, NOEXPORT); - if (*argv != NULL) - error("invalid MAKEFLAGS variable"); - free(oargv); + parseargv(arr, NULL, NOEXPORT); + free(arr); } } +static void +parsemakefiles(char **argv) +{ + char *s, *arg; + int c, hasmake; + + hasmake = 0; + for ( ; *argv && **argv == '-'; ++argv) { + for (s = *argv; c = *s; ++s) { + if (c == 'f' || c == 'j') + arg = getarg(&s, &argv); + + if (c == 'f') { + if (strcmp(arg, "-") == 0) + arg = NULL; + parse(arg); + hasmake = 1; + } + } + } + + if (hasmake) + return; + + if (parse("makefile")) + return; + if (parse("Makefile")) + return; +} + int main(int argc, char *argv[]) { + char *arg0; + signal(SIGINT, sighandler); signal(SIGHUP, sighandler); signal(SIGTERM, sighandler); signal(SIGQUIT, sighandler); + arg0 = *argv++; + inject(defaults); + parsemakefiles(argv); parsemakeflags(); - setmacro("MAKE", argv[0], NOEXPORT); - - ++argv; - parseargv(&argv, EXPORT); + parseargv(argv, &argv, EXPORT); - if (!hasmake) - parsedefault(); + setmacro("MAKE", arg0, NOEXPORT); if (pflag) { dumpmacros(); (DIR) diff --git a/tests/make/execute/0004-fflag.sh b/tests/make/execute/0004-fflag.sh @@ -5,7 +5,7 @@ trap 'rm -f $tmp1 $tmp2' EXIT INT QUIT HUP TERM tmp1=tmp1.$$ tmp2=tmp2.$$ -MAKEFLAGS=-ftest.mk scc-make print-cc print-makeflags > $tmp1 2>&1 +MAKEFLAGS=-fff.mk scc-make -f test.mk print-cc print-makeflags > $tmp1 2>&1 cat <<EOF > $tmp2 c99 (DIR) diff --git a/tests/make/execute/0005-fflag.sh b/tests/make/execute/0005-fflag.sh @@ -5,7 +5,7 @@ trap 'rm -f $tmp1 $tmp2' EXIT INT QUIT HUP TERM tmp1=tmp1.$$ tmp2=tmp2.$$ -MAKEFLAGS=ftest.mk scc-make print-cc print-makeflags > $tmp1 2>&1 +MAKEFLAGS=ffff.mk scc-make -f test.mk print-cc print-makeflags > $tmp1 2>&1 cat <<EOF > $tmp2 c99