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}