xref: /plan9/sys/src/ape/cmd/cc.c (revision 4d44ba9b9ee4246ddbd96c7fcaf0918ab92ab35a)
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 	{"68020",	"2c", "2l", "2"},
27 	{"arm",		"5c", "5l", "5"},
28 	{"amd64",	"6c", "6l", "6"},
29 	{"alpha",	"7c", "7l", "7"},
30 	{"386",		"8c", "8l", "8"},
31 	{"sparc",	"kc", "kl", "k"},
32 	{"power",	"qc", "ql", "q"},
33 	{"mips",	"vc", "vl", "v"},
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 = "2678kqv";
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 		case 'T':
116 		case 'w':
117 			append(&cc, smprint("-%c", ARGC()));
118 			break;
119 		case 'O':
120 			break;
121 		case 'W':
122 			s = ARGF();
123 			if(s && s[1]==',') {
124 				switch (s[0]) {
125 				case 'p':
126 					append(&cpp, s+2);
127 					break;
128 				case '0':
129 					append(&cc, s+2);
130 					break;
131 				case 'l':
132 					append(&ldargs, s+2);
133 					break;
134 				default:
135 					fprint(2, "cc: pass letter after -W should be one of p0l; ignored\n");
136 				}
137 			} else
138 				fprint(2, "cc: bad option after -W; ignored\n");
139 			break;
140 		case 'v':
141 			vflag = 1;
142 			append(&ldargs, "-v");
143 			break;
144 		case 'A':
145 			Aflag = 1;
146 			break;
147 		case 'S':
148 			Sflag = 1;
149 			break;
150 		default:
151 			fprint(2, "cc: flag -%c ignored\n", ARGC());
152 			break;
153 		} ARGEND
154 		if(!Aflag) {
155 			append(&cc, "-J");		/* old/new decl mixture hack */
156 			append(&cc, "-B");		/* turn off non-prototype warnings */
157 		}
158 		if(argc > 0) {
159 			s = argv[0];
160 			suf = utfrrune(s, '.');
161 			if(suf) {
162 				suf++;
163 				if(strcmp(suf, "c") == 0) {
164 					append(&srcs, s);
165 					append(&objs, changeext(s, "o"));
166 				} else if(strcmp(suf, "o") == 0 ||
167 					  strcmp(suf, ot->o) == 0 ||
168 					  strcmp(suf, "a") == 0 ||
169 					  (suf[0] == 'a' && strcmp(suf+1, ot->o) == 0)) {
170 					append(&objs, s);
171 				} else if(utfrune(allos, suf[0]) != 0) {
172 					fprint(2, "cc: argument %s ignored: wrong architecture\n",
173 						s);
174 				}
175 			}
176 		}
177 	}
178 	if(objs.n == 0)
179 		fatal("no files to compile or load");
180 	ccpath = smprint("/bin/%s", ot->cc);
181 	append(&cpp, smprint("-I/%s/include/ape", ot->name));
182 	append(&cpp, "-I/sys/include/ape");
183 	cppn = cpp.n;
184 	ccn = cc.n;
185 	for(i = 0; i < srcs.n; i++) {
186 		append(&cpp, srcs.strings[i]);
187 		if(Eflag)
188 			doexec("/bin/cpp", &cpp);
189 		else {
190 			if(Sflag)
191 				append(&cc, "-S");
192 			else {
193 				append(&cc, "-o");
194 				if (haveoname && cflag)
195 					append(&cc, oname);
196 				else
197 					append(&cc, changeext(srcs.strings[i], "o"));
198 			}
199 			dopipe("/bin/cpp", &cpp, ccpath, &cc);
200 		}
201 		cpp.n = cppn;
202 		cc.n = ccn;
203 	}
204 	if(!cflag) {
205 		append(&ld, "-o");
206 		append(&ld, oname);
207 		for(i = 0; i < ldargs.n; i++)
208 			append(&ld, ldargs.strings[i]);
209 		for(i = 0; i < objs.n; i++)
210 			append(&ld, objs.strings[i]);
211 		append(&ld, smprint("/%s/lib/ape/libap.a", ot->name));
212 		doexec(smprint("/bin/%s", ot->ld), &ld);
213 		if(objs.n == 1)
214 			remove(objs.strings[0]);
215 	}
216 
217 	exits(0);
218 }
219 
220 char *
221 searchlib(char *s, char *objtype)
222 {
223 	char *l;
224 	int i;
225 
226 	if(!s)
227 		return 0;
228 	for(i = srchlibs.n-1; i>=0; i--) {
229 		l = smprint("%s/lib%s.a", srchlibs.strings[i], s);
230 		if(access(l, 0) >= 0)
231 			return l;
232 	}
233 	if(s[1] == 0)
234 		switch(s[0]) {
235 		case 'c':
236 			l = smprint("/%s/lib/ape/libap.a", objtype);
237 			break;
238 		case 'm':
239 			l = smprint("/%s/lib/ape/libap.a", objtype);
240 			break;
241 		case 'l':
242 			l = smprint("/%s/lib/ape/libl.a", objtype);
243 			break;
244 		case 'y':
245 			l = smprint("/%s/lib/ape/liby.a", objtype);
246 			break;
247 		default:
248 			l = 0;
249 		}
250 	else
251 		l = 0;
252 	return l;
253 }
254 
255 void
256 append(List *l, char *s)
257 {
258 	if(l->n >= Maxlist-1)
259 		fatal("too many arguments");
260 	l->strings[l->n++] = s;
261 	l->strings[l->n] = 0;
262 }
263 
264 void
265 doexec(char *c, List *a)
266 {
267 	Waitmsg *w;
268 
269 	if(vflag) {
270 		printlist(a);
271 		fprint(2, "\n");
272 	}
273 	switch(fork()) {
274 	case -1:
275 		fatal("fork failed");
276 	case 0:
277 		exec(c, a->strings);
278 		fatal("exec failed");
279 	}
280 	if((w = wait()) == nil)
281 		fatal("wait failed");
282 	if(w->msg[0])
283 		fatal(smprint("%s: %s", a->strings[0], w->msg));
284 	free(w);
285 }
286 
287 void
288 dopipe(char *c1, List *a1, char *c2, List *a2)
289 {
290 	Waitmsg *w;
291 	int pid1, got;
292 	int fd[2];
293 
294 	if(vflag) {
295 		printlist(a1);
296 		fprint(2, " | ");
297 		printlist(a2);
298 		fprint(2, "\n");
299 	}
300 	if(pipe(fd) < 0)
301 		fatal("pipe failed");
302 	switch((pid1 = fork())) {
303 	case -1:
304 		fatal("fork failed");
305 	case 0:
306 		dup(fd[0], 0);
307 		close(fd[0]);
308 		close(fd[1]);
309 		exec(c2, a2->strings);
310 		fatal("exec failed");
311 	}
312 	switch(fork()) {
313 	case -1:
314 		fatal("fork failed");
315 	case 0:
316 		close(0);
317 		dup(fd[1], 1);
318 		close(fd[0]);
319 		close(fd[1]);
320 		exec(c1, a1->strings);
321 		fatal("exec failed");
322 	}
323 	close(fd[0]);
324 	close(fd[1]);
325 	for(got = 0; got < 2; got++) {
326 		if((w = wait()) == nil)
327 			fatal("wait failed");
328 		if(w->msg[0])
329 			fatal(smprint("%s: %s", (w->pid == pid1) ? a1->strings[0] : a2->strings[0], w->msg));
330 		free(w);
331 	}
332 }
333 
334 Objtype *
335 findoty(void)
336 {
337 	char *o;
338 	Objtype *oty;
339 
340 	o = getenv("objtype");
341 	if(!o)
342 		fatal("no $objtype in environment");
343 	for(oty = objtype; oty < &objtype[Nobjs]; oty++)
344 		if(strcmp(o, oty->name) == 0)
345 			return oty;
346 	fatal("unknown $objtype");
347 	return 0;			/* shut compiler up */
348 }
349 
350 void
351 fatal(char *msg)
352 {
353 	fprint(2, "cc: %s\n", msg);
354 	exits(msg);
355 }
356 
357 /* src ends in .something; return copy of basename with .ext added */
358 char *
359 changeext(char *src, char *ext)
360 {
361 	char *b, *e, *ans;
362 
363 	b = utfrrune(src, '/');
364 	if(b)
365 		b++;
366 	else
367 		b = src;
368 	e = utfrrune(src, '.');
369 	if(!e)
370 		return 0;
371 	*e = 0;
372 	ans = smprint("%s.%s", b, ext);
373 	*e = '.';
374 	return ans;
375 }
376 
377 void
378 printlist(List *l)
379 {
380 	int i;
381 
382 	for(i = 0; i < l->n; i++) {
383 		fprint(2, "%s", l->strings[i]);
384 		if(i < l->n - 1)
385 			fprint(2, " ");
386 	}
387 }
388