Home | History | Annotate | Line # | Download | only in driver
      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 (at) 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 
     48 static volatile sig_atomic_t exit_now;
     49 static volatile sig_atomic_t child;
     50 
     51 static void
     52 sigterm_handler(int signum)
     53 {
     54 	exit_now = 1;
     55 	if (child)
     56 		kill(child, SIGTERM);
     57 }
     58 
     59 static const char versionstr[] = VERSSTR;
     60 
     61 enum phases { DEFAULT, PREPROCESS, COMPILE, ASSEMBLE, LINK } last_phase =
     62     DEFAULT;
     63 
     64 const char *isysroot = NULL;
     65 const char *sysroot = "";
     66 const char *preprocessor;
     67 const char *compiler;
     68 const char *assembler;
     69 const char *linker;
     70 
     71 struct strlist crtdirs;
     72 static struct strlist user_sysincdirs;
     73 struct strlist sysincdirs;
     74 struct strlist includes;
     75 struct strlist incdirs;
     76 struct strlist libdirs;
     77 struct strlist progdirs;
     78 struct strlist preprocessor_flags;
     79 struct strlist compiler_flags;
     80 struct strlist assembler_flags;
     81 struct strlist early_linker_flags;
     82 struct strlist middle_linker_flags;
     83 struct strlist late_linker_flags;
     84 struct strlist stdlib_flags;
     85 struct strlist early_program_csu_files;
     86 struct strlist late_program_csu_files;
     87 struct strlist early_dso_csu_files;
     88 struct strlist late_dso_csu_files;
     89 struct strlist temp_outputs;
     90 
     91 const char *final_output;
     92 static char *temp_directory;
     93 static struct strlist inputs;
     94 
     95 int pic_mode; /* 0: no PIC, 1: -fpic, 2: -fPIC */
     96 int save_temps;
     97 int debug_mode;
     98 int profile_mode;
     99 int nostdinc;
    100 int nostdlib;
    101 int nostartfiles;
    102 int static_mode;
    103 int shared_mode;
    104 int use_pthread;
    105 int verbose_mode;
    106 
    107 void
    108 error(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 
    118 static void
    119 warning(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 
    128 static void
    129 set_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 
    137 static void
    138 expand_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 
    167 static void
    168 missing_argument(const char *argp)
    169 {
    170 	error("Option `%s' required an argument", argp);
    171 }
    172 
    173 static void
    174 split_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 
    186 static int
    187 strlist_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 
    227 static char *
    228 find_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 
    251 static char *
    252 output_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 
    310 static int
    311 preprocess_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 
    354 static int
    355 compile_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 
    380 static int
    381 assemble_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 
    401 static int
    402 handle_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);
    462 done:
    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 
    474 static int
    475 run_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 
    515 static void
    516 cleanup(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 
    530 int
    531 main(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