scc

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

commit 27c9f34bbbbbd150afef63255816ca0c40f24d95
parent aff2954228ebe0e5bd04158caf3ea6bb5de26b7b
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:
Msrc/cmd/make/main.c | 110+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mtests/make/execute/0004-fflag.sh | 2+-
Mtests/make/execute/0005-fflag.sh | 2+-
3 files changed, 59 insertions(+), 55 deletions(-)

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(); 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 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