main shrub/shinobi / src / defaults.c
  1#include "posix.h"
  2#include "gnu/pattern.h"
  3
  4#include <unistd.h>
  5#include <stdio.h>
  6#include <stdlib.h>
  7#include <string.h>
  8
  9extern char **environ;
 10
 11struct DefaultVar {
 12	const char *name;
 13	const char *val;
 14};
 15
 16static void
 17seeddefaults(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), 0, ORIGIN_DEFAULT, 0);
 23}
 24
 25/* posix default inference rules in both 08 and 24 */
 26#define IMPRULES_POSIX_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_POSIX_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_POSIX_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	".c:\n" \
 69	"\t$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
 70	".sh:\n" \
 71	"\tcp $< $@\n" \
 72	"\tchmod a+x $@\n" \
 73	".y.o:\n" \
 74	"\t$(YACC.y) $<\n" \
 75	"\t$(COMPILE.c) y.tab.c\n" \
 76	"\trm -f y.tab.c\n" \
 77	"\tmv y.tab.o $@\n" \
 78	".l.o:\n" \
 79	"\t$(LEX.l) $<\n" \
 80	"\t$(COMPILE.c) lex.yy.c\n" \
 81	"\trm -f lex.yy.c\n" \
 82	"\tmv lex.yy.o $@\n" \
 83	".y.c:\n" \
 84	"\t$(YACC.y) $<\n" \
 85	"\tmv y.tab.c $@\n" \
 86	".l.c:\n" \
 87	"\t$(LEX.l) $< > $@\n" \
 88	".f:\n" \
 89	"\t$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
 90	".c.o:\n" \
 91	"\t$(COMPILE.c) $(OUTPUT_OPTION) $<\n" \
 92	".f.o:\n" \
 93	"\t$(COMPILE.f) $(OUTPUT_OPTION) $<\n"
 94
 95#define IMPPATRULES_GNU \
 96	"%: %.o\n" \
 97	"\t$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
 98	"%: %.c\n" \
 99	"\t$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
