xref: /plan9/sys/src/ape/cmd/cc.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
1 #include <u.h>
2 #include <libc.h>
3 
4 /*
5    POSIX standard c89
6 
7    standard options: -c, -D name[=val], -E (preprocess to stdout),
8        -g, -L dir, -o outfile, -O, -s, -U name
9        (and operands can have -l lib interspersed)
10 
11     nonstandard but specified options: -S (assembly language left in .s),
12        -Wx,arg1[,arg2...] (pass arg(s) to phase x, where x is p (cpp)
13    			 0 (compiler), or l (loader)
14     nonstandard options: -v (echo real commands to stdout as they execute)
15 	-A: turn on ANSI prototype warnings
16  */
17 
18 typedef struct Objtype {
19 	char	*name;
20 	char	*cc;
21 	char	*ld;
22 	char	*o;
23 } Objtype;
24 
25 Objtype objtype[] = {
26 	{"386",		"8c", "8l", "8"},
27 	{"68020",	"2c", "2l", "2"},
28 	{"alpha",	"7c", "7l", "7"},
29 	{"mips",	"vc", "vl", "v"},
30 	{"arm",	"5c", "5l", "5"},
31 	{"mips2",	"4c", "4l", "4"},
32 	{"power",	"qc", "ql", "q"},
33 	{"sparc",	"kc", "kl", "k"},
34 };
35 
36 enum {
37 	Nobjs = (sizeof objtype)/(sizeof objtype[0]),
38 	Maxlist = 2000,
39 };
40 
41 typedef struct List {
42 	char	*strings[Maxlist];
43 	int	n;
44 } List;
45 
46 List	srcs, objs, cpp, cc, ld, ldargs, srchlibs;
47 int	cflag, vflag, Eflag, Sflag, Aflag;
48 char	*allos = "2478kqv";
49 
50 void	append(List *, char *);
51 char	*changeext(char *, char *);
52 void	doexec(char *, List *);
53 void	dopipe(char *, List *, char *, List *);
54 void	fatal(char *);
55 Objtype	*findoty(void);
56 void	printlist(List *);
57 char *searchlib(char *, char*);
58 
59 void
60 main(int argc, char *argv[])
61 {
62 	char *s, *suf, *ccpath, *lib;
63 	char *oname;
64 	int haveoname = 0;
65 	int i, cppn, ccn;
66 	Objtype *ot;
67 
68 	ot = findoty();
69 	oname = "a.out";
70 	append(&cpp, "cpp");
71 	append(&cpp, "-D__STDC__=1");	/* ANSI says so */
72 	append(&cpp, "-D_POSIX_SOURCE=");
73 	append(&cpp, "-N");		/* turn off standard includes */
74 	append(&cc, ot->cc);
75 	append(&ld, ot->ld);
76 	append(&srchlibs, smprint("/%s/lib/ape", ot->name));
77 	while(argc > 0) {
78 		ARGBEGIN {
79 		case 'c':
80 			cflag = 1;
81 			break;
82 		case 'l':
83 			lib = searchlib(ARGF(), ot->name);
84 			if(!lib)
85 				fprint(2, "cc: can't find library for -l\n");
86 			else
87 				append(&objs, lib);
88 			break;
89 		case 'o':
90 			oname = ARGF();
91 			haveoname = 1;
92 			if(!oname)
93 				fatal("cc: no -o argument");
94 			break;
95 		case 'D':
96 		case 'I':
97 		case 'U':
98 			append(&cpp, smprint("-%c%s", ARGC(), ARGF()));
99 			break;
100 		case 'E':
101 			Eflag = 1;
102 			cflag = 1;
103 			break;
104 		case 's':
105 		case 'g':
106 			break;
107 		case 'L':
108 			lib = ARGF();
109 			if(!lib)
110 				fprint(2, "cc: no -L argument\n");
111 			else
112 				append(&srchlibs, lib);
113 			break;
114 		case 'N':
115 			append(&cc, "-N");
116 			break;
117 		case 'O':
118 			break;
119 		case 'W':
120 			s = ARGF();
121 			if(s && s[1]==',') {
122 				switch (s[0]) {
123 				case 'p':
124 					append(&cpp, s+2);
125 					break;
126 				case '0':
127 					append(&cc, s+2);
128 					break;
129 				case 'l':
130 					append(&ldargs, s+2);
131 					break;
132 				default:
133 					fprint(2, "cc: pass letter after -W should be one of p0l; ignored\n");
134 				}
135 			} else
136 				fprint(2, "cc: bad option after -W; ignored\n");
137 			break;
138 		case 'v':
139 			vflag = 1;
140 			append(&ldargs, "-v");
141 			break;
142 		case 'w':
143 			append(&cc, "-w");
144 			break;
145 		case 'A':
146 			Aflag = 1;
147 			break;
148 		case 'S':
149 			Sflag = 1;
150 			break;
151 		default:
152 			fprint(2, "cc: flag -%c ignored\n", ARGC());
153 			break;
154 		} ARGEND
155 		if(!Aflag) {
156 			append(&cc, "-J");		/* old/new decl mixture hack */
157 			append(&cc, "-B");		/* turn off non-prototype warnings */
158 		}
159 		if(argc > 0) {
160 			s = argv[0];
161 			suf = utfrrune(s, '.');
162 			if(suf) {
163 				suf++;
164 				if(strcmp(suf, "c") == 0) {
165 					append(&srcs, s);
166 					append(&objs, changeext(s, "o"));
167 				} else if(strcmp(suf, "o") == 0 ||
168 					  strcmp(suf, ot->o) == 0 ||
169 					  strcmp(suf, "a") == 0 ||
170 					  (suf[0] == 'a' && strcmp(suf+1, ot->o) == 0)) {
171 					append(&objs, s);
172 				} else if(utfrune(allos, suf[0]) != 0) {
173 					fprint(2, "cc: argument %s ignored: wrong architecture\n",
174 						s);
175 				}
176 			}
177 		}
178 	}
179 	if(objs.n == 0)
180 		fatal("no files to compile or load");
181 	ccpath = smprint("/bin/%s", ot->cc);
182 	append(&cpp, smprint("-I/%s/include/ape", ot->name));
183 	append(&cpp, "-I/sys/include/ape");
184 	cppn = cpp.n;
185 	ccn = cc.n;
186 	for(i = 0; i < srcs.n; i++) {
187 		append(&cpp, srcs.strings[i]);
188 		if(Eflag)
189 			doexec("/bin/cpp", &cpp);
190 		else {
191 			if(Sflag)
192 				append(&cc, "-S");
193 			else {
194 				append(&cc, "-o");
195 				if (haveoname && cflag)
196 					append(&cc, oname);
197 				else
198 					append(&cc, changeext(srcs.strings[i], "o"));
199 			}
200 			dopipe("/bin/cpp", &cpp, ccpath, &cc);
201 		}
202 		cpp.n = cppn;
203 		cc.n = ccn;
204 	}
205 	if(!cflag) {
206 		append(&ld, "-o");
207 		append(&ld, oname);
208 		for(i = 0; i < ldargs.n; i++)
209 			append(&ld, ldargs.strings[i]);
210 		for(i = 0; i < objs.n; i++)
211 			append(&ld, objs.strings[i]);
212 		append(&ld, smprint("/%s/lib/ape/libap.a", ot->name));
213 		doexec(smprint("/bin/%s", ot->ld), &ld);
214 		if(objs.n == 1)
215 			remove(objs.strings[0]);
216 	}
217 
218 	exits(0);
219 }
220 
221 char *
222 searchlib(char *s, char *objtype)
223 {
224 	char *l;
225 	int i;
226 
227 	if(!s)
228 		return 0;
229 	for(i = srchlibs.n-1; i>=0; i--) {
230 		l = smprint("%s/lib%s.a", srchlibs.strings[i], s);
231 		if(access(l, 0) >= 0)
232 			return l;
233 	}
234 	if(s[1] == 0)
235 		switch(s[0]) {
236 		case 'c':
237 			l = smprint("/%s/lib/ape/libap.a", objtype);
238 			break;
239 		case 'm':
240 			l = smprint("/%s/lib/ape/libap.a", objtype);
241 			break;
242 		case 'l':
243 			l = smprint("/%s/lib/ape/libl.a", objtype);
244 			break;
245 		case 'y':
246 			l = smprint("/%s/lib/ape/liby.a", objtype);
247 			break;
248 		default:
249 			l = 0;
250 		}
251 	else
252 		l = 0;
253 	return l;
254 }
255 
256 void
257 append(List *l, char *s)
258 {
259 	if(l->n >= Maxlist-1)
260 		fatal("too many arguments");
261 	l->strings[l->n++] = s;
262 	l->strings[l->n] = 0;
263 }
264 
265 void
266 doexec(char *c, List *a)
267 {
268 	Waitmsg *w;
269 
270 	if(vflag) {
271 		printlist(a);
272 		fprint(2, "\n");
273 	}
274 	switch(fork()) {
275 	case -1:
276 		fatal("fork failed");
277 	case 0:
278 		exec(c, a->strings);
279 		fatal("exec failed");
280 	}
281 	if((w = wait()) == nil)
282 		fatal("wait failed");
283 	if(w->msg[0])
284 		fatal(smprint("%s: %s", a->strings[0], w->msg));
285 	free(w);
286 }
287 
288 void
289 dopipe(char *c1, List *a1, char *c2, List *a2)
290 {
291 	Waitmsg *w;
292 	int pid1, got;
293 	int fd[2];
294 
295 	if(vflag) {
296 		printlist(a1);
297 		fprint(2, " | ");
298 		printlist(a2);
299 		fprint(2, "\n");
300 	}
301 	if(pipe(fd) < 0)
302 		fatal("pipe failed");
303 	switch((pid1 = fork())) {
304 	case -1:
305 		fatal("fork failed");
306 	case 0:
307 		dup(fd[0], 0);
308 		close(fd[0]);
309 		close(fd[1]);
310 		exec(c2, a2->strings);
311 		fatal("exec failed");
312 	}
313 	switch(fork()) {
314 	case -1:
315 		fatal("fork failed");
316 	case 0:
317 		close(0);
318 		dup(fd[1], 1);
319 		close(fd[0]);
320 		close(fd[1]);
321 		exec(c1, a1->strings);
322 		fatal("exec failed");
323 	}
324 	close(fd[0]);
325 	close(fd[1]);
326 	for(got = 0; got < 2; got++) {
327 		if((w = wait()) == nil)
328 			fatal("wait failed");
329 		if(w->msg[0])
330 			fatal(smprint("%s: %s", (w->pid == pid1) ? a1->strings[0] : a2->strings[0], w->msg));
331 		free(w);
332 	}
333 }
334 
335 Objtype *
336 findoty(void)
337 {
338 	char *o;
339 	Objtype *oty;
340 
341 	o = getenv("objtype");
342 	if(!o)
343 		fatal("no $objtype in environment");
344 	for(oty = objtype; oty < &objtype[Nobjs]; oty++)
345 		if(strcmp(o, oty->name) == 0)
346 			return oty;
347 	fatal("unknown $objtype");
348 	return 0;			/* shut compiler up */
349 }
350 
351 void
352 fatal(char *msg)
353 {
354 	fprint(2, "cc: %s\n", msg);
355 	exits(msg);
356 }
357 
358 /* src ends in .something; return copy of basename with .ext added */
359 char *
360 changeext(char *src, char *ext)
361 {
362 	char *b, *e, *ans;
363 
364 	b = utfrrune(src, '/');
365 	if(b)
366 		b++;
367 	else
368 		b = src;
369 	e = utfrrune(src, '.');
370 	if(!e)
371 		return 0;
372 	*e = 0;
373 	ans = smprint("%s.%s", b, ext);
374 	*e = '.';
375 	return ans;
376 }
377 
378 void
379 printlist(List *l)
380 {
381 	int i;
382 
383 	for(i = 0; i < l->n; i++) {
384 		fprint(2, "%s", l->strings[i]);
385 		if(i < l->n - 1)
386 			fprint(2, " ");
387 	}
388 }
389