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}