commit 23c6f88

shrub  ·  2026-05-18 18:12:53 +0000 UTC
parent c74e668
move implcit rules and var seeding to a new file; make default vars more posix compliant
3 files changed,  +203, -150
+2, -1
 1@@ -13,7 +13,8 @@ SRCS =  cli/main.c \
 2 	src/eval/dollar.c \
 3 	src/graph/graph.c \
 4 	src/graph/subgraph.c \
 5-	src/posix.c \
 6+	src/sufrule.c \
 7+	src/defaults.c \
 8 	src/targets.c \
 9 	src/gnu/pattern.c \
10 	backends/ninja.c \
+201, -0
  1@@ -0,0 +1,201 @@
  2+#include "posix.h"
  3+
  4+#include <unistd.h>
  5+#include <stdio.h>
  6+#include <stdlib.h>
  7+#include <string.h>
  8+
  9+extern char **environ;
 10+
 11+struct DefaultVar {
 12+	const char *name;
 13+	const char *val;
 14+};
 15+
 16+static void
 17+seeddefaults(struct Env *env, const struct DefaultVar *vars)
 18+{
 19+	size_t i;
 20+
 21+	for (i = 0; vars[i].name; i++)
 22+		envsetvar(env, vars[i].name, xstrdup(vars[i].val), 1, ORIGIN_DEFAULT, 0);
 23+}
 24+
 25+/* rules shared by all dialects except the .c.o rule, which differs */
 26+#define IMPRULES_COMMON \
 27+	".c:\n" \
 28+	"\t$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<\n" \
 29+	".sh:\n" \
 30+	"\tcp $< $@\n" \
 31+	"\tchmod a+x $@\n" \
 32+	".y.o:\n" \
 33+	"\t$(YACC) $(YFLAGS) $<\n" \
 34+	"\t$(CC) $(CPPFLAGS) $(CFLAGS) -c y.tab.c\n" \
 35+	"\trm -f y.tab.c\n" \
 36+	"\tmv y.tab.o $@\n" \
 37+	".l.o:\n" \
 38+	"\t$(LEX) $(LFLAGS) $<\n" \
 39+	"\t$(CC) $(CPPFLAGS) $(CFLAGS) -c lex.yy.c\n" \
 40+	"\trm -f lex.yy.c\n" \
 41+	"\tmv lex.yy.o $@\n" \
 42+	".y.c:\n" \
 43+	"\t$(YACC) $(YFLAGS) $<\n" \
 44+	"\tmv y.tab.c $@\n" \
 45+	".l.c:\n" \
 46+	"\t$(LEX) $(LFLAGS) $<\n" \
 47+	"\tmv lex.yy.c $@\n"
 48+
 49+/* posix 2008 includes fortran; posix 2024 dropped it */
 50+#define IMPRULES_POSIX_2008 \
 51+	".SUFFIXES: .o .c .f .y .l .sh\n" \
 52+	IMPRULES_COMMON \
 53+	".f:\n" \
 54+	"\t$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $<\n" \
 55+	".c.o:\n" \
 56+	"\t$(CC) $(CFLAGS) -c $<\n" \
 57+	".f.o:\n" \
 58+	"\t$(FC) $(FFLAGS) -c $<\n"
 59+
 60+#define IMPRULES_POSIX_2024 \
 61+	".SUFFIXES: .o .c .y .l .sh\n" \
 62+	IMPRULES_COMMON \
 63+	".c.o:\n" \
 64+	"\t$(CC) $(CFLAGS) -c $<\n"
 65+
 66+#define IMPRULES_GNU \
 67+	".SUFFIXES: .o .c .f .y .l .sh\n" \
 68+	IMPRULES_COMMON \
 69+	".f:\n" \
 70+	"\t$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $<\n" \
 71+	".c.o:\n" \
 72+	"\t$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<\n" \
 73+	".f.o:\n" \
 74+	"\t$(FC) $(FFLAGS) -c -o $@ $<\n"
 75+
 76+static int
 77+loadimprules(struct SufRules *rules, const char *src)
 78+{
 79+	struct Ast ast;
 80+	size_t i;
 81+	int rc;
 82+
 83+	rc = parse("<built-in-rules>", src, &ast);
 84+	if (rc < 0)
 85+		return -1;
 86+	for (i = 0; i < ast.n; i++) {
 87+		struct Node *node = &ast.v[i];
 88+
 89+		if (node->kind != NODE_RULE)
 90+			continue;
 91+		if (issufrule(&node->data.rule)) {
 92+			addsufs(&rules->active, &node->data.rule.prereqs);
 93+			continue;
 94+		}
 95+		(void)collectsufrule(rules, &node->data.rule);
 96+	}
 97+	freeast(&ast);
 98+	return 0;
 99+}
