1/*	Id: driver.c,v 1.7 2011/06/03 15:34:01 plunky Exp 	*/
2/*	$NetBSD: driver.c,v 1.1.1.1 2011/09/01 12:47:04 plunky Exp $	*/
3
4/*-
5 * Copyright (c) 2011 Joerg Sonnenberger <joerg@NetBSD.org>.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in
16 *    the documentation and/or other materials provided with the
17 *    distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/wait.h>
34#include <assert.h>
35#include <errno.h>
36#include <signal.h>
37#include <stdarg.h>
38#include <stdlib.h>
39#include <stdio.h>
40#include <string.h>
41#include <unistd.h>
42
43#include "driver.h"
44#include "xalloc.h"
45
46#include "config.h"
47
48static volatile sig_atomic_t exit_now;
49static volatile sig_atomic_t child;
50
51static void
52sigterm_handler(int signum)
53{
54	exit_now = 1;
55	if (child)
56		kill(child, SIGTERM);
57}
58
59static const char versionstr[] = VERSSTR;
60
61enum phases { DEFAULT, PREPROCESS, COMPILE, ASSEMBLE, LINK } last_phase =
62    DEFAULT;
63
64const char *isysroot = NULL;
65const char *sysroot = "";
66const char *preprocessor;
67const char *compiler;
68const char *assembler;
69const char *linker;
70
71struct strlist crtdirs;
72static struct strlist user_sysincdirs;
73struct strlist sysincdirs;
74struct strlist includes;
75struct strlist incdirs;
76struct strlist libdirs;
77struct strlist progdirs;
78struct strlist preprocessor_flags;
79struct strlist compiler_flags;
80struct strlist assembler_flags;
81struct strlist early_linker_flags;
82struct strlist middle_linker_flags;
83struct strlist late_linker_flags;
84struct strlist stdlib_flags;
85struct strlist early_program_csu_files;
86struct strlist late_program_csu_files;
87struct strlist early_dso_csu_files;
88struct strlist late_dso_csu_files;
89struct strlist temp_outputs;
90
91const char *final_output;
92static char *temp_directory;
93static struct strlist inputs;
94
95int pic_mode; /* 0: no PIC, 1: -fpic, 2: -fPIC */
96int save_temps;
97int debug_mode;
98int profile_mode;
99int nostdinc;
100int nostdlib;
101int nostartfiles;
102int static_mode;
103int shared_mode;
104int use_pthread;
105int verbose_mode;
106
107void
108error(const char *fmt, ...)
109{
110	va_list arg;
111	va_start(arg, fmt);
112	vfprintf(stderr, fmt, arg);
113	putc('\n', stderr);
114	va_end(arg);
115	exit(1);
116}
117
118static void
119warning(const char *fmt, ...)
120{
121	va_list arg;
122	va_start(arg, fmt);
123	vfprintf(stderr, fmt, arg);
124	putc('\n', stderr);
125	va_end(arg);
126}
127
128static void
129set_last_phase(enum phases phase)
130{
131	assert(phase != DEFAULT);
132	if (last_phase != DEFAULT && phase != last_phase)
133		error("conflicting compiler options specified");
134	last_phase = phase;
135}
136
137static void
138expand_sysroot(void)
139{
140	struct string *s;
141	struct strlist *lists[] = { &crtdirs, &sysincdirs, &incdirs,
142	    &user_sysincdirs, &libdirs, &progdirs, NULL };
143	const char *sysroots[] = { sysroot, isysroot, isysroot, isysroot,
144	    sysroot, sysroot, NULL };
145	size_t i, sysroot_len, value_len;
146	char *path;
147
148	assert(sizeof(lists) / sizeof(lists[0]) ==
149	       sizeof(sysroots) / sizeof(sysroots[0]));
150
151	for (i = 0; lists[i] != NULL; ++i) {
152		STRLIST_FOREACH(s, lists[i]) {
153			if (s->value[0] != '=')
154				continue;
155			sysroot_len = strlen(sysroots[i]);
156			/* Skipped '=' compensates additional space for '\0' */
157			value_len = strlen(s->value);
158			path = xmalloc(sysroot_len + value_len);
159			memcpy(path, sysroots[i], sysroot_len);
160			memcpy(path + sysroot_len, s->value + 1, value_len);
161			free(s->value);
162			s->value = path;
163		}
164	}
165}
166
167static void
168missing_argument(const char *argp)
169{
170	error("Option `%s' required an argument", argp);
171}
172
173static void
174split_and_append(struct strlist *l, char *arg)
175{
176	char *next;
177
178	for (; arg != NULL; arg = NULL) {
179		next = strchr(arg, ',');
180		if (next != NULL)
181			*next++ = '\0';
182		strlist_append(l, arg);
183	}
184}
185
186static int
187strlist_exec(struct strlist *l)
188{
189	char **argv;
190	size_t argc;
191	int result;
192
193	strlist_make_array(l, &argv, &argc);
194	if (verbose_mode) {
195		printf("Calling ");
196		strlist_print(l, stdout);
197		printf("\n");
198	}
199
200	if (exit_now)
201		return 1;
202
203	switch ((child = fork())) {
204	case 0:
205		execvp(argv[0], argv);
206		result = write(STDERR_FILENO, "Exec of ", 8);
207		result = write(STDERR_FILENO, argv[0], strlen(argv[0]));
208		result = write(STDERR_FILENO, "failed\n", 7);
209		(void)result;
210		_exit(127);
211	case -1:
212		error("fork failed");
213	default:
214		while (waitpid(child, &result, 0) == -1 && errno == EINTR)
215			/* nothing */(void)0;
216		result = WEXITSTATUS(result);
217		if (result)
218			error("%s terminated with status %d", argv[0], result);
219		while (argc-- > 0)
220			free(argv[argc]);
221		free(argv);
222		break;
223	}
224	return exit_now;
225}
226
227static char *
228find_file(const char *file, struct strlist *path, int mode)
229{
230	struct string *s;
231	char *f;
232	size_t lf, lp;
233	int need_sep;
234
235	lf = strlen(file);
236	STRLIST_FOREACH(s, path) {
237		lp = strlen(s->value);
238		need_sep = (lp && s->value[lp - 1] != '/') ? 1 : 0;
239		f = xmalloc(lp + lf + need_sep + 1);
240		memcpy(f, s->value, lp);
241		if (need_sep)
242			f[lp] = '/';
243		memcpy(f + lp + need_sep, file, lf + 1);
244		if (access(f, mode) == 0)
245			return f;
246		free(f);
247	}
248	return xstrdup(file);
249}
250
251static char *
252output_name(const char *file, const char *new_suffix, int counter, int last)
253{
254	const char *old_suffix;
255	char *name;
256	size_t lf, ls, len;
257	int counter_len;
258
259	if (last && final_output)
260		return xstrdup(final_output);
261
262	old_suffix = strrchr(file, '.');
263	if (old_suffix != NULL && strchr(old_suffix, '/') != NULL)
264		old_suffix = NULL;
265	if (old_suffix == NULL)
266		old_suffix = file + strlen(file);
267
268	ls = strlen(new_suffix);
269	if (save_temps || last) {
270		lf = old_suffix - file;
271		name = xmalloc(lf + ls + 1);
272		memcpy(name, file, lf);
273		memcpy(name + lf, new_suffix, ls + 1);
274		return name;
275	}
276	if (temp_directory == NULL) {
277		const char *template;
278		char *path;
279		size_t template_len;
280		int need_sep;
281
282		template = getenv("TMPDIR");
283		if (template == NULL)
284			template = "/tmp";
285		template_len = strlen(template);
286		if (template_len && template[template_len - 1] == '/')
287			need_sep = 0;
288		else
289			need_sep = 1;
290		path = xmalloc(template_len + need_sep + 6 + 1);
291		memcpy(path, template, template_len);
292		if (need_sep)
293			path[template_len] = '/';
294		memcpy(path + template_len + need_sep, "pcc-XXXXXX", 11);
295		if (mkdtemp(path) == NULL)
296			error("mkdtemp failed: %s", strerror(errno));
297		temp_directory = path;
298	}
299	lf = strlen(temp_directory);
300	counter_len = snprintf(NULL, 0, "%d", counter);
301	if (counter_len < 1)
302		error("snprintf failure");
303	len = lf + 1 + (size_t)counter_len + ls + 1;
304	name = xmalloc(len);
305	snprintf(name, len, "%s/%d%s", temp_directory, counter, new_suffix);
306	strlist_append(&temp_outputs, name);
307	return name;
308}
309
310static int
311preprocess_input(const char *file, char *input, char **output,
312    const char *suffix, int counter)
313{
314	struct strlist args;
315	struct string *s;
316	char *out;
317	int retval;
318
319	strlist_init(&args);
320	strlist_append_list(&args, &preprocessor_flags);
321	STRLIST_FOREACH(s, &includes) {
322		strlist_append(&args, "-i");
323		strlist_append(&args, s->value);
324	}
325	STRLIST_FOREACH(s, &incdirs) {
326		strlist_append(&args, "-I");
327		strlist_append(&args, s->value);
328	}
329	STRLIST_FOREACH(s, &user_sysincdirs) {
330		strlist_append(&args, "-S");
331		strlist_append(&args, s->value);
332	}
333	if (!nostdinc) {
334		STRLIST_FOREACH(s, &sysincdirs) {
335			strlist_append(&args, "-S");
336			strlist_append(&args, s->value);
337		}
338	}
339	strlist_append(&args, input);
340	if (last_phase == PREPROCESS && final_output == NULL)
341		out = xstrdup("-");
342	else
343		out = output_name(file, suffix, counter,
344		    last_phase == PREPROCESS);
345	if (strcmp(out, "-"))
346		strlist_append(&args, out);
347	strlist_prepend(&args, find_file(preprocessor, &progdirs, X_OK));
348	*output = out;
349	retval = strlist_exec(&args);
350	strlist_free(&args);
351	return retval;
352}
353
354static int
355compile_input(const char *file, char *input, char **output,
356    const char *suffix, int counter)
357{
358	struct strlist args;
359	char *out;
360	int retval;
361
362	strlist_init(&args);
363	strlist_append_list(&args, &compiler_flags);
364	if (debug_mode)
365		strlist_append(&args, "-g");
366	if (pic_mode)
367		strlist_append(&args, "-k");
368	if (profile_mode)
369		warning("-pg is currently ignored");
370	strlist_append(&args, input);
371	out = output_name(file, suffix, counter, last_phase == ASSEMBLE);
372	strlist_append(&args, out);
373	strlist_prepend(&args, find_file(compiler, &progdirs, X_OK));
374	*output = out;
375	retval = strlist_exec(&args);
376	strlist_free(&args);
377	return retval;
378}
379
380static int
381assemble_input(const char *file, char *input, char **output,
382    const char *suffix, int counter)
383{
384	struct strlist args;
385	char *out;
386	int retval;
387
388	strlist_init(&args);
389	strlist_append_list(&args, &assembler_flags);
390	strlist_append(&args, input);
391	out = output_name(file, ".o", counter, last_phase == COMPILE);
392	strlist_append(&args, "-o");
393	strlist_append(&args, out);
394	strlist_prepend(&args, find_file(assembler, &progdirs, X_OK));
395	*output = out;
396	retval = strlist_exec(&args);
397	strlist_free(&args);
398	return retval;
399}
400
401static int
402handle_input(const char *file)
403{
404	static int counter;
405	const char *suffix;
406	char *src;
407	int handled, retval;
408
409	++counter;
410
411	if (strcmp(file, "-") == 0) {
412		/* XXX see -x option */
413		suffix = ".c";
414	} else {
415		suffix = strrchr(file, '.');
416		if (suffix != NULL && strchr(suffix, '/') != NULL)
417			suffix = NULL;
418		if (suffix == NULL)
419			suffix = "";
420	}
421
422	src = xstrdup(file);
423	if (strcmp(suffix, ".c") == 0) {
424		suffix = ".i";
425		retval = preprocess_input(file, src, &src, suffix, counter);
426		if (retval)
427			return retval;
428		handled = 1;
429	} else if (strcmp(suffix, ".S") == 0) {
430		suffix = ".s";
431		retval = preprocess_input(file, src, &src, suffix, counter);
432		if (retval)
433			return retval;
434		handled = 1;
435	}
436
437	if (last_phase == PREPROCESS)
438		goto done;
439
440	if (strcmp(suffix, ".i") == 0) {
441		suffix = ".s";
442		retval = compile_input(file, src, &src, suffix, counter);
443		if (retval)
444			return retval;
445		handled = 1;
446	}
447	if (last_phase == ASSEMBLE)
448		goto done;
449
450	if (strcmp(suffix, ".s") == 0) {
451		suffix = ".o";
452		retval = assemble_input(file, src, &src, suffix, counter);
453		if (retval)
454			return retval;
455		handled = 1;
456	}
457	if (last_phase == COMPILE)
458		goto done;
459	if (strcmp(suffix, ".o") == 0)
460		handled = 1;
461	strlist_append(&middle_linker_flags, src);
462done:
463	if (handled)
464		return 0;
465	if (last_phase == LINK)
466		warning("unknown suffix %s, passing file down to linker",
467		    suffix);
468	else
469		warning("unknown suffix %s, skipped", suffix);
470	free(src);
471	return 0;
472}
473
474static int
475run_linker(void)
476{
477	struct strlist linker_flags;
478	struct strlist *early_csu, *late_csu;
479	struct string *s;
480	int retval;
481
482	if (final_output) {
483		strlist_prepend(&early_linker_flags, final_output);
484		strlist_prepend(&early_linker_flags, "-o");
485	}
486	if (!nostdlib)
487		strlist_append_list(&late_linker_flags, &stdlib_flags);
488	if (!nostartfiles) {
489		if (shared_mode) {
490			early_csu = &early_dso_csu_files;
491			late_csu = &late_dso_csu_files;
492		} else {
493			early_csu = &early_program_csu_files;
494			late_csu = &late_program_csu_files;
495		}
496		STRLIST_FOREACH(s, early_csu)
497			strlist_append_nocopy(&middle_linker_flags,
498			    find_file(s->value, &crtdirs, R_OK));
499		STRLIST_FOREACH(s, late_csu)
500			strlist_append_nocopy(&late_linker_flags,
501			    find_file(s->value, &crtdirs, R_OK));
502	}
503	strlist_init(&linker_flags);
504	strlist_append_list(&linker_flags, &early_linker_flags);
505	strlist_append_list(&linker_flags, &middle_linker_flags);
506	strlist_append_list(&linker_flags, &late_linker_flags);
507	strlist_prepend(&linker_flags, find_file(linker, &progdirs, X_OK));
508
509	retval = strlist_exec(&linker_flags);
510
511	strlist_free(&linker_flags);
512	return retval;
513}
514
515static void
516cleanup(void)
517{
518	struct string *file;
519
520	STRLIST_FOREACH(file, &temp_outputs) {
521		if (unlink(file->value) == -1)
522			warning("removal of ``%s'' failed: %s", file->value,
523			    strerror(errno));
524	}
525	if (temp_directory && rmdir(temp_directory) == -1)
526		warning("removal of ``%s'' failed: %s", temp_directory,
527		    strerror(errno));
528}
529
530int
531main(int argc, char **argv)
532{
533	struct string *input;
534	char *argp;
535	int retval;
536
537	strlist_init(&crtdirs);
538	strlist_init(&user_sysincdirs);
539	strlist_init(&sysincdirs);
540	strlist_init(&incdirs);
541	strlist_init(&includes);
542	strlist_init(&libdirs);
543	strlist_init(&progdirs);
544	strlist_init(&inputs);
545	strlist_init(&preprocessor_flags);
546	strlist_init(&compiler_flags);
547	strlist_init(&assembler_flags);
548	strlist_init(&early_linker_flags);
549	strlist_init(&middle_linker_flags);
550	strlist_init(&late_linker_flags);
551	strlist_init(&stdlib_flags);
552	strlist_init(&early_program_csu_files);
553	strlist_init(&late_program_csu_files);
554	strlist_init(&early_dso_csu_files);
555	strlist_init(&late_dso_csu_files);
556	strlist_init(&temp_outputs);
557
558	init_platform_specific(TARGOS, TARGMACH);
559
560	while (--argc) {
561		++argv;
562		argp = *argv;
563
564		if (*argp != '-' || strcmp(argp, "-") == 0) {
565			strlist_append(&inputs, argp);
566			continue;
567		}
568		switch (argp[1]) {
569		case '-':
570			if (strcmp(argp, "--param") == 0) {
571				if (argc == 0)
572					missing_argument(argp);
573				--argc;
574				++argv;
575				/* Unused */
576				continue;
577			}
578			if (strncmp(argp, "--sysroot=", 10) == 0) {
579				sysroot = argp + 10;
580				continue;
581			}
582			if (strcmp(argp, "--version") == 0) {
583				printf("%s\n", versionstr);
584				exit(0);
585			}
586			break;
587		case 'B':
588			strlist_append(&crtdirs, argp);
589			strlist_append(&libdirs, argp);
590			strlist_append(&progdirs, argp);
591			continue;
592		case 'C':
593			if (argp[2] == '\0') {
594				strlist_append(&preprocessor_flags, argp);
595				continue;
596			}
597			break;
598		case 'c':
599			if (argp[2] == '\0') {
600				set_last_phase(COMPILE);
601				continue;
602			}
603			break;
604		case 'D':
605			strlist_append(&preprocessor_flags, argp);
606			if (argp[2] == '\0') {
607				if (argc == 0)
608					missing_argument(argp);
609				--argc;
610				++argv;
611				strlist_append(&preprocessor_flags, argp);
612			}
613			continue;
614		case 'E':
615			if (argp[2] == '\0') {
616				set_last_phase(PREPROCESS);
617				continue;
618			}
619			break;
620		case 'f':
621			if (strcmp(argp, "-fpic") == 0) {
622				pic_mode = 1;
623				continue;
624			}
625			if (strcmp(argp, "-fPIC") == 0) {
626				pic_mode = 2;
627				continue;
628			}
629			/* XXX GCC options */
630			break;
631		case 'g':
632			if (argp[2] == '\0') {
633				debug_mode = 1;
634				continue;
635			}
636			/* XXX allow variants like -g1? */
637			break;
638		case 'I':
639			if (argp[2] == '\0') {
640				if (argc == 0)
641					missing_argument(argp);
642				--argc;
643				++argv;
644				strlist_append(&incdirs, argp);
645				continue;
646			}
647			strlist_append(&incdirs, argp + 2);
648			continue;
649		case 'i':
650			if (strcmp(argp, "-isystem") == 0) {
651				if (argc == 0)
652					missing_argument(argp);
653				--argc;
654				++argv;
655				strlist_append(&user_sysincdirs, argp);
656				continue;
657			}
658			if (strcmp(argp, "-include") == 0) {
659				if (argc == 0)
660					missing_argument(argp);
661				--argc;
662				++argv;
663				strlist_append(&includes, argp);
664				continue;
665			}
666			if (strcmp(argp, "-isysroot") == 0) {
667				if (argc == 0)
668					missing_argument(argp);
669				--argc;
670				++argv;
671				isysroot = argp;
672				continue;
673			}
674			/* XXX -idirafter */
675			/* XXX -iquote */
676			break;
677		case 'k':
678			if (argp[2] == '\0') {
679				pic_mode = 1;
680				continue;
681			}
682			break;
683		case 'M':
684			if (argp[2] == '\0') {
685				strlist_append(&preprocessor_flags, argp);
686				continue;
687			}
688			break;
689		case 'm':
690			/* XXX implement me */
691			break;
692		case 'n':
693			if (strcmp(argp, "-nostdinc") == 0) {
694				nostdinc = 1;
695				continue;
696			}
697			if (strcmp(argp, "-nostdinc++") == 0)
698				continue;
699			if (strcmp(argp, "-nostdlib") == 0) {
700				nostdlib = 1;
701				nostartfiles = 1;
702				continue;
703			}
704			if (strcmp(argp, "-nostartfiles") == 0) {
705				nostartfiles = 1;
706				continue;
707			}
708			break;
709		case 'O':
710			if (argp[2] != '\0' && argp[3] != '\0')
711				break;
712			switch(argp[2]) {
713			case '2':
714			case '1': case '\0':
715				strlist_append(&compiler_flags, "-xtemps");
716				strlist_append(&compiler_flags, "-xdeljumps");
717				strlist_append(&compiler_flags, "-xinline");
718			case '0':
719				continue;
720			}
721			break;
722		case 'o':
723			if (argp[2] == '\0') {
724				if (argc == 0)
725					missing_argument(argp);
726				--argc;
727				++argv;
728				if (final_output)
729					error("Only one `-o' option allowed");
730				final_output = *argv;
731				continue;
732			}
733			break;
734		case 'p':
735			if (argp[2] == '\0' || strcmp(argp, "-pg") == 0) {
736				profile_mode = 1;
737				continue;
738			}
739			if (strcmp(argp, "-pedantic") == 0)
740				continue;
741			if (strcmp(argp, "-pipe") == 0)
742				continue; /* XXX implement me */
743			if (strcmp(argp, "-pthread") == 0) {
744				use_pthread = 1;
745				continue;
746			}
747			/* XXX -print-prog-name=XXX */
748			/* XXX -print-multi-os-directory */
749			break;
750		case 'r':
751			if (argp[2] == '\0') {
752				strlist_append(&middle_linker_flags, argp);
753				continue;
754			}
755			break;
756		case 'S':
757			if (argp[2] == '\0') {
758				set_last_phase(ASSEMBLE);
759				continue;
760			}
761			break;
762		case 's':
763			if (strcmp(argp, "-save-temps") == 0) {
764				save_temps = 1;
765				continue;
766			}
767			if (strcmp(argp, "-shared") == 0) {
768				shared_mode = 1;
769				continue;
770			}
771			if (strcmp(argp, "-static") == 0) {
772				static_mode = 1;
773				continue;
774			}
775			if (strncmp(argp, "-std=", 5) == 0)
776				continue; /* XXX sanitize me */
777			break;
778		case 't':
779			if (argp[2] == '\0') {
780				strlist_append(&preprocessor_flags, argp);
781				continue;
782			}
783		case 'U':
784			strlist_append(&preprocessor_flags, argp);
785			if (argp[2] == '\0') {
786				if (argc == 0)
787					missing_argument(argp);
788				--argc;
789				++argv;
790				strlist_append(&preprocessor_flags, argp);
791			}
792			continue;
793		case 'v':
794			if (argp[2] == '\0') {
795				verbose_mode = 1;
796				continue;
797			}
798			break;
799		case 'W':
800			if (strncmp(argp, "-Wa,", 4) == 0) {
801				split_and_append(&assembler_flags, argp + 4);
802				continue;
803			}
804			if (strncmp(argp, "-Wl,", 4) == 0) {
805				split_and_append(&middle_linker_flags, argp + 4);
806				continue;
807			}
808			if (strncmp(argp, "-Wp,", 4) == 0) {
809				split_and_append(&preprocessor_flags, argp + 4);
810				continue;
811			}
812			/* XXX warning flags */
813			break;
814		case 'x':
815			/* XXX -x c */
816			/* XXX -c assembler-with-cpp */
817			break;
818		}
819		error("unknown flag `%s'", argp);
820	}
821
822	if (last_phase == DEFAULT)
823		last_phase = LINK;
824
825	if (verbose_mode)
826		printf("%s\n", versionstr);
827
828	if (isysroot == NULL)
829		isysroot = sysroot;
830	expand_sysroot();
831
832	if (last_phase != LINK && final_output && !STRLIST_EMPTY(&inputs) &&
833	    !STRLIST_NEXT(STRLIST_FIRST(&inputs)))
834		error("-o specified with more than one input");
835
836	if (last_phase == PREPROCESS && final_output == NULL)
837		final_output = "-";
838
839	if (STRLIST_EMPTY(&inputs))
840		error("No input specificed");
841
842	retval = 0;
843
844	signal(SIGTERM, sigterm_handler);
845
846	STRLIST_FOREACH(input, &inputs) {
847		if (handle_input(input->value))
848			retval = 1;
849	}
850	if (!retval && last_phase == LINK) {
851		if (run_linker())
852			retval = 1;
853	}
854
855	if (exit_now)
856		warning("Received signal, terminating");
857
858	cleanup();
859
860	strlist_free(&crtdirs);
861	strlist_free(&user_sysincdirs);
862	strlist_free(&sysincdirs);
863	strlist_free(&incdirs);
864	strlist_free(&includes);
865	strlist_free(&libdirs);
866	strlist_free(&progdirs);
867	strlist_free(&inputs);
868	strlist_free(&preprocessor_flags);
869	strlist_free(&compiler_flags);
870	strlist_free(&assembler_flags);
871	strlist_free(&early_linker_flags);
872	strlist_free(&middle_linker_flags);
873	strlist_free(&late_linker_flags);
874	strlist_free(&stdlib_flags);
875	strlist_free(&early_program_csu_files);
876	strlist_free(&late_program_csu_files);
877	strlist_free(&early_dso_csu_files);
878	strlist_free(&late_dso_csu_files);
879	strlist_free(&temp_outputs);
880
881	return retval;
882}
883