Home | History | Annotate | Download | only in cw
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * Wrapper for the GNU C compiler to make it accept the Sun C compiler
     29  * arguments where possible.
     30  *
     31  * Since the translation is inexact, this is something of a work-in-progress.
     32  *
     33  */
     34 
     35 /* If you modify this file, you must increment CW_VERSION */
     36 #define	CW_VERSION	"1.28"
     37 
     38 /*
     39  * -#		Verbose mode
     40  * -###		Show compiler commands built by driver, no compilation
     41  * -A<name[(tokens)]>	Preprocessor predicate assertion
     42  * -B<[static|dynamic]>	Specify dynamic or static binding
     43  * -C		Prevent preprocessor from removing comments
     44  * -c		Compile only - produce .o files, suppress linking
     45  * -cg92	Alias for -xtarget=ss1000
     46  * -D<name[=token]>	Associate name with token as if by #define
     47  * -d[y|n]	dynamic [-dy] or static [-dn] option to linker
     48  * -E		Compile source through preprocessor only, output to stdout
     49  * -erroff=<t>	Suppress warnings specified by tags t(%none, %all, <tag list>)
     50  * -errtags=<a>	Display messages with tags a(no, yes)
     51  * -errwarn=<t>	Treats warnings specified by tags t(%none, %all, <tag list>)
     52  *		as errors
     53  * -fast	Optimize using a selection of options
     54  * -fd		Report old-style function definitions and declarations
     55  * -features=zla	Allow zero-length arrays
     56  * -flags	Show this summary of compiler options
     57  * -fnonstd	Initialize floating-point hardware to non-standard preferences
     58  * -fns[=<yes|no>] Select non-standard floating point mode
     59  * -fprecision=<p> Set FP rounding precision mode p(single, double, extended)
     60  * -fround=<r>	Select the IEEE rounding mode in effect at startup
     61  * -fsimple[=<n>] Select floating-point optimization preferences <n>
     62  * -fsingle	Use single-precision arithmetic (-Xt and -Xs modes only)
     63  * -ftrap=<t>	Select floating-point trapping mode in effect at startup
     64  * -fstore	force floating pt. values to target precision on assignment
     65  * -G		Build a dynamic shared library
     66  * -g		Compile for debugging
     67  * -H		Print path name of each file included during compilation
     68  * -h <name>	Assign <name> to generated dynamic shared library
     69  * -I<dir>	Add <dir> to preprocessor #include file search path
     70  * -i		Passed to linker to ignore any LD_LIBRARY_PATH setting
     71  * -keeptmp	Keep temporary files created during compilation
     72  * -KPIC	Compile position independent code with 32-bit addresses
     73  * -Kpic	Compile position independent code
     74  * -L<dir>	Pass to linker to add <dir> to the library search path
     75  * -l<name>	Link with library lib<name>.a or lib<name>.so
     76  * -mc		Remove duplicate strings from .comment section of output files
     77  * -mr		Remove all strings from .comment section of output files
     78  * -mr,"string"	Remove all strings and append "string" to .comment section
     79  * -mt		Specify options needed when compiling multi-threaded code
     80  * -native	Find available processor, generate code accordingly
     81  * -nofstore	Do not force floating pt. values to target precision
     82  *		on assignment
     83  * -nolib	Same as -xnolib
     84  * -noqueue	Disable queuing of compiler license requests
     85  * -norunpath	Do not build in a runtime path for shared libraries
     86  * -O		Use default optimization level (-xO2 or -xO3. Check man page.)
     87  * -o <outputfile> Set name of output file to <outputfile>
     88  * -P		Compile source through preprocessor only, output to .i  file
     89  * -PIC		Alias for -KPIC or -xcode=pic32
     90  * -p		Compile for profiling with prof
     91  * -pic		Alias for -Kpic or -xcode=pic13
     92  * -Q[y|n]	Emit/don't emit identification info to output file
     93  * -qp		Compile for profiling with prof
     94  * -R<dir[:dir]> Build runtime search path list into executable
     95  * -S		Compile and only generate assembly code (.s)
     96  * -s		Strip symbol table from the executable file
     97  * -t		Turn off duplicate symbol warnings when linking
     98  * -U<name>	Delete initial definition of preprocessor symbol <name>
     99  * -V		Report version number of each compilation phase
    100  * -v		Do stricter semantic checking
    101  * -W<c>,<arg>	Pass <arg> to specified component <c> (a,l,m,p,0,2,h,i,u)
    102  * -w		Suppress compiler warning messages
    103  * -Xa		Compile assuming ANSI C conformance, allow K & R extensions
    104  *		(default mode)
    105  * -Xc		Compile assuming strict ANSI C conformance
    106  * -Xs		Compile assuming (pre-ANSI) K & R C style code
    107  * -Xt		Compile assuming K & R conformance, allow ANSI C
    108  * -x386	Generate code for the 80386 processor
    109  * -x486	Generate code for the 80486 processor
    110  * -xarch=<a>	Specify target architecture instruction set
    111  * -xbuiltin[=<b>] When profitable inline, or substitute intrinisic functions
    112  *		for system functions, b={%all,%none}
    113  * -xCC		Accept C++ style comments
    114  * -xchar_byte_order=<o> Specify multi-char byte order <o> (default, high, low)
    115  * -xchip=<c>	Specify the target processor for use by the optimizer
    116  * -xcode=<c>	Generate different code for forming addresses
    117  * -xcrossfile[=<n>] Enable optimization and inlining across source files,
    118  *		n={0|1}
    119  * -xe		Perform only syntax/semantic checking, no code generation
    120  * -xF		Compile for later mapfile reordering or unused section
    121  *		elimination
    122  * -xhelp=<f>	Display on-line help information f(flags, readme, errors)
    123  * -xildoff	Cancel -xildon
    124  * -xildon	Enable use of the incremental linker, ild
    125  * -xinline=[<a>,...,<a>]  Attempt inlining of specified user routines,
    126  *		<a>={%auto,func,no%func}
    127  * -xlibmieee	Force IEEE 754 return values for math routines in
    128  *		exceptional cases
    129  * -xlibmil	Inline selected libm math routines for optimization
    130  * -xlic_lib=sunperf	Link in the Sun supplied performance libraries
    131  * -xlicinfo	Show license server information
    132  * -xM		Generate makefile dependencies
    133  * -xM1		Generate makefile dependencies, but exclude /usr/include
    134  * -xmaxopt=[off,1,2,3,4,5] maximum optimization level allowed on #pragma opt
    135  * -xnolib	Do not link with default system libraries
    136  * -xnolibmil	Cancel -xlibmil on command line
    137  * -xO<n>	Generate optimized code (n={1|2|3|4|5})
    138  * -xP		Print prototypes for function definitions
    139  * -xpentium	Generate code for the pentium processor
    140  * -xpg		Compile for profiling with gprof
    141  * -xprofile=<p> Collect data for a profile or use a profile to optimize
    142  *		<p>={{collect,use}[:<path>],tcov}
    143  * -xregs=<r>	Control register allocation
    144  * -xs		Allow debugging without object (.o) files
    145  * -xsb		Compile for use with the WorkShop source browser
    146  * -xsbfast	Generate only WorkShop source browser info, no compilation
    147  * -xsfpconst	Represent unsuffixed floating point constants as single
    148  *		precision
    149  * -xspace	Do not do optimizations that increase code size
    150  * -xstrconst	Place string literals into read-only data segment
    151  * -xtarget=<t>	Specify target system for optimization
    152  * -xtemp=<dir>	Set directory for temporary files to <dir>
    153  * -xtime	Report the execution time for each compilation phase
    154  * -xtransition	Emit warnings for differences between K&R C and ANSI C
    155  * -xtrigraphs[=<yes|no>] Enable|disable trigraph translation
    156  * -xunroll=n	Enable unrolling loops n times where possible
    157  * -Y<c>,<dir>	Specify <dir> for location of component <c> (a,l,m,p,0,h,i,u)
    158  * -YA,<dir>	Change default directory searched for components
    159  * -YI,<dir>	Change default directory searched for include files
    160  * -YP,<dir>	Change default directory for finding libraries files
    161  * -YS,<dir>	Change default directory for startup object files
    162  */
    163 
    164 /*
    165  * Translation table:
    166  */
    167 /*
    168  * -#				-v
    169  * -###				error
    170  * -A<name[(tokens)]>		pass-thru
    171  * -B<[static|dynamic]>		pass-thru (syntax error for anything else)
    172  * -C				pass-thru
    173  * -c				pass-thru
    174  * -cg92			-m32 -mcpu=v8 -mtune=supersparc (SPARC only)
    175  * -D<name[=token]>		pass-thru
    176  * -dy or -dn			-Wl,-dy or -Wl,-dn
    177  * -E				pass-thru
    178  * -erroff=E_EMPTY_TRANSLATION_UNIT ignore
    179  * -errtags=%all		-Wall
    180  * -errwarn=%all		-Werror else -Wno-error
    181  * -fast			error
    182  * -fd				error
    183  * -features=zla		ignore
    184  * -flags			--help
    185  * -fnonstd			error
    186  * -fns[=<yes|no>]		error
    187  * -fprecision=<p>		error
    188  * -fround=<r>			error
    189  * -fsimple[=<n>]		error
    190  * -fsingle[=<n>]		error
    191  * -ftrap=<t>			error
    192  * -fstore			error
    193  * -G				pass-thru
    194  * -g				pass-thru
    195  * -H				pass-thru
    196  * -h <name>			pass-thru
    197  * -I<dir>			pass-thru
    198  * -i				pass-thru
    199  * -keeptmp			-save-temps
    200  * -KPIC			-fPIC
    201  * -Kpic			-fpic
    202  * -L<dir>			pass-thru
    203  * -l<name>			pass-thru
    204  * -mc				error
    205  * -mr				error
    206  * -mr,"string"			error
    207  * -mt				-D_REENTRANT
    208  * -native			error
    209  * -nofstore			error
    210  * -nolib			-nodefaultlibs
    211  * -noqueue			ignore
    212  * -norunpath			ignore
    213  * -O				-O1 (Check the man page to be certain)
    214  * -o <outputfile>		pass-thru
    215  * -P				-E -o filename.i (or error)
    216  * -PIC				-fPIC (C++ only)
    217  * -p				pass-thru
    218  * -pic				-fpic (C++ only)
    219  * -Q[y|n]			error
    220  * -qp				-p
    221  * -R<dir[:dir]>		pass-thru
    222  * -S				pass-thru
    223  * -s				-Wl,-s
    224  * -t				-Wl,-t
    225  * -U<name>			pass-thru
    226  * -V				--version
    227  * -v				-Wall
    228  * -Wa,<arg>			pass-thru
    229  * -Wp,<arg>			pass-thru except -xc99=<a>
    230  * -Wl,<arg>			pass-thru
    231  * -W{m,0,2,h,i,u>		error/ignore
    232  * -Wu,-xmodel=kernel		-ffreestanding -mcmodel=kernel -mno-red-zone
    233  * -xmodel=kernel		-ffreestanding -mcmodel=kernel -mno-red-zone
    234  * -Wu,-save_args		-msave-args
    235  * -w				pass-thru
    236  * -Xa				-std=iso9899:199409 or -ansi
    237  * -Xc				-ansi -pedantic
    238  * -Xt				error
    239  * -Xs				-traditional -std=c89
    240  * -x386			-march=i386 (x86 only)
    241  * -x486			-march=i486 (x86 only)
    242  * -xarch=<a>			table
    243  * -xbuiltin[=<b>]		-fbuiltin (-fno-builtin otherwise)
    244  * -xCC				ignore
    245  * -xchar_byte_order=<o>	error
    246  * -xchip=<c>			table
    247  * -xcode=<c>			table
    248  * -xdebugformat=<format>	ignore (always use dwarf-2 for gcc)
    249  * -xcrossfile[=<n>]		ignore
    250  * -xe				error
    251  * -xF				error
    252  * -xhelp=<f>			error
    253  * -xildoff			ignore
    254  * -xildon			ignore
    255  * -xinline			ignore
    256  * -xlibmieee			error
    257  * -xlibmil			error
    258  * -xlic_lib=sunperf		error
    259  * -xM				-M
    260  * -xM1				-MM
    261  * -xmaxopt=[...]		error
    262  * -xnolib			-nodefaultlibs
    263  * -xnolibmil			error
    264  * -xO<n>			-O<n>
    265  * -xP				error
    266  * -xpentium			-march=pentium (x86 only)
    267  * -xpg				error
    268  * -xprofile=<p>		error
    269  * -xregs=<r>			table
    270  * -xs				error
    271  * -xsb				error
    272  * -xsbfast			error
    273  * -xsfpconst			error
    274  * -xspace			ignore (-not -Os)
    275  * -xstrconst			ignore
    276  * -xtarget=<t>			table
    277  * -xtemp=<dir>			error
    278  * -xtime			error
    279  * -xtransition			-Wtransition
    280  * -xtrigraphs=<yes|no>		-trigraphs -notrigraphs
    281  * -xunroll=n			error
    282  * -W0,-xdbggen=no%usedonly	-fno-eliminate-unused-debug-symbols
    283  *				-fno-eliminate-unused-debug-types
    284  * -Y<c>,<dir>			error
    285  * -YA,<dir>			error
    286  * -YI,<dir>			-nostdinc -I<dir>
    287  * -YP,<dir>			error
    288  * -YS,<dir>			error
    289  */
    290 
    291 #include <stdio.h>
    292 #include <sys/types.h>
    293 #include <unistd.h>
    294 #include <string.h>
    295 #include <stdlib.h>
    296 #include <ctype.h>
    297 #include <fcntl.h>
    298 #include <errno.h>
    299 #include <stdarg.h>
    300 #include <sys/utsname.h>
    301 #include <sys/param.h>
    302 #include <sys/isa_defs.h>
    303 #include <sys/wait.h>
    304 #include <sys/stat.h>
    305 
    306 #define	CW_F_CXX	0x01
    307 #define	CW_F_SHADOW	0x02
    308 #define	CW_F_EXEC	0x04
    309 #define	CW_F_ECHO	0x08
    310 #define	CW_F_XLATE	0x10
    311 #define	CW_F_PROG	0x20
    312 
    313 typedef enum cw_compiler {
    314 	CW_C_CC = 0,
    315 	CW_C_GCC
    316 } cw_compiler_t;
    317 
    318 static const char *cmds[] = {
    319 	"cc", "CC",
    320 	"gcc", "g++"
    321 };
    322 
    323 static const char *dirs[] = {
    324 	DEFAULT_CC_DIR, DEFAULT_CPLUSPLUS_DIR,
    325 	DEFAULT_GCC_DIR, DEFAULT_GPLUSPLUS_DIR
    326 };
    327 
    328 #define	CC(ctx) \
    329 	(((ctx)->i_flags & CW_F_SHADOW) ? \
    330 	    ((ctx)->i_compiler == CW_C_CC ? CW_C_GCC : CW_C_CC) : \
    331 	    (ctx)->i_compiler)
    332 
    333 #define	CIDX(compiler, flags)	\
    334 	((int)(compiler) << 1) + ((flags) & CW_F_CXX ? 1 : 0)
    335 
    336 typedef enum cw_op {
    337 	CW_O_NONE = 0,
    338 	CW_O_PREPROCESS,
    339 	CW_O_COMPILE,
    340 	CW_O_LINK
    341 } cw_op_t;
    342 
    343 struct aelist {
    344 	struct ae {
    345 		struct ae *ae_next;
    346 		char *ae_arg;
    347 	} *ael_head, *ael_tail;
    348 	int ael_argc;
    349 };
    350 
    351 typedef struct cw_ictx {
    352 	cw_compiler_t	i_compiler;
    353 	struct aelist	*i_ae;
    354 	uint32_t	i_flags;
    355 	int		i_oldargc;
    356 	char		**i_oldargv;
    357 	pid_t		i_pid;
    358 	char		i_discard[MAXPATHLEN];
    359 	char		*i_stderr;
    360 } cw_ictx_t;
    361 
    362 /*
    363  * Status values to indicate which Studio compiler and associated
    364  * flags are being used.
    365  */
    366 #define	M32		0x01	/* -m32 - only on Studio 12 */
    367 #define	M64		0x02	/* -m64 - only on Studio 12 */
    368 #define	SS11		0x100	/* Studio 11 */
    369 #define	SS12		0x200	/* Studio 12 */
    370 
    371 #define	TRANS_ENTRY	5
    372 /*
    373  * Translation table definition for the -xarch= flag. The "x_arg"
    374  * value is translated into the appropriate gcc flags according
    375  * to the values in x_trans[n]. The x_flags indicates what compiler
    376  * is being used and what flags have been set via the use of
    377  * "x_arg".
    378  */
    379 typedef struct xarch_table {
    380 	char	*x_arg;
    381 	int	x_flags;
    382 	char	*x_trans[TRANS_ENTRY];
    383 } xarch_table_t;
    384 
    385 /*
    386  * The translation table for the -xarch= flag used in the Studio compilers.
    387  */
    388 static const xarch_table_t xtbl[] = {
    389 #if defined(__x86)
    390 	{ "generic",	SS11 },
    391 	{ "generic64",	(SS11|M64), { "-m64", "-mtune=opteron" } },
    392 	{ "amd64",	(SS11|M64), { "-m64", "-mtune=opteron" } },
    393 	{ "386",	SS11,	{ "-march=i386" } },
    394 	{ "pentium_pro", SS11,	{ "-march=pentiumpro" } },
    395 #elif defined(__sparc)
    396 	{ "generic",	(SS11|M32), { "-m32", "-mcpu=v8" } },
    397 	{ "generic64",	(SS11|M64), { "-m64", "-mcpu=v9" } },
    398 	{ "v8",		(SS11|M32), { "-m32", "-mcpu=v8", "-mno-v8plus" } },
    399 	{ "v8plus",	(SS11|M32), { "-m32", "-mcpu=v9", "-mv8plus" } },
    400 	{ "v8plusa",	(SS11|M32), { "-m32", "-mcpu=ultrasparc", "-mv8plus",
    401 			"-mvis" } },
    402 	{ "v8plusb",	(SS11|M32), { "-m32", "-mcpu=ultrasparc3", "-mv8plus",
    403 			"-mvis" } },
    404 	{ "v9",		(SS11|M64), { "-m64", "-mcpu=v9" } },
    405 	{ "v9a",	(SS11|M64), { "-m64", "-mcpu=ultrasparc", "-mvis" } },
    406 	{ "v9b",	(SS11|M64), { "-m64", "-mcpu=ultrasparc3", "-mvis" } },
    407 	{ "sparc",	SS12, { "-mcpu=v9", "-mv8plus" } },
    408 	{ "sparcvis",	SS12, { "-mcpu=ultrasparc", "-mvis" } },
    409 	{ "sparcvis2",	SS12, { "-mcpu=ultrasparc3", "-mvis" } }
    410 #endif
    411 };
    412 
    413 static int xtbl_size = sizeof (xtbl) / sizeof (xarch_table_t);
    414 
    415 static const char *progname;
    416 
    417 static const char *xchip_tbl[] = {
    418 #if defined(__x86)
    419 	"386",		"-mtune=i386", NULL,
    420 	"486",		"-mtune=i486", NULL,
    421 	"pentium",	"-mtune=pentium", NULL,
    422 	"pentium_pro",  "-mtune=pentiumpro", NULL,
    423 #elif defined(__sparc)
    424 	"super",	"-mtune=supersparc", NULL,
    425 	"ultra",	"-mtune=ultrasparc", NULL,
    426 	"ultra3",	"-mtune=ultrasparc3", NULL,
    427 #endif
    428 	NULL,		NULL
    429 };
    430 
    431 static const char *xcode_tbl[] = {
    432 #if defined(__sparc)
    433 	"abs32",	"-fno-pic", "-mcmodel=medlow", NULL,
    434 	"abs44",	"-fno-pic", "-mcmodel=medmid", NULL,
    435 	"abs64",	"-fno-pic", "-mcmodel=medany", NULL,
    436 	"pic13",	"-fpic", NULL,
    437 	"pic32",	"-fPIC", NULL,
    438 #endif
    439 	NULL,		NULL
    440 };
    441 
    442 static const char *xtarget_tbl[] = {
    443 #if defined(__x86)
    444 	"pentium_pro",	"-march=pentiumpro", NULL,
    445 #endif	/* __x86 */
    446 	NULL,		NULL
    447 };
    448 
    449 static const char *xregs_tbl[] = {
    450 #if defined(__sparc)
    451 	"appl",		"-mapp-regs", NULL,
    452 	"no%appl",	"-mno-app-regs", NULL,
    453 	"float",	"-mfpu", NULL,
    454 	"no%float",	"-mno-fpu", NULL,
    455 #endif	/* __sparc */
    456 	NULL,		NULL
    457 };
    458 
    459 static void
    460 nomem(void)
    461 {
    462 	(void) fprintf(stderr, "%s: error: out of memory\n", progname);
    463 	exit(1);
    464 }
    465 
    466 static void
    467 cw_perror(const char *fmt, ...)
    468 {
    469 	va_list ap;
    470 	int saved_errno = errno;
    471 
    472 	(void) fprintf(stderr, "%s: error: ", progname);
    473 
    474 	va_start(ap, fmt);
    475 	(void) vfprintf(stderr, fmt, ap);
    476 	va_end(ap);
    477 
    478 	(void) fprintf(stderr, " (%s)\n", strerror(saved_errno));
    479 }
    480 
    481 static void
    482 newae(struct aelist *ael, const char *arg)
    483 {
    484 	struct ae *ae;
    485 
    486 	if ((ae = calloc(sizeof (*ae), 1)) == NULL)
    487 		nomem();
    488 	ae->ae_arg = strdup(arg);
    489 	if (ael->ael_tail == NULL)
    490 		ael->ael_head = ae;
    491 	else
    492 		ael->ael_tail->ae_next = ae;
    493 	ael->ael_tail = ae;
    494 	ael->ael_argc++;
    495 }
    496 
    497 static cw_ictx_t *
    498 newictx(void)
    499 {
    500 	cw_ictx_t *ctx = calloc(sizeof (cw_ictx_t), 1);
    501 	if (ctx)
    502 		if ((ctx->i_ae = calloc(sizeof (struct aelist), 1)) == NULL) {
    503 			free(ctx);
    504 			return (NULL);
    505 		}
    506 
    507 	return (ctx);
    508 }
    509 
    510 static void
    511 error(const char *arg)
    512 {
    513 	(void) fprintf(stderr,
    514 	    "%s: error: mapping failed at or near arg '%s'\n", progname, arg);
    515 	exit(2);
    516 }
    517 
    518 /*
    519  * Add the current favourite set of warnings to the gcc invocation.
    520  */
    521 static void
    522 warnings(struct aelist *h)
    523 {
    524 	static int warningsonce;
    525 
    526 	if (warningsonce++)
    527 		return;
    528 
    529 	newae(h, "-Wall");
    530 	newae(h, "-Wno-unknown-pragmas");
    531 	newae(h, "-Wno-missing-braces");
    532 	newae(h, "-Wno-sign-compare");
    533 	newae(h, "-Wno-parentheses");
    534 	newae(h, "-Wno-uninitialized");
    535 	newae(h, "-Wno-implicit-function-declaration");
    536 	newae(h, "-Wno-unused");
    537 	newae(h, "-Wno-trigraphs");
    538 	newae(h, "-Wno-char-subscripts");
    539 	newae(h, "-Wno-switch");
    540 }
    541 
    542 static void
    543 optim_disable(struct aelist *h, int level)
    544 {
    545 	if (level >= 2) {
    546 		newae(h, "-fno-strict-aliasing");
    547 		newae(h, "-fno-unit-at-a-time");
    548 		newae(h, "-fno-optimize-sibling-calls");
    549 	}
    550 }
    551 
    552 /* ARGSUSED */
    553 static void
    554 Xamode(struct aelist *h)
    555 {
    556 }
    557 
    558 static void
    559 Xcmode(struct aelist *h)
    560 {
    561 	static int xconce;
    562 
    563 	if (xconce++)
    564 		return;
    565 
    566 	newae(h, "-ansi");
    567 	newae(h, "-pedantic-errors");
    568 }
    569 
    570 static void
    571 Xsmode(struct aelist *h)
    572 {
    573 	static int xsonce;
    574 
    575 	if (xsonce++)
    576 		return;
    577 
    578 	newae(h, "-traditional");
    579 	newae(h, "-traditional-cpp");
    580 }
    581 
    582 static void
    583 usage()
    584 {
    585 	(void) fprintf(stderr,
    586 	    "usage: %s { -_cc | -_gcc | -_CC | -_g++ } [ -_compiler | ... ]\n",
    587 	    progname);
    588 	exit(2);
    589 }
    590 
    591 static int
    592 xlate_xtb(struct aelist *h, const char *xarg)
    593 {
    594 	int	i, j;
    595 
    596 	for (i = 0; i < xtbl_size; i++) {
    597 		if (strcmp(xtbl[i].x_arg, xarg) == 0)
    598 			break;
    599 	}
    600 
    601 	/*
    602 	 * At the end of the table and so no matching "arg" entry
    603 	 * found and so this must be a bad -xarch= flag.
    604 	 */
    605 	if (i == xtbl_size)
    606 		error(xarg);
    607 
    608 	for (j = 0; j < TRANS_ENTRY; j++) {
    609 		if (xtbl[i].x_trans[j] != NULL)
    610 			newae(h, xtbl[i].x_trans[j]);
    611 		else
    612 			break;
    613 	}
    614 	return (xtbl[i].x_flags);
    615 
    616 }
    617 
    618 static void
    619 xlate(struct aelist *h, const char *xarg, const char **table)
    620 {
    621 	while (*table != NULL && strcmp(xarg, *table) != 0) {
    622 		while (*table != NULL)
    623 			table++;
    624 		table++;
    625 	}
    626 
    627 	if (*table == NULL)
    628 		error(xarg);
    629 
    630 	table++;
    631 
    632 	while (*table != NULL) {
    633 		newae(h, *table);
    634 		table++;
    635 	}
    636 }
    637 
    638 static void
    639 do_gcc(cw_ictx_t *ctx)
    640 {
    641 	int c;
    642 	int pic = 0, nolibc = 0;
    643 	int in_output = 0, seen_o = 0, c_files = 0;
    644 	cw_op_t op = CW_O_LINK;
    645 	char *model = NULL;
    646 	int	mflag = 0;
    647 
    648 	if (ctx->i_flags & CW_F_PROG) {
    649 		newae(ctx->i_ae, "--version");
    650 		return;
    651 	}
    652 
    653 	newae(ctx->i_ae, "-fident");
    654 	newae(ctx->i_ae, "-finline");
    655 	newae(ctx->i_ae, "-fno-inline-functions");
    656 	newae(ctx->i_ae, "-fno-builtin");
    657 	newae(ctx->i_ae, "-fno-asm");
    658 	newae(ctx->i_ae, "-nodefaultlibs");
    659 
    660 #if defined(__sparc)
    661 	/*
    662 	 * The SPARC ldd and std instructions require 8-byte alignment of
    663 	 * their address operand.  gcc correctly uses them only when the
    664 	 * ABI requires 8-byte alignment; unfortunately we have a number of
    665 	 * pieces of buggy code that doesn't conform to the ABI.  This
    666 	 * flag makes gcc work more like Studio with -xmemalign=4.
    667 	 */
    668 	newae(ctx->i_ae, "-mno-integer-ldd-std");
    669 #endif
    670 
    671 	/*
    672 	 * This is needed because 'u' is defined
    673 	 * under a conditional on 'sun'.  Should
    674 	 * probably just remove the conditional,
    675 	 * or make it be dependent on '__sun'.
    676 	 *
    677 	 * -Dunix is also missing in enhanced ANSI mode
    678 	 */
    679 	newae(ctx->i_ae, "-D__sun");
    680 
    681 	/*
    682 	 * Walk the argument list, translating as we go ..
    683 	 */
    684 
    685 	while (--ctx->i_oldargc > 0) {
    686 		char *arg = *++ctx->i_oldargv;
    687 		size_t arglen = strlen(arg);
    688 
    689 		if (*arg == '-') {
    690 			arglen--;
    691 		} else {
    692 			/*
    693 			 * Discard inline files that gcc doesn't grok
    694 			 */
    695 			if (!in_output && arglen > 3 &&
    696 			    strcmp(arg + arglen - 3, ".il") == 0)
    697 				continue;
    698 
    699 			if (!in_output && arglen > 2 &&
    700 			    arg[arglen - 2] == '.' &&
    701 			    (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' ||
    702 			    arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i'))
    703 				c_files++;
    704 
    705 			/*
    706 			 * Otherwise, filenames and partial arguments
    707 			 * are passed through for gcc to chew on.  However,
    708 			 * output is always discarded for the secondary
    709 			 * compiler.
    710 			 */
    711 			if ((ctx->i_flags & CW_F_SHADOW) && in_output)
    712 				newae(ctx->i_ae, ctx->i_discard);
    713 			else
    714 				newae(ctx->i_ae, arg);
    715 			in_output = 0;
    716 			continue;
    717 		}
    718 
    719 		if (ctx->i_flags & CW_F_CXX) {
    720 			if (strncmp(arg, "-compat=", 8) == 0) {
    721 				/* discard -compat=4 and -compat=5 */
    722 				continue;
    723 			}
    724 			if (strcmp(arg, "-Qoption") == 0) {
    725 				/* discard -Qoption and its two arguments */
    726 				if (ctx->i_oldargc < 3)
    727 					error(arg);
    728 				ctx->i_oldargc -= 2;
    729 				ctx->i_oldargv += 2;
    730 				continue;
    731 			}
    732 			if (strcmp(arg, "-xwe") == 0) {
    733 				/* turn warnings into errors */
    734 				newae(ctx->i_ae, "-Werror");
    735 				continue;
    736 			}
    737 			if (strcmp(arg, "-noex") == 0) {
    738 				/* no exceptions */
    739 				newae(ctx->i_ae, "-fno-exceptions");
    740 				/* no run time type descriptor information */
    741 				newae(ctx->i_ae, "-fno-rtti");
    742 				continue;
    743 			}
    744 			if (strcmp(arg, "-pic") == 0) {
    745 				newae(ctx->i_ae, "-fpic");
    746 				pic = 1;
    747 				continue;
    748 			}
    749 			if (strcmp(arg, "-PIC") == 0) {
    750 				newae(ctx->i_ae, "-fPIC");
    751 				pic = 1;
    752 				continue;
    753 			}
    754 			if (strcmp(arg, "-norunpath") == 0) {
    755 				/* gcc has no corresponding option */
    756 				continue;
    757 			}
    758 			if (strcmp(arg, "-nolib") == 0) {
    759 				/* -nodefaultlibs is on by default */
    760 				nolibc = 1;
    761 				continue;
    762 			}
    763 #if defined(__sparc)
    764 			if (strcmp(arg, "-cg92") == 0) {
    765 				mflag |= xlate_xtb(ctx->i_ae, "v8");
    766 				xlate(ctx->i_ae, "super", xchip_tbl);
    767 				continue;
    768 			}
    769 #endif	/* __sparc */
    770 		}
    771 
    772 		switch ((c = arg[1])) {
    773 		case '_':
    774 			if (strcmp(arg, "-_noecho") == 0)
    775 				ctx->i_flags &= ~CW_F_ECHO;
    776 			else if (strncmp(arg, "-_cc=", 5) == 0 ||
    777 			    strncmp(arg, "-_CC=", 5) == 0)
    778 				/* EMPTY */;
    779 			else if (strncmp(arg, "-_gcc=", 6) == 0 ||
    780 			    strncmp(arg, "-_g++=", 6) == 0)
    781 				newae(ctx->i_ae, arg + 6);
    782 			else
    783 				error(arg);
    784 			break;
    785 		case '#':
    786 			if (arglen == 1) {
    787 				newae(ctx->i_ae, "-v");
    788 				break;
    789 			}
    790 			error(arg);
    791 			break;
    792 		case 'g':
    793 			newae(ctx->i_ae, "-gdwarf-2");
    794 			break;
    795 		case 'E':
    796 			if (arglen == 1) {
    797 				newae(ctx->i_ae, "-xc");
    798 				newae(ctx->i_ae, arg);
    799 				op = CW_O_PREPROCESS;
    800 				nolibc = 1;
    801 				break;
    802 			}
    803 			error(arg);
    804 			break;
    805 		case 'c':
    806 		case 'S':
    807 			if (arglen == 1) {
    808 				op = CW_O_COMPILE;
    809 				nolibc = 1;
    810 			}
    811 			/* FALLTHROUGH */
    812 		case 'C':
    813 		case 'H':
    814 		case 'p':
    815 			if (arglen == 1) {
    816 				newae(ctx->i_ae, arg);
    817 				break;
    818 			}
    819 			error(arg);
    820 			break;
    821 		case 'A':
    822 		case 'h':
    823 		case 'I':
    824 		case 'i':
    825 		case 'L':
    826 		case 'l':
    827 		case 'R':
    828 		case 'U':
    829 		case 'u':
    830 		case 'w':
    831 			newae(ctx->i_ae, arg);
    832 			break;
    833 		case 'o':
    834 			seen_o = 1;
    835 			if (arglen == 1) {
    836 				in_output = 1;
    837 				newae(ctx->i_ae, arg);
    838 			} else if (ctx->i_flags & CW_F_SHADOW) {
    839 				newae(ctx->i_ae, "-o");
    840 				newae(ctx->i_ae, ctx->i_discard);
    841 			} else {
    842 				newae(ctx->i_ae, arg);
    843 			}
    844 			break;
    845 		case 'D':
    846 			newae(ctx->i_ae, arg);
    847 			/*
    848 			 * XXX	Clearly a hack ... do we need _KADB too?
    849 			 */
    850 			if (strcmp(arg, "-D_KERNEL") == 0 ||
    851 			    strcmp(arg, "-D_BOOT") == 0)
    852 				newae(ctx->i_ae, "-ffreestanding");
    853 			break;
    854 		case 'd':
    855 			if (arglen == 2) {
    856 				if (strcmp(arg, "-dy") == 0) {
    857 					newae(ctx->i_ae, "-Wl,-dy");
    858 					break;
    859 				}
    860 				if (strcmp(arg, "-dn") == 0) {
    861 					newae(ctx->i_ae, "-Wl,-dn");
    862 					break;
    863 				}
    864 			}
    865 			if (strcmp(arg, "-dalign") == 0) {
    866 				/*
    867 				 * -dalign forces alignment in some cases;
    868 				 * gcc does not need any flag to do this.
    869 				 */
    870 				break;
    871 			}
    872 			error(arg);
    873 			break;
    874 		case 'e':
    875 			if (strcmp(arg,
    876 			    "-erroff=E_EMPTY_TRANSLATION_UNIT") == 0) {
    877 				/*
    878 				 * Accept but ignore this -- gcc doesn't
    879 				 * seem to complain about empty translation
    880 				 * units
    881 				 */
    882 				break;
    883 			}
    884 			/* XX64 -- ignore all -erroff= options, for now */
    885 			if (strncmp(arg, "-erroff=", 8) == 0)
    886 				break;
    887 			if (strcmp(arg, "-errtags=yes") == 0) {
    888 				warnings(ctx->i_ae);
    889 				break;
    890 			}
    891 			if (strcmp(arg, "-errwarn=%all") == 0) {
    892 				newae(ctx->i_ae, "-Werror");
    893 				break;
    894 			}
    895 			error(arg);
    896 			break;
    897 		case 'f':
    898 			if (strcmp(arg, "-flags") == 0) {
    899 				newae(ctx->i_ae, "--help");
    900 				break;
    901 			}
    902 			if (strncmp(arg, "-features=zla", 13) == 0) {
    903 				/*
    904 				 * Accept but ignore this -- gcc allows
    905 				 * zero length arrays.
    906 				 */
    907 				break;
    908 			}
    909 			error(arg);
    910 			break;
    911 		case 'G':
    912 			newae(ctx->i_ae, "-shared");
    913 			nolibc = 1;
    914 			break;
    915 		case 'k':
    916 			if (strcmp(arg, "-keeptmp") == 0) {
    917 				newae(ctx->i_ae, "-save-temps");
    918 				break;
    919 			}
    920 			error(arg);
    921 			break;
    922 		case 'K':
    923 			if (arglen == 1) {
    924 				if ((arg = *++ctx->i_oldargv) == NULL ||
    925 				    *arg == '\0')
    926 					error("-K");
    927 				ctx->i_oldargc--;
    928 			} else {
    929 				arg += 2;
    930 			}
    931 			if (strcmp(arg, "pic") == 0) {
    932 				newae(ctx->i_ae, "-fpic");
    933 				pic = 1;
    934 				break;
    935 			}
    936 			if (strcmp(arg, "PIC") == 0) {
    937 				newae(ctx->i_ae, "-fPIC");
    938 				pic = 1;
    939 				break;
    940 			}
    941 			error("-K");
    942 			break;
    943 		case 'm':
    944 			if (strcmp(arg, "-mt") == 0) {
    945 				newae(ctx->i_ae, "-D_REENTRANT");
    946 				break;
    947 			}
    948 			if (strcmp(arg, "-m64") == 0) {
    949 				newae(ctx->i_ae, "-m64");
    950 #if defined(__x86)
    951 				newae(ctx->i_ae, "-mtune=opteron");
    952 #endif
    953 				mflag |= M64;
    954 				break;
    955 			}
    956 			if (strcmp(arg, "-m32") == 0) {
    957 				newae(ctx->i_ae, "-m32");
    958 				mflag |= M32;
    959 				break;
    960 			}
    961 			error(arg);
    962 			break;
    963 		case 'B':	/* linker options */
    964 		case 'M':
    965 		case 'z':
    966 			{
    967 				char *opt;
    968 				size_t len;
    969 				char *s;
    970 
    971 				if (arglen == 1) {
    972 					opt = *++ctx->i_oldargv;
    973 					if (opt == NULL || *opt == '\0')
    974 						error(arg);
    975 					ctx->i_oldargc--;
    976 				} else {
    977 					opt = arg + 2;
    978 				}
    979 				len = strlen(opt) + 7;
    980 				if ((s = malloc(len)) == NULL)
    981 					nomem();
    982 				(void) snprintf(s, len, "-Wl,-%c%s", c, opt);
    983 				newae(ctx->i_ae, s);
    984 				free(s);
    985 			}
    986 			break;
    987 		case 'n':
    988 			if (strcmp(arg, "-noqueue") == 0) {
    989 				/*
    990 				 * Horrid license server stuff - n/a
    991 				 */
    992 				break;
    993 			}
    994 			error(arg);
    995 			break;
    996 		case 'O':
    997 			if (arglen == 1) {
    998 				newae(ctx->i_ae, "-O");
    999 				break;
   1000 			}
   1001 			error(arg);
   1002 			break;
   1003 		case 'P':
   1004 			/*
   1005 			 * We could do '-E -o filename.i', but that's hard,
   1006 			 * and we don't need it for the case that's triggering
   1007 			 * this addition.  We'll require the user to specify
   1008 			 * -o in the Makefile.  If they don't they'll find out
   1009 			 * in a hurry.
   1010 			 */
   1011 			newae(ctx->i_ae, "-E");
   1012 			op = CW_O_PREPROCESS;
   1013 			nolibc = 1;
   1014 			break;
   1015 		case 'q':
   1016 			if (strcmp(arg, "-qp") == 0) {
   1017 				newae(ctx->i_ae, "-p");
   1018 				break;
   1019 			}
   1020 			error(arg);
   1021 			break;
   1022 		case 's':
   1023 			if (arglen == 1) {
   1024 				newae(ctx->i_ae, "-Wl,-s");
   1025 				break;
   1026 			}
   1027 			error(arg);
   1028 			break;
   1029 		case 't':
   1030 			if (arglen == 1) {
   1031 				newae(ctx->i_ae, "-Wl,-t");
   1032 				break;
   1033 			}
   1034 			error(arg);
   1035 			break;
   1036 		case 'V':
   1037 			if (arglen == 1) {
   1038 				ctx->i_flags &= ~CW_F_ECHO;
   1039 				newae(ctx->i_ae, "--version");
   1040 				break;
   1041 			}
   1042 			error(arg);
   1043 			break;
   1044 		case 'v':
   1045 			if (arglen == 1) {
   1046 				warnings(ctx->i_ae);
   1047 				break;
   1048 			}
   1049 			error(arg);
   1050 			break;
   1051 		case 'W':
   1052 			if (strncmp(arg, "-Wp,-xc99", 9) == 0) {
   1053 				/*
   1054 				 * gcc's preprocessor will accept c99
   1055 				 * regardless, so accept and ignore.
   1056 				 */
   1057 				break;
   1058 			}
   1059 			if (strncmp(arg, "-Wa,", 4) == 0 ||
   1060 			    strncmp(arg, "-Wp,", 4) == 0 ||
   1061 			    strncmp(arg, "-Wl,", 4) == 0) {
   1062 				newae(ctx->i_ae, arg);
   1063 				break;
   1064 			}
   1065 			if (strcmp(arg, "-W0,-xc99=pragma") == 0) {
   1066 				/* (undocumented) enables _Pragma */
   1067 				break;
   1068 			}
   1069 			if (strcmp(arg, "-W0,-xc99=%none") == 0) {
   1070 				/*
   1071 				 * This is a polite way of saying
   1072 				 * "no c99 constructs allowed!"
   1073 				 * For now, just accept and ignore this.
   1074 				 */
   1075 				break;
   1076 			}
   1077 			if (strcmp(arg, "-W0,-noglobal") == 0 ||
   1078 			    strcmp(arg, "-W0,-xglobalstatic") == 0) {
   1079 				/*
   1080 				 * gcc doesn't prefix local symbols
   1081 				 * in debug mode, so this is not needed.
   1082 				 */
   1083 				break;
   1084 			}
   1085 			if (strcmp(arg, "-W0,-Lt") == 0) {
   1086 				/*
   1087 				 * Generate tests at the top of loops.
   1088 				 * There is no direct gcc equivalent, ignore.
   1089 				 */
   1090 				break;
   1091 			}
   1092 			if (strcmp(arg, "-W0,-xdbggen=no%usedonly") == 0) {
   1093 				newae(ctx->i_ae,
   1094 				    "-fno-eliminate-unused-debug-symbols");
   1095 				newae(ctx->i_ae,
   1096 				    "-fno-eliminate-unused-debug-types");
   1097 				break;
   1098 			}
   1099 			if (strcmp(arg, "-W2,-xwrap_int") == 0) {
   1100 				/*
   1101 				 * Use the legacy behaviour (pre-SS11)
   1102 				 * for integer wrapping.
   1103 				 * gcc does not need this.
   1104 				 */
   1105 				break;
   1106 			}
   1107 			if (strcmp(arg, "-W2,-Rcond_elim") == 0) {
   1108 				/*
   1109 				 * Elimination and expansion of conditionals;
   1110 				 * gcc has no direct equivalent.
   1111 				 */
   1112 				break;
   1113 			}
   1114 			if (strcmp(arg, "-Wd,-xsafe=unboundsym") == 0) {
   1115 				/*
   1116 				 * Prevents optimizing away checks for
   1117 				 * unbound weak symbol addresses.  gcc does
   1118 				 * not do this, so it's not needed.
   1119 				 */
   1120 				break;
   1121 			}
   1122 			if (strncmp(arg, "-Wc,-xcode=", 11) == 0) {
   1123 				xlate(ctx->i_ae, arg + 11, xcode_tbl);
   1124 				if (strncmp(arg + 11, "pic", 3) == 0)
   1125 					pic = 1;
   1126 				break;
   1127 			}
   1128 			if (strncmp(arg, "-Wc,-Qiselect", 13) == 0) {
   1129 				/*
   1130 				 * Prevents insertion of register symbols.
   1131 				 * gcc doesn't do this, so ignore it.
   1132 				 */
   1133 				break;
   1134 			}
   1135 			if (strcmp(arg, "-Wc,-Qassembler-ounrefsym=0") == 0) {
   1136 				/*
   1137 				 * Prevents optimizing away of static variables.
   1138 				 * gcc does not do this, so it's not needed.
   1139 				 */
   1140 				break;
   1141 			}
   1142 #if defined(__x86)
   1143 			if (strcmp(arg, "-Wu,-no_got_reloc") == 0) {
   1144 				newae(ctx->i_ae, "-fno-jump-tables");
   1145 				newae(ctx->i_ae, "-fno-constant-pools");
   1146 				break;
   1147 			}
   1148 			if (strcmp(arg, "-Wu,-xmodel=kernel") == 0) {
   1149 				newae(ctx->i_ae, "-ffreestanding");
   1150 				newae(ctx->i_ae, "-mno-red-zone");
   1151 				model = "-mcmodel=kernel";
   1152 				nolibc = 1;
   1153 				break;
   1154 			}
   1155 			if (strcmp(arg, "-Wu,-save_args") == 0) {
   1156 				newae(ctx->i_ae, "-msave-args");
   1157 				break;
   1158 			}
   1159 #endif	/* __x86 */
   1160 			error(arg);
   1161 			break;
   1162 		case 'X':
   1163 			if (strcmp(arg, "-Xa") == 0 ||
   1164 			    strcmp(arg, "-Xt") == 0) {
   1165 				Xamode(ctx->i_ae);
   1166 				break;
   1167 			}
   1168 			if (strcmp(arg, "-Xc") == 0) {
   1169 				Xcmode(ctx->i_ae);
   1170 				break;
   1171 			}
   1172 			if (strcmp(arg, "-Xs") == 0) {
   1173 				Xsmode(ctx->i_ae);
   1174 				break;
   1175 			}
   1176 			error(arg);
   1177 			break;
   1178 		case 'x':
   1179 			if (arglen == 1)
   1180 				error(arg);
   1181 			switch (arg[2]) {
   1182 #if defined(__x86)
   1183 			case '3':
   1184 				if (strcmp(arg, "-x386") == 0) {
   1185 					newae(ctx->i_ae, "-march=i386");
   1186 					break;
   1187 				}
   1188 				error(arg);
   1189 				break;
   1190 			case '4':
   1191 				if (strcmp(arg, "-x486") == 0) {
   1192 					newae(ctx->i_ae, "-march=i486");
   1193 					break;
   1194 				}
   1195 				error(arg);
   1196 				break;
   1197 #endif	/* __x86 */
   1198 			case 'a':
   1199 				if (strncmp(arg, "-xarch=", 7) == 0) {
   1200 					mflag |= xlate_xtb(ctx->i_ae, arg + 7);
   1201 					break;
   1202 				}
   1203 				error(arg);
   1204 				break;
   1205 			case 'b':
   1206 				if (strncmp(arg, "-xbuiltin=", 10) == 0) {
   1207 					if (strcmp(arg + 10, "%all"))
   1208 						newae(ctx->i_ae, "-fbuiltin");
   1209 					break;
   1210 				}
   1211 				error(arg);
   1212 				break;
   1213 			case 'C':
   1214 				/* Accept C++ style comments -- ignore */
   1215 				if (strcmp(arg, "-xCC") == 0)
   1216 					break;
   1217 				error(arg);
   1218 				break;
   1219 			case 'c':
   1220 				if (strncmp(arg, "-xc99=%all", 10) == 0) {
   1221 					newae(ctx->i_ae, "-std=gnu99");
   1222 					break;
   1223 				}
   1224 				if (strncmp(arg, "-xc99=%none", 11) == 0) {
   1225 					newae(ctx->i_ae, "-std=gnu89");
   1226 					break;
   1227 				}
   1228 				if (strncmp(arg, "-xchip=", 7) == 0) {
   1229 					xlate(ctx->i_ae, arg + 7, xchip_tbl);
   1230 					break;
   1231 				}
   1232 				if (strncmp(arg, "-xcode=", 7) == 0) {
   1233 					xlate(ctx->i_ae, arg + 7, xcode_tbl);
   1234 					if (strncmp(arg + 7, "pic", 3) == 0)
   1235 						pic = 1;
   1236 					break;
   1237 				}
   1238 				if (strncmp(arg, "-xcache=", 8) == 0)
   1239 					break;
   1240 				if (strncmp(arg, "-xcrossfile", 11) == 0)
   1241 					break;
   1242 				error(arg);
   1243 				break;
   1244 			case 'd':
   1245 				if (strcmp(arg, "-xdepend") == 0)
   1246 					break;
   1247 				if (strncmp(arg, "-xdebugformat=", 14) == 0)
   1248 					break;
   1249 				error(arg);
   1250 				break;
   1251 			case 'F':
   1252 				/*
   1253 				 * Compile for mapfile reordering, or unused
   1254 				 * section elimination, syntax can be -xF or
   1255 				 * more complex, like -xF=%all -- ignore.
   1256 				 */
   1257 				if (strncmp(arg, "-xF", 3) == 0)
   1258 					break;
   1259 				error(arg);
   1260 				break;
   1261 			case 'i':
   1262 				if (strncmp(arg, "-xinline", 8) == 0)
   1263 					/* No inlining; ignore */
   1264 					break;
   1265 				if (strcmp(arg, "-xildon") == 0 ||
   1266 				    strcmp(arg, "-xildoff") == 0)
   1267 					/* No incremental linking; ignore */
   1268 					break;
   1269 				error(arg);
   1270 				break;
   1271 #if defined(__x86)
   1272 			case 'm':
   1273 				if (strcmp(arg, "-xmodel=kernel") == 0) {
   1274 					newae(ctx->i_ae, "-ffreestanding");
   1275 					newae(ctx->i_ae, "-mno-red-zone");
   1276 					model = "-mcmodel=kernel";
   1277 					nolibc = 1;
   1278 					break;
   1279 				}
   1280 				error(arg);
   1281 				break;
   1282 #endif	/* __x86 */
   1283 			case 'M':
   1284 				if (strcmp(arg, "-xM") == 0) {
   1285 					newae(ctx->i_ae, "-M");
   1286 					break;
   1287 				}
   1288 				if (strcmp(arg, "-xM1") == 0) {
   1289 					newae(ctx->i_ae, "-MM");
   1290 					break;
   1291 				}
   1292 				error(arg);
   1293 				break;
   1294 			case 'n':
   1295 				if (strcmp(arg, "-xnolib") == 0) {
   1296 					nolibc = 1;
   1297 					break;
   1298 				}
   1299 				error(arg);
   1300 				break;
   1301 			case 'O':
   1302 				if (strncmp(arg, "-xO", 3) == 0) {
   1303 					size_t len = strlen(arg);
   1304 					char *s;
   1305 					int c = *(arg + 3);
   1306 					int level;
   1307 
   1308 					if (len != 4 || !isdigit(c))
   1309 						error(arg);
   1310 
   1311 					if ((s = malloc(len)) == NULL)
   1312 						nomem();
   1313 
   1314 					level = atoi(arg + 3);
   1315 					if (level > 5)
   1316 						error(arg);
   1317 					if (level >= 2) {
   1318 						/*
   1319 						 * For gcc-3.4.x at -O2 we
   1320 						 * need to disable optimizations
   1321 						 * that break ON.
   1322 						 */
   1323 						optim_disable(ctx->i_ae, level);
   1324 						/*
   1325 						 * limit -xO3 to -O2 as well.
   1326 						 */
   1327 						level = 2;
   1328 					}
   1329 					(void) snprintf(s, len, "-O%d", level);
   1330 					newae(ctx->i_ae, s);
   1331 					free(s);
   1332 					break;
   1333 				}
   1334 				error(arg);
   1335 				break;
   1336 			case 'p':
   1337 				if (strcmp(arg, "-xpentium") == 0) {
   1338 					newae(ctx->i_ae, "-march=pentium");
   1339 					break;
   1340 				}
   1341 				if (strcmp(arg, "-xpg") == 0) {
   1342 					newae(ctx->i_ae, "-pg");
   1343 					break;
   1344 				}
   1345 				error(arg);
   1346 				break;
   1347 			case 'r':
   1348 				if (strncmp(arg, "-xregs=", 7) == 0) {
   1349 					xlate(ctx->i_ae, arg + 7, xregs_tbl);
   1350 					break;
   1351 				}
   1352 				error(arg);
   1353 				break;
   1354 			case 's':
   1355 				if (strcmp(arg, "-xs") == 0 ||
   1356 				    strcmp(arg, "-xspace") == 0 ||
   1357 				    strcmp(arg, "-xstrconst") == 0)
   1358 					break;
   1359 				error(arg);
   1360 				break;
   1361 			case 't':
   1362 				if (strcmp(arg, "-xtransition") == 0) {
   1363 					newae(ctx->i_ae, "-Wtransition");
   1364 					break;
   1365 				}
   1366 				if (strcmp(arg, "-xtrigraphs=yes") == 0) {
   1367 					newae(ctx->i_ae, "-trigraphs");
   1368 					break;
   1369 				}
   1370 				if (strcmp(arg, "-xtrigraphs=no") == 0) {
   1371 					newae(ctx->i_ae, "-notrigraphs");
   1372 					break;
   1373 				}
   1374 				if (strncmp(arg, "-xtarget=", 9) == 0) {
   1375 					xlate(ctx->i_ae, arg + 9, xtarget_tbl);
   1376 					break;
   1377 				}
   1378 				error(arg);
   1379 				break;
   1380 			case 'e':
   1381 			case 'h':
   1382 			case 'l':
   1383 			default:
   1384 				error(arg);
   1385 				break;
   1386 			}
   1387 			break;
   1388 		case 'Y':
   1389 			if (arglen == 1) {
   1390 				if ((arg = *++ctx->i_oldargv) == NULL ||
   1391 				    *arg == '\0')
   1392 					error("-Y");
   1393 				ctx->i_oldargc--;
   1394 				arglen = strlen(arg + 1);
   1395 			} else {
   1396 				arg += 2;
   1397 			}
   1398 			/* Just ignore -YS,... for now */
   1399 			if (strncmp(arg, "S,", 2) == 0)
   1400 				break;
   1401 			if (strncmp(arg, "l,", 2) == 0) {
   1402 				char *s = strdup(arg);
   1403 				s[0] = '-';
   1404 				s[1] = 'B';
   1405 				newae(ctx->i_ae, s);
   1406 				free(s);
   1407 				break;
   1408 			}
   1409 			if (strncmp(arg, "I,", 2) == 0) {
   1410 				char *s = strdup(arg);
   1411 				s[0] = '-';
   1412 				s[1] = 'I';
   1413 				newae(ctx->i_ae, "-nostdinc");
   1414 				newae(ctx->i_ae, s);
   1415 				free(s);
   1416 				break;
   1417 			}
   1418 			error(arg);
   1419 			break;
   1420 		case 'Q':
   1421 			/*
   1422 			 * We could map -Qy into -Wl,-Qy etc.
   1423 			 */
   1424 		default:
   1425 			error(arg);
   1426 			break;
   1427 		}
   1428 	}
   1429 
   1430 	if (c_files > 1 && (ctx->i_flags & CW_F_SHADOW) &&
   1431 	    op != CW_O_PREPROCESS) {
   1432 		(void) fprintf(stderr, "%s: error: multiple source files are "
   1433 		    "allowed only with -E or -P\n", progname);
   1434 		exit(2);
   1435 	}
   1436 
   1437 	/*
   1438 	 * Make sure that we do not have any unintended interactions between
   1439 	 * the xarch options passed in and the version of the Studio compiler
   1440 	 * used.
   1441 	 */
   1442 	if ((mflag & (SS11|SS12)) == (SS11|SS12)) {
   1443 		(void) fprintf(stderr,
   1444 		    "Conflicting \"-xarch=\" flags (both Studio 11 and 12)\n");
   1445 		exit(2);
   1446 	}
   1447 
   1448 	switch (mflag) {
   1449 	case 0:
   1450 		/* FALLTHROUGH */
   1451 	case M32:
   1452 #if defined(__sparc)
   1453 		/*
   1454 		 * Only -m32 is defined and so put in the missing xarch
   1455 		 * translation.
   1456 		 */
   1457 		newae(ctx->i_ae, "-mcpu=v8");
   1458 		newae(ctx->i_ae, "-mno-v8plus");
   1459 #endif
   1460 		break;
   1461 	case M64:
   1462 #if defined(__sparc)
   1463 		/*
   1464 		 * Only -m64 is defined and so put in the missing xarch
   1465 		 * translation.
   1466 		 */
   1467 		newae(ctx->i_ae, "-mcpu=v9");
   1468 #endif
   1469 		break;
   1470 	case SS12:
   1471 #if defined(__sparc)
   1472 		/* no -m32/-m64 flag used - this is an error for sparc builds */
   1473 		(void) fprintf(stderr, "No -m32/-m64 flag defined\n");
   1474 		exit(2);
   1475 #endif
   1476 		break;
   1477 	case SS11:
   1478 		/* FALLTHROUGH */
   1479 	case (SS11|M32):
   1480 	case (SS11|M64):
   1481 		break;
   1482 	case (SS12|M32):
   1483 #if defined(__sparc)
   1484 		/*
   1485 		 * Need to add in further 32 bit options because with SS12
   1486 		 * the xarch=sparcvis option can be applied to 32 or 64
   1487 		 * bit, and so the translatation table (xtbl) cannot handle
   1488 		 * that.
   1489 		 */
   1490 		newae(ctx->i_ae, "-mv8plus");
   1491 #endif
   1492 		break;
   1493 	case (SS12|M64):
   1494 		break;
   1495 	default:
   1496 		(void) fprintf(stderr,
   1497 		    "Incompatible -xarch= and/or -m32/-m64 options used.\n");
   1498 		exit(2);
   1499 	}
   1500 	if (op == CW_O_LINK && (ctx->i_flags & CW_F_SHADOW))
   1501 		exit(0);
   1502 
   1503 	if (model && !pic)
   1504 		newae(ctx->i_ae, model);
   1505 	if (!nolibc)
   1506 		newae(ctx->i_ae, "-lc");
   1507 	if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
   1508 		newae(ctx->i_ae, "-o");
   1509 		newae(ctx->i_ae, ctx->i_discard);
   1510 	}
   1511 }
   1512 
   1513 static void
   1514 do_cc(cw_ictx_t *ctx)
   1515 {
   1516 	int in_output = 0, seen_o = 0;
   1517 	cw_op_t op = CW_O_LINK;
   1518 
   1519 	if (ctx->i_flags & CW_F_PROG) {
   1520 		newae(ctx->i_ae, "-V");
   1521 		return;
   1522 	}
   1523 
   1524 	while (--ctx->i_oldargc > 0) {
   1525 		char *arg = *++ctx->i_oldargv;
   1526 
   1527 		if (*arg != '-') {
   1528 			if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) {
   1529 				newae(ctx->i_ae, arg);
   1530 			} else {
   1531 				in_output = 0;
   1532 				newae(ctx->i_ae, ctx->i_discard);
   1533 			}
   1534 			continue;
   1535 		}
   1536 		switch (*(arg + 1)) {
   1537 		case '_':
   1538 			if (strcmp(arg, "-_noecho") == 0) {
   1539 				ctx->i_flags &= ~CW_F_ECHO;
   1540 			} else if (strncmp(arg, "-_cc=", 5) == 0 ||
   1541 			    strncmp(arg, "-_CC=", 5) == 0) {
   1542 				newae(ctx->i_ae, arg + 5);
   1543 			} else if (strncmp(arg, "-_gcc=", 6) != 0 &&
   1544 			    strncmp(arg, "-_g++=", 6) != 0) {
   1545 				(void) fprintf(stderr,
   1546 				    "%s: invalid argument '%s'\n", progname,
   1547 				    arg);
   1548 				exit(2);
   1549 			}
   1550 			break;
   1551 		case 'V':
   1552 			ctx->i_flags &= ~CW_F_ECHO;
   1553 			newae(ctx->i_ae, arg);
   1554 			break;
   1555 		case 'o':
   1556 			seen_o = 1;
   1557 			if (strlen(arg) == 2) {
   1558 				in_output = 1;
   1559 				newae(ctx->i_ae, arg);
   1560 			} else if (ctx->i_flags & CW_F_SHADOW) {
   1561 				newae(ctx->i_ae, "-o");
   1562 				newae(ctx->i_ae, ctx->i_discard);
   1563 			} else {
   1564 				newae(ctx->i_ae, arg);
   1565 			}
   1566 			break;
   1567 		case 'c':
   1568 		case 'S':
   1569 			if (strlen(arg) == 2)
   1570 				op = CW_O_COMPILE;
   1571 			newae(ctx->i_ae, arg);
   1572 			break;
   1573 		case 'E':
   1574 		case 'P':
   1575 			if (strlen(arg) == 2)
   1576 				op = CW_O_PREPROCESS;
   1577 		/*FALLTHROUGH*/
   1578 		default:
   1579 			newae(ctx->i_ae, arg);
   1580 		}
   1581 	}
   1582 
   1583 	if ((op == CW_O_LINK || op == CW_O_PREPROCESS) &&
   1584 	    (ctx->i_flags & CW_F_SHADOW))
   1585 		exit(0);
   1586 
   1587 	if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
   1588 		newae(ctx->i_ae, "-o");
   1589 		newae(ctx->i_ae, ctx->i_discard);
   1590 	}
   1591 }
   1592 
   1593 static void
   1594 prepctx(cw_ictx_t *ctx)
   1595 {
   1596 	const char *dir, *cmd;
   1597 	char *program;
   1598 	size_t len;
   1599 
   1600 	dir = dirs[CIDX(CC(ctx), ctx->i_flags)];
   1601 	cmd = cmds[CIDX(CC(ctx), ctx->i_flags)];
   1602 	len = strlen(dir) + strlen(cmd) + 2;
   1603 	if ((program = malloc(len)) == NULL)
   1604 		nomem();
   1605 	(void) snprintf(program, len, "%s/%s", dir, cmd);
   1606 
   1607 	newae(ctx->i_ae, program);
   1608 
   1609 	if (ctx->i_flags & CW_F_PROG) {
   1610 		(void) printf("%s: %s\n", (ctx->i_flags & CW_F_SHADOW) ?
   1611 		    "shadow" : "primary", program);
   1612 		(void) fflush(stdout);
   1613 	}
   1614 
   1615 	if (!(ctx->i_flags & CW_F_XLATE))
   1616 		return;
   1617 
   1618 	switch (CC(ctx)) {
   1619 	case CW_C_CC:
   1620 		do_cc(ctx);
   1621 		break;
   1622 	case CW_C_GCC:
   1623 		do_gcc(ctx);
   1624 		break;
   1625 	}
   1626 }
   1627 
   1628 static int
   1629 invoke(cw_ictx_t *ctx)
   1630 {
   1631 	char **newargv;
   1632 	int ac;
   1633 	struct ae *a;
   1634 
   1635 	if ((newargv = calloc(sizeof (*newargv), ctx->i_ae->ael_argc + 1)) ==
   1636 	    NULL)
   1637 		nomem();
   1638 
   1639 	if (ctx->i_flags & CW_F_ECHO)
   1640 		(void) fprintf(stderr, "+ ");
   1641 
   1642 	for (ac = 0, a = ctx->i_ae->ael_head; a; a = a->ae_next, ac++) {
   1643 		newargv[ac] = a->ae_arg;
   1644 		if (ctx->i_flags & CW_F_ECHO)
   1645 			(void) fprintf(stderr, "%s ", a->ae_arg);
   1646 		if (a == ctx->i_ae->ael_tail)
   1647 			break;
   1648 	}
   1649 
   1650 	if (ctx->i_flags & CW_F_ECHO) {
   1651 		(void) fprintf(stderr, "\n");
   1652 		(void) fflush(stderr);
   1653 	}
   1654 
   1655 	if (!(ctx->i_flags & CW_F_EXEC))
   1656 		return (0);
   1657 
   1658 	/*
   1659 	 * We must fix up the environment here so that the
   1660 	 * dependency files are not trampled by the shadow compiler.
   1661 	 */
   1662 	if ((ctx->i_flags & CW_F_SHADOW) &&
   1663 	    (unsetenv("SUNPRO_DEPENDENCIES") != 0 ||
   1664 	    unsetenv("DEPENDENCIES_OUTPUT") != 0)) {
   1665 		(void) fprintf(stderr, "error: environment setup failed: %s\n",
   1666 		    strerror(errno));
   1667 		return (-1);
   1668 	}
   1669 
   1670 	(void) execv(newargv[0], newargv);
   1671 	cw_perror("couldn't run %s", newargv[0]);
   1672 
   1673 	return (-1);
   1674 }
   1675 
   1676 static int
   1677 reap(cw_ictx_t *ctx)
   1678 {
   1679 	int status, ret = 0;
   1680 	char buf[1024];
   1681 	struct stat s;
   1682 
   1683 	/*
   1684 	 * Only wait for one specific child.
   1685 	 */
   1686 	if (ctx->i_pid <= 0)
   1687 		return (-1);
   1688 
   1689 	do {
   1690 		if (waitpid(ctx->i_pid, &status, 0) < 0) {
   1691 			cw_perror("cannot reap child");
   1692 			return (-1);
   1693 		}
   1694 		if (status != 0) {
   1695 			if (WIFSIGNALED(status)) {
   1696 				ret = -WTERMSIG(status);
   1697 				break;
   1698 			} else if (WIFEXITED(status)) {
   1699 				ret = WEXITSTATUS(status);
   1700 				break;
   1701 			}
   1702 		}
   1703 	} while (!WIFEXITED(status) && !WIFSIGNALED(status));
   1704 
   1705 	(void) unlink(ctx->i_discard);
   1706 
   1707 	if (stat(ctx->i_stderr, &s) < 0) {
   1708 		cw_perror("stat failed on child cleanup");
   1709 		return (-1);
   1710 	}
   1711 	if (s.st_size != 0) {
   1712 		FILE *f;
   1713 
   1714 		if ((f = fopen(ctx->i_stderr, "r")) != NULL) {
   1715 			while (fgets(buf, sizeof (buf), f))
   1716 				(void) fprintf(stderr, "%s", buf);
   1717 			(void) fflush(stderr);
   1718 			(void) fclose(f);
   1719 		}
   1720 	}
   1721 	(void) unlink(ctx->i_stderr);
   1722 	free(ctx->i_stderr);
   1723 
   1724 	/*
   1725 	 * cc returns an error code when given -V; we want that to succeed.
   1726 	 */
   1727 	if (ctx->i_flags & CW_F_PROG)
   1728 		return (0);
   1729 
   1730 	return (ret);
   1731 }
   1732 
   1733 static int
   1734 exec_ctx(cw_ictx_t *ctx, int block)
   1735 {
   1736 	char *file;
   1737 
   1738 	/*
   1739 	 * To avoid offending cc's sensibilities, the name of its output
   1740 	 * file must end in '.o'.
   1741 	 */
   1742 	if ((file = tempnam(NULL, ".cw")) == NULL) {
   1743 		nomem();
   1744 		return (-1);
   1745 	}
   1746 	(void) strlcpy(ctx->i_discard, file, MAXPATHLEN);
   1747 	(void) strlcat(ctx->i_discard, ".o", MAXPATHLEN);
   1748 	free(file);
   1749 
   1750 	if ((ctx->i_stderr = tempnam(NULL, ".cw")) == NULL) {
   1751 		nomem();
   1752 		return (-1);
   1753 	}
   1754 
   1755 	if ((ctx->i_pid = fork()) == 0) {
   1756 		int fd;
   1757 
   1758 		(void) fclose(stderr);
   1759 		if ((fd = open(ctx->i_stderr, O_WRONLY | O_CREAT | O_EXCL,
   1760 		    0666)) < 0) {
   1761 			cw_perror("open failed for standard error");
   1762 			exit(1);
   1763 		}
   1764 		if (dup2(fd, 2) < 0) {
   1765 			cw_perror("dup2 failed for standard error");
   1766 			exit(1);
   1767 		}
   1768 		if (fd != 2)
   1769 			(void) close(fd);
   1770 		if (freopen("/dev/fd/2", "w", stderr) == NULL) {
   1771 			cw_perror("freopen failed for /dev/fd/2");
   1772 			exit(1);
   1773 		}
   1774 		prepctx(ctx);
   1775 		exit(invoke(ctx));
   1776 	}
   1777 
   1778 	if (ctx->i_pid < 0) {
   1779 		cw_perror("fork failed");
   1780 		return (1);
   1781 	}
   1782 
   1783 	if (block)
   1784 		return (reap(ctx));
   1785 
   1786 	return (0);
   1787 }
   1788 
   1789 int
   1790 main(int argc, char **argv)
   1791 {
   1792 	cw_ictx_t *ctx = newictx();
   1793 	cw_ictx_t *ctx_shadow = newictx();
   1794 	const char *dir;
   1795 	char cc_buf[MAXPATHLEN], gcc_buf[MAXPATHLEN];
   1796 	int do_serial, do_shadow;
   1797 	int ret = 0;
   1798 
   1799 	if ((progname = strrchr(argv[0], '/')) == NULL)
   1800 		progname = argv[0];
   1801 	else
   1802 		progname++;
   1803 
   1804 	if (ctx == NULL || ctx_shadow == NULL)
   1805 		nomem();
   1806 
   1807 	ctx->i_flags = CW_F_ECHO|CW_F_XLATE;
   1808 
   1809 	/*
   1810 	 * Figure out where to get our tools from.  This depends on
   1811 	 * the environment variables set at run time.
   1812 	 */
   1813 	if ((dir = getenv("SPRO_VROOT")) != NULL) {
   1814 		(void) snprintf(cc_buf, MAXPATHLEN, "%s/bin", dir);
   1815 	} else if ((dir = getenv("SPRO_ROOT")) != NULL) {
   1816 		(void) snprintf(cc_buf, MAXPATHLEN, "%s/SS12/bin", dir);
   1817 	} else if ((dir = getenv("BUILD_TOOLS")) != NULL) {
   1818 		(void) snprintf(cc_buf, MAXPATHLEN,
   1819 		    "%s/SUNWspro/SS12/bin", dir);
   1820 	}
   1821 	if (dir != NULL) {
   1822 		dirs[CIDX(CW_C_CC, 0)] = (const char *)cc_buf;
   1823 		dirs[CIDX(CW_C_CC, CW_F_CXX)] = (const char *)cc_buf;
   1824 	}
   1825 
   1826 	if ((dir = getenv("GNU_ROOT")) != NULL) {
   1827 		(void) snprintf(gcc_buf, MAXPATHLEN, "%s/bin", dir);
   1828 		dirs[CIDX(CW_C_GCC, 0)] = (const char *)gcc_buf;
   1829 		dirs[CIDX(CW_C_GCC, CW_F_CXX)] = (const char *)gcc_buf;
   1830 	}
   1831 
   1832 	if ((dir = getenv("CW_CC_DIR")) != NULL)
   1833 		dirs[CIDX(CW_C_CC, 0)] = dir;
   1834 	if ((dir = getenv("CW_CPLUSPLUS_DIR")) != NULL)
   1835 		dirs[CIDX(CW_C_CC, CW_F_CXX)] = dir;
   1836 	if ((dir = getenv("CW_GCC_DIR")) != NULL)
   1837 		dirs[CIDX(CW_C_GCC, 0)] = dir;
   1838 	if ((dir = getenv("CW_GPLUSPLUS_DIR")) != NULL)
   1839 		dirs[CIDX(CW_C_GCC, CW_F_CXX)] = dir;
   1840 
   1841 	do_shadow = (getenv("CW_NO_SHADOW") ? 0 : 1);
   1842 	do_serial = (getenv("CW_SHADOW_SERIAL") ? 1 : 0);
   1843 
   1844 	if (getenv("CW_NO_EXEC") == NULL)
   1845 		ctx->i_flags |= CW_F_EXEC;
   1846 
   1847 	/*
   1848 	 * The first argument must be one of "-_cc", "-_gcc", "-_CC", or "-_g++"
   1849 	 */
   1850 	if (argc == 1)
   1851 		usage();
   1852 	argc--;
   1853 	argv++;
   1854 	if (strcmp(argv[0], "-_cc") == 0) {
   1855 		ctx->i_compiler = CW_C_CC;
   1856 	} else if (strcmp(argv[0], "-_gcc") == 0) {
   1857 		ctx->i_compiler = CW_C_GCC;
   1858 	} else if (strcmp(argv[0], "-_CC") == 0) {
   1859 		ctx->i_compiler = CW_C_CC;
   1860 		ctx->i_flags |= CW_F_CXX;
   1861 	} else if (strcmp(argv[0], "-_g++") == 0) {
   1862 		ctx->i_compiler = CW_C_GCC;
   1863 		ctx->i_flags |= CW_F_CXX;
   1864 	} else {
   1865 		/* assume "-_gcc" by default */
   1866 		argc++;
   1867 		argv--;
   1868 		ctx->i_compiler = CW_C_GCC;
   1869 	}
   1870 
   1871 	/*
   1872 	 * -_compiler - tell us the path to the primary compiler only
   1873 	 */
   1874 	if (argc > 1 && strcmp(argv[1], "-_compiler") == 0) {
   1875 		ctx->i_flags &= ~CW_F_XLATE;
   1876 		prepctx(ctx);
   1877 		(void) printf("%s\n", ctx->i_ae->ael_head->ae_arg);
   1878 		return (0);
   1879 	}
   1880 
   1881 	/*
   1882 	 * -_versions - tell us the cw version, paths to all compilers, and
   1883 	 *		ask each for its version if we know how.
   1884 	 */
   1885 	if (argc > 1 && strcmp(argv[1], "-_versions") == 0) {
   1886 		(void) printf("cw version %s", CW_VERSION);
   1887 		if (!do_shadow)
   1888 			(void) printf(" (SHADOW MODE DISABLED)");
   1889 		(void) printf("\n");
   1890 		(void) fflush(stdout);
   1891 		ctx->i_flags &= ~CW_F_ECHO;
   1892 		ctx->i_flags |= CW_F_PROG|CW_F_EXEC;
   1893 		argc--;
   1894 		argv++;
   1895 		do_serial = 1;
   1896 	}
   1897 
   1898 	ctx->i_oldargc = argc;
   1899 	ctx->i_oldargv = argv;
   1900 
   1901 	ret |= exec_ctx(ctx, do_serial);
   1902 
   1903 	if (do_shadow) {
   1904 		(void) memcpy(ctx_shadow, ctx, sizeof (cw_ictx_t));
   1905 		ctx_shadow->i_flags |= CW_F_SHADOW;
   1906 		ret |= exec_ctx(ctx_shadow, 1);
   1907 	}
   1908 
   1909 	if (!do_serial)
   1910 		ret |= reap(ctx);
   1911 
   1912 	return (ret);
   1913 }
   1914