100	"%.o: %.c\n" \
101	"\t$(COMPILE.c) $(OUTPUT_OPTION) $<\n" \
102	"%: %.cc\n" \
103	"\t$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
104	"%.o: %.cc\n" \
105	"\t$(COMPILE.cc) $(OUTPUT_OPTION) $<\n" \
106	"%: %.C\n" \
107	"\t$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
108	"%.o: %.C\n" \
109	"\t$(COMPILE.C) $(OUTPUT_OPTION) $<\n" \
110	"%: %.cpp\n" \
111	"\t$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
112	"%.o: %.cpp\n" \
113	"\t$(COMPILE.cpp) $(OUTPUT_OPTION) $<\n" \
114	"%: %.p\n" \
115	"\t$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
116	"%.o: %.p\n" \
117	"\t$(COMPILE.p) $(OUTPUT_OPTION) $<\n" \
118	"%: %.f\n" \
119	"\t$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
120	"%.o: %.f\n" \
121	"\t$(COMPILE.f) $(OUTPUT_OPTION) $<\n" \
122	"%: %.F\n" \
123	"\t$(LINK.F) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
124	"%.o: %.F\n" \
125	"\t$(COMPILE.F) $(OUTPUT_OPTION) $<\n" \
126	"%.f: %.F\n" \
127	"\t$(PREPROCESS.F) $(OUTPUT_OPTION) $<\n" \
128	"%: %.m\n" \
129	"\t$(LINK.m) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
130	"%.o: %.m\n" \
131	"\t$(COMPILE.m) $(OUTPUT_OPTION) $<\n" \
132	"%: %.r\n" \
133	"\t$(LINK.r) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
134	"%.o: %.r\n" \
135	"\t$(COMPILE.r) $(OUTPUT_OPTION) $<\n" \
136	"%.f: %.r\n" \
137	"\t$(PREPROCESS.r) $(OUTPUT_OPTION) $<\n" \
138	"%: %.s\n" \
139	"\t$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
140	"%.o: %.s\n" \
141	"\t$(COMPILE.s) -o $@ $<\n" \
142	"%: %.S\n" \
143	"\t$(LINK.S) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
144	"%.o: %.S\n" \
145	"\t$(COMPILE.S) -o $@ $<\n" \
146	"%.s: %.S\n" \
147	"\t$(PREPROCESS.S) $< > $@\n"
148
149static int
150loadimprules(struct SufRules *rules, const char *src)
151{
152	struct Ast ast;
153	size_t i;
154	int rc;
155
156	rc = parse("<built-in-rules>", src, &ast, MODE_GNU);
157	if (rc < 0)
158		return -1;
159	for (i = 0; i < ast.n; i++) {
160		struct Node *node = &ast.v[i];
161
162		if (node->kind != NODE_RULE)
163			continue;
164		if (issufrule(&node->data.rule)) {
165			addsufs(&rules->active, &node->data.rule.prereqs);
166			continue;
167		}
168		(void)collectsufrule(rules, &node->data.rule, 1);
169	}
170	freeast(&ast);
171	return 0;
172}
173
174static int
175loadimppatrules(struct PatRules *rules, const char *src)
176{
177	struct Ast ast;
178	size_t i;
179	int rc;
180
181	rc = parse("<built-in-pattern-rules>", src, &ast, MODE_GNU);
182	if (rc < 0)
183		return -1;
184	for (i = 0; i < ast.n; i++) {
185		struct Node *node = &ast.v[i];
186
187		if (node->kind != NODE_RULE)
188			continue;
189		collectpat(rules, &node->data.rule, 1);
190	}
191	freeast(&ast);
192	return 0;
193}
194
195void
196seedenv(struct Env *env, int isposix, int envoverride, enum ShinMode mode)
197{
198	char *cwd;
199	size_t i;
200	static const struct DefaultVar posix[] = {
201		{"AR", "ar"},
202		{"ARFLAGS", "-rv"},
203		{"YACC", "yacc"},
204		{"YFLAGS", ""},
205		{"LEX", "lex"},
206		{"LFLAGS", ""},
207		{"LDFLAGS", ""},
208		/* even though posix specifies it like '-O 1', gcc and clang dont seem to like that*/
209		{"CFLAGS", "-O1"},
210		{0, 0},
211	};
212	static const struct DefaultVar posix2024[] = {
213		{"CC", "c17"},
214		{0, 0},
215	};
216	static const struct DefaultVar posix2008[] = {
217		{"MAKE", "make"},
218		{"CC", "c99"},
219		{"FC", "fort77"},
220		{"FFLAGS", "-O1"},
221		{0, 0},
222	};
223	static const struct DefaultVar gnu[] = {
224		{"CC", "cc"},
225		{"CFLAGS", ""},
226		{"CXX", "c++"},
227		{"CPP", "$(CC) -E"},
228		{"FC", "fort77"},
229		{"FFLAGS", ""},
230		{"PC", "pc"},
231		{"OBJC", "cc"},
232		{"AR", "ar"},
233		{"ARFLAGS", "-rv"},
234		{"RANLIB", "ranlib"},
235		{"AS", "as"},
236		{"GET", "get"},
237		{"GFLAGS", ""},
238		{"LD", "ld"},
239		{"LDFLAGS", ""},
240		{"OUTPUT_OPTION", "-o $@"},
241		{"COMPILE.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c"},
242		{"LINK.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)"},
243		{"COMPILE.cc", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c"},
244		{"LINK.cc", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)"},
245		{"COMPILE.C", "$(COMPILE.cc)"},
246		{"LINK.C", "$(LINK.cc)"},
247		{"COMPILE.cpp", "$(COMPILE.cc)"},
248		{"LINK.cpp", "$(LINK.cc)"},
249		{"COMPILE.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c"},
250		{"LINK.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)"},
251		{"COMPILE.f", "$(FC) $(FFLAGS) $(TARGET_ARCH) -c"},
252		{"LINK.f", "$(FC) $(FFLAGS) $(LDFLAGS) $(TARGET_ARCH)"},
253		{"COMPILE.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c"},
254		{"LINK.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)"},
255		{"PREPROCESS.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -F"},
256		{"COMPILE.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c"},
257		{"LINK.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)"},
258		{"COMPILE.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -c"},
259		{"LINK.r", "$(FC) $(FFLAGS) $(RFLAGS) $(LDFLAGS) $(TARGET_ARCH)"},
260		{"PREPROCESS.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F"},
261		{"COMPILE.s", "$(AS) $(ASFLAGS) $(TARGET_MACH)"},
262		{"LINK.s", "$(CC) $(ASFLAGS) $(LDFLAGS) $(TARGET_MACH)"},
263		{"COMPILE.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c"},
264		{"LINK.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)"},
265		{"PREPROCESS.S", "$(CPP) $(CPPFLAGS)"},
266		{"LINK.o", "$(CC) $(LDFLAGS) $(TARGET_ARCH)"},
267		{"LEX.l", "$(LEX) $(LFLAGS) -t"},
268		{"YACC.y", "$(YACC) $(YFLAGS)"},
269		{"LEX", "lex"},
270		{"LFLAGS", ""},
271		{"SCCSFLAGS", ""},
272		{"SCCSGETFLAGS", "-s"},
273		{"YACC", "yacc"},
274		{"YFLAGS", ""},
275		{"SHELL", "/bin/sh"},
276		{"MAKE", "make"},
277		/* we lie about being the latest version of gnu make. i think it's
278		 * kinda selfish they made this be MAKE_VERSION instead of GMAKE_VERSION,
279		 * what if bsd make wanted to add a similar one? */
280		{"MAKE_VERSION", "4.4.1"},
281		{"RM", "rm -f"},
282		{0, 0},
283	};
284
285	if (mode == MODE_POSIX_2024) {
286		seeddefaults(env, posix);
287		seeddefaults(env, posix2024);
288	} else if (mode == MODE_POSIX_2008) {
289		seeddefaults(env, posix);
290		seeddefaults(env, posix2008);
291	} else {
292		seeddefaults(env, gnu);
293		if (isposix) {
294			/* GNU make keeps the whole gnu variable set under .POSIX
295			 * then replaces only defaults for variables specifically specified
296			 * by posix */
297			seeddefaults(env, posix);
298			seeddefaults(env, posix2008);
299		}
300		cwd = getcwddup();
301		/*TODO: do this properly, this only expands at evaluation time,
302		 * unsure about behaviour under directory change condition or
303		 * in submakes. should work for most simple cases. */
304		envsetvar(env, "CURDIR", cwd, 1, ORIGIN_FILE, 0);
305	}
306	for (i = 0; environ && environ[i]; i++) {
307		const char *eq;
308		char *name;
309
310		eq = strchr(environ[i], '=');
311		if (!eq || eq == environ[i])
312			continue;
313		name = xstrndup(environ[i], (size_t)(eq - environ[i]));
314		if (mode == MODE_POSIX_2008 && strcmp(name, "CURDIR") == 0) {
315			free(name);
316			continue;
317		}
318		envsetvar(env, name, xstrdup(eq + 1), 1,
319		          envoverride ? ORIGIN_ENV_OVERRIDE : ORIGIN_ENV, 0);
320		free(name);
321	}
322}
323
324void
325imprules(struct SufRules *rules, enum ShinMode mode)
326{
327	const char *src;
328
329	if (mode == MODE_POSIX_2024)
330		src = IMPRULES_POSIX_2024;
331	else if (mode == MODE_POSIX_2008)
332		src = IMPRULES_POSIX_2008;
333	else
334		src = IMPRULES_GNU;
335	if (loadimprules(rules, src) < 0) {
336		fprintf(stderr, "failed to load built-in implicit rules\n");
337		exit(1);
338	}
339}
340
341int
342imppatrules(struct PatRules *rules, enum ShinMode mode)
343{
344	if (mode != MODE_GNU)
345		return 0;
346	return loadimppatrules(rules, IMPPATRULES_GNU);
347}