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