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