main 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), 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#define IMPPATRULES_GNU \
 77	"%: %.o\n" \
 78	"\t$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
 79	"%: %.c\n" \
 80	"\t$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
 81	"%.o: %.c\n" \
 82	"\t$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<\n" \
 83	"%: %.cc\n" \
 84	"\t$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
 85	"%.o: %.cc\n" \
 86	"\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<\n" \
 87	"%: %.C\n" \
 88	"\t$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
 89	"%.o: %.C\n" \
 90	"\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<\n" \
 91	"%: %.cpp\n" \
 92	"\t$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
 93	"%.o: %.cpp\n" \
 94	"\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<\n" \
 95	"%: %.p\n" \
 96	"\t$(FC) $(FFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
 97	"%.o: %.p\n" \
 98	"\t$(FC) $(FFLAGS) -c -o $@ $<\n" \
 99	"%: %.f\n" \
100	"\t$(FC) $(FFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
101	"%.o: %.f\n" \
102	"\t$(FC) $(FFLAGS) -c -o $@ $<\n" \
103	"%: %.F\n" \
104	"\t$(FC) $(FFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
105	"%.o: %.F\n" \
106	"\t$(FC) $(CPPFLAGS) $(FFLAGS) -c -o $@ $<\n" \
107	"%.f: %.F\n" \
108	"\t$(FC) $(CPPFLAGS) $(FFLAGS) -o $@ -c $<\n" \
109	"%: %.m\n" \
110	"\t$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
111	"%.o: %.m\n" \
112	"\t$(OBJC) $(CPPFLAGS) $(OBJCFLAGS) -c -o $@ $<\n" \
113	"%: %.r\n" \
114	"\t$(FC) $(FFLAGS) $(RFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
115	"%.o: %.r\n" \
116	"\t$(FC) $(FFLAGS) $(RFLAGS) -c -o $@ $<\n" \
117	"%.f: %.r\n" \
118	"\t$(FC) $(FFLAGS) $(RFLAGS) -F $< > $@\n" \
119	"%: %.s\n" \
120	"\t$(AS) $(ASFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
121	"%.o: %.s\n" \
122	"\t$(AS) $(ASFLAGS) -o $@ $<\n" \
123	"%: %.S\n" \
124	"\t$(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@\n" \
125	"%.o: %.S\n" \
126	"\t$(CC) $(ASFLAGS) $(CPPFLAGS) -c -o $@ $<\n" \
127	"%.s: %.S\n" \
128	"\t$(CC) $(ASFLAGS) $(CPPFLAGS) -E $< > $@\n"
129
130static int
131loadimprules(struct SufRules *rules, const char *src)
132{
133	struct Ast ast;
134	size_t i;
135	int rc;
136
137	rc = parse("<built-in-rules>", src, &ast, MODE_GNU);
138	if (rc < 0)
139		return -1;
140	for (i = 0; i < ast.n; i++) {
141		struct Node *node = &ast.v[i];
142
143		if (node->kind != NODE_RULE)
144			continue;
145		if (issufrule(&node->data.rule)) {
146			addsufs(&rules->active, &node->data.rule.prereqs);
147			continue;
148		}
149		(void)collectsufrule(rules, &node->data.rule);
150	}
151	freeast(&ast);
152	return 0;
153}
154
155static int
156loadimppatrules(struct PatRules *rules, const char *src)
157{
158	struct Ast ast;
159	size_t i;
160	int rc;
161
162	rc = parse("<built-in-pattern-rules>", src, &ast, MODE_GNU);
163	if (rc < 0)
164		return -1;
165	for (i = 0; i < ast.n; i++) {
166		struct Node *node = &ast.v[i];
167
168		if (node->kind != NODE_RULE)
169			continue;
170		collectpat(rules, &node->data.rule, 1);
171	}
172	freeast(&ast);
173	return 0;
174}
175
176void
177seedenv(struct Env *env, int isposix, int envoverride, enum ShinMode mode)
178{
179	char *cwd;
180	size_t i;
181	static const struct DefaultVar posix[] = {
182		{"AR", "ar"},
183		{"ARFLAGS", "-rv"},
184		{"YACC", "yacc"},
185		{"YFLAGS", ""},
186		{"LEX", "lex"},
187		{"LFLAGS", ""},
188		{"LDFLAGS", ""},
189		/* even though posix specifies it like '-O 1', gcc and clang dont seem to like that*/
190		{"CFLAGS", "-O1"},
191		{0, 0},
192	};
193	static const struct DefaultVar posix2024[] = {
194		{"CC", "c17"},
195		{0, 0},
196	};
197	static const struct DefaultVar posix2008[] = {
198		{"MAKE", "make"},
199		{"CC", "c99"},
200		{"FC", "fort77"},
201		{"FFLAGS", "-O1"},
202		{0, 0},
203	};
204	static const struct DefaultVar gnu[] = {
205		{"CC", "cc"},
206		{"CFLAGS", ""},
207		{"CXX", "c++"},
208		{"CPP", "$(CC) -E"},
209		{"FC", "fort77"},
210		{"FFLAGS", ""},
211		{"AR", "ar"},
212		{"ARFLAGS", "-rv"},
213		{"RANLIB", "ranlib"},
214		{"AS", "as"},
215		{"GET", "get"},
216		{"GFLAGS", ""},
217		{"LD", "ld"},
218		{"LDFLAGS", ""},
219		{"LEX", "lex"},
220		{"LFLAGS", ""},
221		{"SCCSFLAGS", ""},
222		{"SCCSGETFLAGS", "-s"},
223		{"YACC", "yacc"},
224		{"YFLAGS", ""},
225		{"SHELL", "/bin/sh"},
226		{"MAKE", "make"},
227		/* we lie about being the latest version of gnu make. i think it's
228		 * kinda selfish they made this be MAKE_VERSION instead of GMAKE_VERSION,
229		 * what if bsd make wanted to add a similar one? */
230		{"MAKE_VERSION", "4.4.1"},
231		{"RM", "rm -f"},
232		{0, 0},
233	};
234
235	if (mode == MODE_POSIX_2024) {
236		seeddefaults(env, posix);
237		seeddefaults(env, posix2024);
238	} else if (mode == MODE_POSIX_2008 || isposix) {
239		seeddefaults(env, posix);
240		seeddefaults(env, posix2008);
241	} else {
242		seeddefaults(env, gnu);
243		cwd = getcwddup();
244		/*TODO: do this properly, this only expands at evaluation time,
245		 * unsure about behaviour under directory change condition or
246		 * in submakes. should work for most simple cases. */
247		envsetvar(env, "CURDIR", cwd, 1, ORIGIN_FILE, 0);
248	}
249	for (i = 0; environ && environ[i]; i++) {
250		const char *eq;
251		char *name;
252
253		eq = strchr(environ[i], '=');
254		if (!eq || eq == environ[i])
255			continue;
256		name = xstrndup(environ[i], (size_t)(eq - environ[i]));
257		if (mode == MODE_POSIX_2008 && strcmp(name, "CURDIR") == 0) {
258			free(name);
259			continue;
260		}
261		envsetvar(env, name, xstrdup(eq + 1), 1,
262		          envoverride ? ORIGIN_ENV_OVERRIDE : ORIGIN_ENV, 0);
263		free(name);
264	}
265}
266
267void
268imprules(struct SufRules *rules, int posix, enum ShinMode mode)
269{
270	const char *src;
271
272	if (mode == MODE_POSIX_2024)
273		src = IMPRULES_POSIX_2024;
274	else if (mode == MODE_POSIX_2008 || posix)
275		src = IMPRULES_POSIX_2008;
276	else
277		src = IMPRULES_GNU;
278	if (loadimprules(rules, src) < 0) {
279		fprintf(stderr, "failed to load built-in implicit rules\n");
280		exit(1);
281	}
282}
283
284int
285imppatrules(struct PatRules *rules, enum ShinMode mode)
286{
287	if (mode != MODE_GNU)
288		return 0;
289	return loadimppatrules(rules, IMPPATRULES_GNU);
290}