100+
101+void
102+seedenv(struct Env *env, int isposix, int envoverride, enum ShinMode mode)
103+{
104+	char *cwd;
105+	size_t i;
106+	static const struct DefaultVar posix[] = {
107+		{"AR", "ar"},
108+		{"ARFLAGS", "-rv"},
109+		{"YACC", "yacc"},
110+		{"YFLAGS", ""},
111+		{"LEX", "lex"},
112+		{"LFLAGS", ""},
113+		{"LDFLAGS", ""},
114+		{"CFLAGS", "-O 1"},
115+		{0, 0},
116+	};
117+	static const struct DefaultVar posix2024[] = {
118+		{"CC", "c17"},
119+		{0, 0},
120+	};
121+	static const struct DefaultVar posix2008[] = {
122+		{"MAKE", "make"},
123+		{"CC", "c99"},
124+		{"FC", "fort77"},
125+		{"FFLAGS", "-O 1"},
126+		{0, 0},
127+	};
128+	static const struct DefaultVar gnu[] = {
129+		{"CC", "cc"},
130+		{"CFLAGS", ""},
131+		{"CXX", "c++"},
132+		{"CPP", "$(CC) -E"},
133+		{"FC", "fort77"},
134+		{"FFLAGS", ""},
135+		{"AR", "ar"},
136+		{"ARFLAGS", "-rv"},
137+		{"RANLIB", "ranlib"},
138+		{"AS", "as"},
139+		{"GET", "get"},
140+		{"GFLAGS", ""},
141+		{"LD", "ld"},
142+		{"LDFLAGS", ""},
143+		{"LEX", "lex"},
144+		{"LFLAGS", ""},
145+		{"SCCSFLAGS", ""},
146+		{"SCCSGETFLAGS", "-s"},
147+		{"YACC", "yacc"},
148+		{"YFLAGS", ""},
149+		{"SHELL", "/bin/sh"},
150+		{"MAKE", "make"},
151+		/* we lie about being the latest version of gnu make. i think it's
152+		 * kinda selfish they made this be MAKE_VERSION instead of GMAKE_VERSION,
153+		 * what if bsd make wanted to add a similar one? */
154+		{"MAKE_VERSION", "4.4.1"},
155+		{"RM", "rm -f"},
156+		{0, 0},
157+	};
158+
159+	if (mode == MODE_POSIX_2024) {
160+		seeddefaults(env, posix);
161+		seeddefaults(env, posix2024);
162+	} else if (mode == MODE_POSIX_2008 || isposix) {
163+		seeddefaults(env, posix);
164+		seeddefaults(env, posix2008);
165+	} else {
166+		seeddefaults(env, gnu);
167+		cwd = getcwddup();
168+		/*TODO: do this properly, this only expands at evaluation time,
169+		 * unsure about behaviour under directory change condition or
170+		 * in submakes. should work for most simple cases. */
171+		envsetvar(env, "CURDIR", cwd, 1, ORIGIN_FILE, 0);
172+	}
173+	for (i = 0; environ && environ[i]; i++) {
174+		const char *eq;
175+		char *name;
176+
177+		eq = strchr(environ[i], '=');
178+		if (!eq || eq == environ[i])
179+			continue;
180+		name = xstrndup(environ[i], (size_t)(eq - environ[i]));
181+		envsetvar(env, name, xstrdup(eq + 1), 1,
182+		          envoverride ? ORIGIN_ENV_OVERRIDE : ORIGIN_ENV, 0);
183+		free(name);
184+	}
185+}
186+
187+void
188+imprules(struct SufRules *rules, int posix, enum ShinMode mode)
189+{
190+	const char *src;
191+
192+	if (mode == MODE_POSIX_2024)
193+		src = IMPRULES_POSIX_2024;
194+	else if (mode == MODE_POSIX_2008 || posix)
195+		src = IMPRULES_POSIX_2008;
196+	else
197+		src = IMPRULES_GNU;
198+	if (loadimprules(rules, src) < 0) {
199+		fprintf(stderr, "failed to load built-in implicit rules\n");
200+		exit(1);
201+	}
202+}
R src/posix.c => src/sufrule.c
+0, -149
  1@@ -215,155 +215,6 @@ expandauto(const char *s, const struct Target *t, const char *stem)
  2 	return out;
  3 }
  4 
  5-/* rules shared by all dialects except the .c.o rule, which differs */
  6-#define IMPRULES_COMMON \
  7-	".c:\n" \
  8-	"\t$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<\n" \
  9-	".sh:\n" \
 10-	"\tcp $< $@\n" \
 11-	"\tchmod a+x $@\n" \
 12-	".y.o:\n" \
 13-	"\t$(YACC) $(YFLAGS) $<\n" \
 14-	"\t$(CC) $(CPPFLAGS) $(CFLAGS) -c y.tab.c\n" \
 15-	"\trm -f y.tab.c\n" \
 16-	"\tmv y.tab.o $@\n" \
 17-	".l.o:\n" \
 18-	"\t$(LEX) $(LFLAGS) $<\n" \
 19-	"\t$(CC) $(CPPFLAGS) $(CFLAGS) -c lex.yy.c\n" \
 20-	"\trm -f lex.yy.c\n" \
 21-	"\tmv lex.yy.o $@\n" \
 22-	".y.c:\n" \
 23-	"\t$(YACC) $(YFLAGS) $<\n" \
 24-	"\tmv y.tab.c $@\n" \
 25-	".l.c:\n" \
 26-	"\t$(LEX) $(LFLAGS) $<\n" \
 27-	"\tmv lex.yy.c $@\n"
 28-
 29-/* posix 2008 includes fortran; posix 2024 dropped it */
 30-#define IMPRULES_POSIX_2008 \
 31-	".SUFFIXES: .o .c .f .y .l .sh\n" \
 32-	IMPRULES_COMMON \
 33-	".f:\n" \
 34-	"\t$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $<\n" \
 35-	".c.o:\n" \
 36-	"\t$(CC) $(CFLAGS) -c $<\n" \
 37-	".f.o:\n" \
 38-	"\t$(FC) $(FFLAGS) -c $<\n"
 39-
 40-#define IMPRULES_POSIX_2024 \
 41-	".SUFFIXES: .o .c .y .l .sh\n" \
 42-	IMPRULES_COMMON \
 43-	".c.o:\n" \
 44-	"\t$(CC) $(CFLAGS) -c $<\n"
 45-
 46-#define IMPRULES_GNU \
 47-	".SUFFIXES: .o .c .f .y .l .sh\n" \
 48-	IMPRULES_COMMON \
 49-	".f:\n" \
 50-	"\t$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $<\n" \
 51-	".c.o:\n" \
 52-	"\t$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<\n" \
 53-	".f.o:\n" \
 54-	"\t$(FC) $(FFLAGS) -c -o $@ $<\n"
 55-
 56-static int
 57-loadimprules(struct SufRules *rules, const char *src)
 58-{
 59-	struct Ast ast;
 60-	size_t i;
 61-	int rc;
 62-
 63-	rc = parse("<built-in-rules>", src, &ast);
 64-	if (rc < 0)
 65-		return -1;
 66-	for (i = 0; i < ast.n; i++) {
 67-		struct Node *node = &ast.v[i];
 68-
 69-		if (node->kind != NODE_RULE)
 70-			continue;
 71-		if (issufrule(&node->data.rule)) {
 72-			addsufs(&rules->active, &node->data.rule.prereqs);
 73-			continue;
 74-		}
 75-		(void)collectsufrule(rules, &node->data.rule);
 76-	}
 77-	freeast(&ast);
 78-	return 0;
 79-}
 80-
 81-void
 82-seedenv(struct Env *env, int posix, int envoverride, enum ShinMode mode)
 83-{
 84-	char *cwd;
 85-	size_t i;
 86-
 87-	envsetvar(env, "CC", xstrdup("cc"), 1, ORIGIN_DEFAULT, 0);
 88-	envsetvar(env, "CFLAGS", xstrdup(""), 1, ORIGIN_DEFAULT, 0);
 89-	envsetvar(env, "CXX", xstrdup("c++"), 1, ORIGIN_DEFAULT, 0);
 90-	envsetvar(env, "CPP", xstrdup("$(CC) -E"), 0, ORIGIN_DEFAULT, 0);
 91-	envsetvar(env, "FC", xstrdup("fort77"), 1, ORIGIN_DEFAULT, 0);
 92-	envsetvar(env, "FFLAGS", xstrdup(""), 1, ORIGIN_DEFAULT, 0);
 93-	envsetvar(env, "AR", xstrdup("ar"), 1, ORIGIN_DEFAULT, 0);
 94-	envsetvar(env, "ARFLAGS", xstrdup("-rv"), 1, ORIGIN_DEFAULT, 0);
 95-	envsetvar(env, "RANLIB", xstrdup("ranlib"), 1, ORIGIN_DEFAULT, 0);
 96-	envsetvar(env, "AS", xstrdup("as"), 1, ORIGIN_DEFAULT, 0);
 97-	envsetvar(env, "GET", xstrdup("get"), 1, ORIGIN_DEFAULT, 0);
 98-	envsetvar(env, "GFLAGS", xstrdup(""), 1, ORIGIN_DEFAULT, 0);
 99-	envsetvar(env, "LD", xstrdup("ld"), 1, ORIGIN_DEFAULT, 0);
100-	envsetvar(env, "LDFLAGS", xstrdup(""), 1, ORIGIN_DEFAULT, 0);
101-	envsetvar(env, "LEX", xstrdup("lex"), 1, ORIGIN_DEFAULT, 0);
102-	envsetvar(env, "LFLAGS", xstrdup(""), 1, ORIGIN_DEFAULT, 0);
103-	envsetvar(env, "SCCSFLAGS", xstrdup(""), 1, ORIGIN_DEFAULT, 0);
104-	envsetvar(env, "SCCSGETFLAGS", xstrdup("-s"), 1, ORIGIN_DEFAULT, 0);
105-	envsetvar(env, "YACC", xstrdup("yacc"), 1, ORIGIN_DEFAULT, 0);
106-	envsetvar(env, "YFLAGS", xstrdup(""), 1, ORIGIN_DEFAULT, 0);
107-	envsetvar(env, "SHELL", xstrdup("/bin/sh"), 1, ORIGIN_DEFAULT, 0);
108-	envsetvar(env, "MAKE", xstrdup("make"), 1, ORIGIN_DEFAULT, 0);
109-	envsetvar(env, "RM", xstrdup("rm -f"), 1, ORIGIN_DEFAULT, 0);
110-	cwd = getcwddup();
111-	/*TODO: do this properly, this only expands at evaluation time,
112-	 * unsure about behaviour under directory change condition or 
113-	 * in submakes. should work for most simple cases. */
114-	envsetvar(env, "CURDIR", cwd, 1, ORIGIN_FILE, 0);
115-	if (posix || mode != MODE_GNU) {
116-		const char *cc = "c99";
117-
118-		if (mode == MODE_POSIX_2024)
119-			cc = "c17";
120-		envsetvar(env, "CC", xstrdup(cc), 1, ORIGIN_DEFAULT, 0);
121-		envsetvar(env, "CFLAGS", xstrdup("-O1"), 1, ORIGIN_DEFAULT, 0);
122-		envsetvar(env, "FFLAGS", xstrdup("-O1"), 1, ORIGIN_DEFAULT, 0);
123-	}
124-	for (i = 0; environ && environ[i]; i++) {
125-		const char *eq;
126-		char *name;
127-
128-		eq = strchr(environ[i], '=');
129-		if (!eq || eq == environ[i])
130-			continue;
131-		name = xstrndup(environ[i], (size_t)(eq - environ[i]));
132-		envsetvar(env, name, xstrdup(eq + 1), 1,
133-		          envoverride ? ORIGIN_ENV_OVERRIDE : ORIGIN_ENV, 0);
134-		free(name);
135-	}
136-}
137-
138-void
139-imprules(struct SufRules *rules, int posix, enum ShinMode mode)
140-{
141-	const char *src;
142-
143-	if (mode == MODE_POSIX_2024)
144-		src = IMPRULES_POSIX_2024;
145-	else if (mode == MODE_POSIX_2008 || posix)
146-		src = IMPRULES_POSIX_2008;
147-	else
148-		src = IMPRULES_GNU;
149-	if (loadimprules(rules, src) < 0) {
150-		fprintf(stderr, "failed to load built-in implicit rules\n");
151-		exit(1);
152-	}
153-}
154 
155 int
156 issufrule(const struct RuleNode *rule)