xref: /illumos-gate/usr/src/tools/cw/cw.c (revision bb9475a199514dcace79d04d02c1eff05d65b94f)
1aa9ef484SJohn Levon 
27c478bd9Sstevel@tonic-gate /*
37c478bd9Sstevel@tonic-gate  * CDDL HEADER START
47c478bd9Sstevel@tonic-gate  *
57c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
602e56f3fSwesolows  * Common Development and Distribution License (the "License").
702e56f3fSwesolows  * You may not use this file except in compliance with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
2202e56f3fSwesolows 
237c478bd9Sstevel@tonic-gate /*
247fbf8d03SScott Rotondo  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
261f5207b7SJohn Levon  *
27564d5236SRichard Lowe  * Copyright 2018 Richard Lowe.
281f5207b7SJohn Levon  * Copyright 2019 Joyent, Inc.
29*bb9475a1SRobert Mustacchi  * Copyright 2025 Oxide Computer Company
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * Wrapper for the GNU C compiler to make it accept the Sun C compiler
347c478bd9Sstevel@tonic-gate  * arguments where possible.
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * Since the translation is inexact, this is something of a work-in-progress.
379a70fc3bSMark J. Nelson  *
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate 
405d9d9091SRichard Lowe /*
41d17be682SRichard Lowe  * If you modify this file, you must increment CW_VERSION.  This is a semver,
42d17be682SRichard Lowe  * incompatible changes should bump the major, anything else the minor.
435d9d9091SRichard Lowe  */
44*bb9475a1SRobert Mustacchi #define	CW_VERSION	"10.0"
459a70fc3bSMark J. Nelson 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * -#		Verbose mode
487c478bd9Sstevel@tonic-gate  * -###		Show compiler commands built by driver, no compilation
497c478bd9Sstevel@tonic-gate  * -A<name[(tokens)]>	Preprocessor predicate assertion
507c478bd9Sstevel@tonic-gate  * -C		Prevent preprocessor from removing comments
517c478bd9Sstevel@tonic-gate  * -c		Compile only - produce .o files, suppress linking
527c478bd9Sstevel@tonic-gate  * -D<name[=token]>	Associate name with token as if by #define
537c478bd9Sstevel@tonic-gate  * -d[y|n]	dynamic [-dy] or static [-dn] option to linker
547c478bd9Sstevel@tonic-gate  * -E		Compile source through preprocessor only, output to stdout
557c478bd9Sstevel@tonic-gate  * -erroff=<t>	Suppress warnings specified by tags t(%none, %all, <tag list>)
567c478bd9Sstevel@tonic-gate  * -errtags=<a>	Display messages with tags a(no, yes)
577c478bd9Sstevel@tonic-gate  * -errwarn=<t>	Treats warnings specified by tags t(%none, %all, <tag list>)
587c478bd9Sstevel@tonic-gate  *		as errors
597c478bd9Sstevel@tonic-gate  * -g		Compile for debugging
607c478bd9Sstevel@tonic-gate  * -H		Print path name of each file included during compilation
617c478bd9Sstevel@tonic-gate  * -h <name>	Assign <name> to generated dynamic shared library
627c478bd9Sstevel@tonic-gate  * -I<dir>	Add <dir> to preprocessor #include file search path
637c478bd9Sstevel@tonic-gate  * -i		Passed to linker to ignore any LD_LIBRARY_PATH setting
647c478bd9Sstevel@tonic-gate  * -keeptmp	Keep temporary files created during compilation
657c478bd9Sstevel@tonic-gate  * -L<dir>	Pass to linker to add <dir> to the library search path
667c478bd9Sstevel@tonic-gate  * -l<name>	Link with library lib<name>.a or lib<name>.so
677c478bd9Sstevel@tonic-gate  * -mt		Specify options needed when compiling multi-threaded code
68662492f5Ssherrym  * -O		Use default optimization level (-xO2 or -xO3. Check man page.)
697c478bd9Sstevel@tonic-gate  * -o <outputfile> Set name of output file to <outputfile>
707c478bd9Sstevel@tonic-gate  * -P		Compile source through preprocessor only, output to .i  file
717c478bd9Sstevel@tonic-gate  * -p		Compile for profiling with prof
727c478bd9Sstevel@tonic-gate  * -R<dir[:dir]> Build runtime search path list into executable
737c478bd9Sstevel@tonic-gate  * -S		Compile and only generate assembly code (.s)
747c478bd9Sstevel@tonic-gate  * -s		Strip symbol table from the executable file
75*bb9475a1SRobert Mustacchi  * -std=	Set the C standard (note this is in the GNU syntax)
76159cf8a6Swesolows  * -t		Turn off duplicate symbol warnings when linking
777c478bd9Sstevel@tonic-gate  * -U<name>	Delete initial definition of preprocessor symbol <name>
787c478bd9Sstevel@tonic-gate  * -V		Report version number of each compilation phase
797c478bd9Sstevel@tonic-gate  * -v		Do stricter semantic checking
807c478bd9Sstevel@tonic-gate  * -W<c>,<arg>	Pass <arg> to specified component <c> (a,l,m,p,0,2,h,i,u)
817c478bd9Sstevel@tonic-gate  * -w		Suppress compiler warning messages
827c478bd9Sstevel@tonic-gate  * -Xa		Compile assuming ANSI C conformance, allow K & R extensions
837c478bd9Sstevel@tonic-gate  *		(default mode)
847c478bd9Sstevel@tonic-gate  * -Xs		Compile assuming (pre-ANSI) K & R C style code
857c478bd9Sstevel@tonic-gate  * -xarch=<a>	Specify target architecture instruction set
867c478bd9Sstevel@tonic-gate  * -xbuiltin[=<b>] When profitable inline, or substitute intrinisic functions
877c478bd9Sstevel@tonic-gate  *		for system functions, b={%all,%none}
887c478bd9Sstevel@tonic-gate  * -xchip=<c>	Specify the target processor for use by the optimizer
897c478bd9Sstevel@tonic-gate  * -xO<n>	Generate optimized code (n={1|2|3|4|5})
907c478bd9Sstevel@tonic-gate  * -xtarget=<t>	Specify target system for optimization
91d17be682SRichard Lowe  * -YI,<dir>	Specify <dir> for location of headers
927c478bd9Sstevel@tonic-gate  */
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate  * Translation table:
967c478bd9Sstevel@tonic-gate  */
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate  * -#				-v
997c478bd9Sstevel@tonic-gate  * -###				error
1007c478bd9Sstevel@tonic-gate  * -A<name[(tokens)]>		pass-thru
1017c478bd9Sstevel@tonic-gate  * -B<[static|dynamic]>		pass-thru (syntax error for anything else)
1027c478bd9Sstevel@tonic-gate  * -C				pass-thru
1037c478bd9Sstevel@tonic-gate  * -c				pass-thru
1047c478bd9Sstevel@tonic-gate  * -D<name[=token]>		pass-thru
1057c478bd9Sstevel@tonic-gate  * -E				pass-thru
1067c478bd9Sstevel@tonic-gate  * -errtags=%all		-Wall
1077c478bd9Sstevel@tonic-gate  * -errwarn=%all		-Werror else -Wno-error
1087c478bd9Sstevel@tonic-gate  * -g				pass-thru
1097c478bd9Sstevel@tonic-gate  * -H				pass-thru
1107c478bd9Sstevel@tonic-gate  * -I<dir>			pass-thru
1117c478bd9Sstevel@tonic-gate  * -i				pass-thru
1127c478bd9Sstevel@tonic-gate  * -keeptmp			-save-temps
1137c478bd9Sstevel@tonic-gate  * -L<dir>			pass-thru
1147c478bd9Sstevel@tonic-gate  * -l<name>			pass-thru
1157c478bd9Sstevel@tonic-gate  * -mt				-D_REENTRANT
1167c478bd9Sstevel@tonic-gate  * -nolib			-nodefaultlibs
117662492f5Ssherrym  * -O				-O1 (Check the man page to be certain)
1187c478bd9Sstevel@tonic-gate  * -o <outputfile>		pass-thru
1197c478bd9Sstevel@tonic-gate  * -P				-E -o filename.i (or error)
1207c478bd9Sstevel@tonic-gate  * -p				pass-thru
1217c478bd9Sstevel@tonic-gate  * -R<dir[:dir]>		pass-thru
1227c478bd9Sstevel@tonic-gate  * -S				pass-thru
123*bb9475a1SRobert Mustacchi  * -std=			pass-thru
1247c478bd9Sstevel@tonic-gate  * -U<name>			pass-thru
1257c478bd9Sstevel@tonic-gate  * -V				--version
1267c478bd9Sstevel@tonic-gate  * -v				-Wall
1277c478bd9Sstevel@tonic-gate  * -Wa,<arg>			pass-thru
128d17be682SRichard Lowe  * -Wp,<arg>			pass-thru
1297c478bd9Sstevel@tonic-gate  * -Wl,<arg>			pass-thru
13054836668Spetede  * -xmodel=kernel		-ffreestanding -mcmodel=kernel -mno-red-zone
131d430274bSsherrym  * -Wu,-save_args		-msave-args
1327c478bd9Sstevel@tonic-gate  * -w				pass-thru
1337c478bd9Sstevel@tonic-gate  * -Xa				-std=iso9899:199409 or -ansi
1347c478bd9Sstevel@tonic-gate  * -Xs				-traditional -std=c89
1357c478bd9Sstevel@tonic-gate  * -xarch=<a>			table
13602e56f3fSwesolows  * -xbuiltin[=<b>]		-fbuiltin (-fno-builtin otherwise)
1377c478bd9Sstevel@tonic-gate  * -xchip=<c>			table
1387c478bd9Sstevel@tonic-gate  * -xO<n>			-O<n>
1397c478bd9Sstevel@tonic-gate  * -xtarget=<t>			table
1407c478bd9Sstevel@tonic-gate  * -xtransition			-Wtransition
1417c478bd9Sstevel@tonic-gate  * -YI,<dir>			-nostdinc -I<dir>
1427c478bd9Sstevel@tonic-gate  */
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate #include <ctype.h>
145aa9ef484SJohn Levon #include <err.h>
14680ab886dSwesolows #include <errno.h>
147aa9ef484SJohn Levon #include <fcntl.h>
148aa9ef484SJohn Levon #include <getopt.h>
149aa9ef484SJohn Levon #include <stdio.h>
150aa9ef484SJohn Levon #include <stdlib.h>
15122a8b493SToomas Soome #include <stdbool.h>
152aa9ef484SJohn Levon #include <string.h>
153aa9ef484SJohn Levon #include <unistd.h>
15488e61e85SRichard Lowe #include <dirent.h>
155aa9ef484SJohn Levon 
1567c478bd9Sstevel@tonic-gate #include <sys/param.h>
15780ab886dSwesolows #include <sys/stat.h>
158aa9ef484SJohn Levon #include <sys/types.h>
159aa9ef484SJohn Levon #include <sys/utsname.h>
160aa9ef484SJohn Levon #include <sys/wait.h>
1617c478bd9Sstevel@tonic-gate 
16280ab886dSwesolows #define	CW_F_CXX	0x01
16380ab886dSwesolows #define	CW_F_SHADOW	0x02
16480ab886dSwesolows #define	CW_F_EXEC	0x04
16580ab886dSwesolows #define	CW_F_ECHO	0x08
16680ab886dSwesolows #define	CW_F_XLATE	0x10
1671912d2c4Swesolows #define	CW_F_PROG	0x20
16880ab886dSwesolows 
16980ab886dSwesolows typedef enum cw_op {
17080ab886dSwesolows 	CW_O_NONE = 0,
17180ab886dSwesolows 	CW_O_PREPROCESS,
17280ab886dSwesolows 	CW_O_COMPILE,
17380ab886dSwesolows 	CW_O_LINK
17480ab886dSwesolows } cw_op_t;
17580ab886dSwesolows 
17680ab886dSwesolows struct aelist {
17780ab886dSwesolows 	struct ae {
17880ab886dSwesolows 		struct ae *ae_next;
17980ab886dSwesolows 		char *ae_arg;
18080ab886dSwesolows 	} *ael_head, *ael_tail;
18180ab886dSwesolows 	int ael_argc;
18280ab886dSwesolows };
18380ab886dSwesolows 
184aa9ef484SJohn Levon typedef enum {
185aa9ef484SJohn Levon 	GNU,
1861f5207b7SJohn Levon 	SUN,
1871f5207b7SJohn Levon 	SMATCH
188aa9ef484SJohn Levon } compiler_style_t;
189aa9ef484SJohn Levon 
190*bb9475a1SRobert Mustacchi typedef enum {
191*bb9475a1SRobert Mustacchi 	SOURCE_FILE_T_NONE,
192*bb9475a1SRobert Mustacchi 	SOURCE_FILE_T_C,
193*bb9475a1SRobert Mustacchi 	SOURCE_FILE_T_S,
194*bb9475a1SRobert Mustacchi 	SOURCE_FILE_T_CPP,
195*bb9475a1SRobert Mustacchi 	SOURCE_FILE_T_CCX,
196*bb9475a1SRobert Mustacchi 	SOURCE_FILE_T_I
197*bb9475a1SRobert Mustacchi } source_file_type_t;
198*bb9475a1SRobert Mustacchi 
199aa9ef484SJohn Levon typedef struct {
200aa9ef484SJohn Levon 	char *c_name;
201aa9ef484SJohn Levon 	char *c_path;
202aa9ef484SJohn Levon 	compiler_style_t c_style;
203aa9ef484SJohn Levon } cw_compiler_t;
204aa9ef484SJohn Levon 
20580ab886dSwesolows typedef struct cw_ictx {
206aa9ef484SJohn Levon 	struct cw_ictx	*i_next;
207aa9ef484SJohn Levon 	cw_compiler_t	*i_compiler;
20869b1fd3fSRichard Lowe 	char		*i_linker;
20980ab886dSwesolows 	struct aelist	*i_ae;
21080ab886dSwesolows 	uint32_t	i_flags;
21180ab886dSwesolows 	int		i_oldargc;
21280ab886dSwesolows 	char		**i_oldargv;
21380ab886dSwesolows 	pid_t		i_pid;
21488e61e85SRichard Lowe 	char		*i_tmpdir;
2151912d2c4Swesolows 	char		*i_stderr;
21680ab886dSwesolows } cw_ictx_t;
21780ab886dSwesolows 
218e521259dSpetede /*
219e521259dSpetede  * Status values to indicate which Studio compiler and associated
220e521259dSpetede  * flags are being used.
221e521259dSpetede  */
222e521259dSpetede #define	M32		0x01	/* -m32 - only on Studio 12 */
223e521259dSpetede #define	M64		0x02	/* -m64 - only on Studio 12 */
224e521259dSpetede #define	SS11		0x100	/* Studio 11 */
225e521259dSpetede #define	SS12		0x200	/* Studio 12 */
2267c478bd9Sstevel@tonic-gate 
227e521259dSpetede #define	TRANS_ENTRY	5
228e521259dSpetede /*
229e521259dSpetede  * Translation table definition for the -xarch= flag. The "x_arg"
230e521259dSpetede  * value is translated into the appropriate gcc flags according
231e521259dSpetede  * to the values in x_trans[n]. The x_flags indicates what compiler
232e521259dSpetede  * is being used and what flags have been set via the use of
233e521259dSpetede  * "x_arg".
234e521259dSpetede  */
235e521259dSpetede typedef struct xarch_table {
236e521259dSpetede 	char	*x_arg;
237e521259dSpetede 	int	x_flags;
238e521259dSpetede 	char	*x_trans[TRANS_ENTRY];
239e521259dSpetede } xarch_table_t;
240e521259dSpetede 
241e521259dSpetede /*
242e521259dSpetede  * The translation table for the -xarch= flag used in the Studio compilers.
243e521259dSpetede  */
244e521259dSpetede static const xarch_table_t xtbl[] = {
2457c478bd9Sstevel@tonic-gate #if defined(__x86)
246aa9ef484SJohn Levon 	{ "generic",	SS11, {NULL} },
2477a6460b6Spetede 	{ "generic64",	(SS11|M64), { "-m64", "-mtune=opteron" } },
2487a6460b6Spetede 	{ "amd64",	(SS11|M64), { "-m64", "-mtune=opteron" } },
2497a6460b6Spetede 	{ "386",	SS11,	{ "-march=i386" } },
2507a6460b6Spetede 	{ "pentium_pro", SS11,	{ "-march=pentiumpro" } },
25125c28e83SPiotr Jasiukajtis 	{ "sse",	SS11, { "-msse", "-mfpmath=sse" } },
25225c28e83SPiotr Jasiukajtis 	{ "sse2",	SS11, { "-msse2", "-mfpmath=sse" } },
2537c478bd9Sstevel@tonic-gate #endif
2547c478bd9Sstevel@tonic-gate };
2557c478bd9Sstevel@tonic-gate 
256e521259dSpetede static int xtbl_size = sizeof (xtbl) / sizeof (xarch_table_t);
257e521259dSpetede 
2587c478bd9Sstevel@tonic-gate static const char *xchip_tbl[] = {
2597c478bd9Sstevel@tonic-gate #if defined(__x86)
2607c478bd9Sstevel@tonic-gate 	"386",		"-mtune=i386", NULL,
2617c478bd9Sstevel@tonic-gate 	"486",		"-mtune=i486", NULL,
2627c478bd9Sstevel@tonic-gate 	"pentium",	"-mtune=pentium", NULL,
2637c478bd9Sstevel@tonic-gate 	"pentium_pro",  "-mtune=pentiumpro", NULL,
2647c478bd9Sstevel@tonic-gate #endif
2657c478bd9Sstevel@tonic-gate 	NULL,		NULL
2667c478bd9Sstevel@tonic-gate };
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate static const char *xtarget_tbl[] = {
2697c478bd9Sstevel@tonic-gate #if defined(__x86)
2707c478bd9Sstevel@tonic-gate 	"pentium_pro",	"-march=pentiumpro", NULL,
2717c478bd9Sstevel@tonic-gate #endif	/* __x86 */
2727c478bd9Sstevel@tonic-gate 	NULL,		NULL
2737c478bd9Sstevel@tonic-gate };
2747c478bd9Sstevel@tonic-gate 
27580ab886dSwesolows static void
nomem(void)27680ab886dSwesolows nomem(void)
2777c478bd9Sstevel@tonic-gate {
278aa9ef484SJohn Levon 	errx(1, "out of memory");
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate static void
newae(struct aelist * ael,const char * arg)2827c478bd9Sstevel@tonic-gate newae(struct aelist *ael, const char *arg)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate 	struct ae *ae;
2857c478bd9Sstevel@tonic-gate 
28669b1fd3fSRichard Lowe 	if ((ae = calloc(1, sizeof (*ae))) == NULL)
28780ab886dSwesolows 		nomem();
2887c478bd9Sstevel@tonic-gate 	ae->ae_arg = strdup(arg);
2897c478bd9Sstevel@tonic-gate 	if (ael->ael_tail == NULL)
2907c478bd9Sstevel@tonic-gate 		ael->ael_head = ae;
2917c478bd9Sstevel@tonic-gate 	else
2927c478bd9Sstevel@tonic-gate 		ael->ael_tail->ae_next = ae;
2937c478bd9Sstevel@tonic-gate 	ael->ael_tail = ae;
29480ab886dSwesolows 	ael->ael_argc++;
29580ab886dSwesolows }
29680ab886dSwesolows 
29780ab886dSwesolows static cw_ictx_t *
newictx(void)29880ab886dSwesolows newictx(void)
29980ab886dSwesolows {
30069b1fd3fSRichard Lowe 	cw_ictx_t *ctx = calloc(1, sizeof (cw_ictx_t));
30180ab886dSwesolows 	if (ctx)
30269b1fd3fSRichard Lowe 		if ((ctx->i_ae = calloc(1, sizeof (struct aelist))) == NULL) {
30380ab886dSwesolows 			free(ctx);
30480ab886dSwesolows 			return (NULL);
30580ab886dSwesolows 		}
30680ab886dSwesolows 
30780ab886dSwesolows 	return (ctx);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate static void
error(const char * arg)3117c478bd9Sstevel@tonic-gate error(const char *arg)
3127c478bd9Sstevel@tonic-gate {
313aa9ef484SJohn Levon 	errx(2, "error: mapping failed at or near arg '%s'", arg);
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate /*
3177c478bd9Sstevel@tonic-gate  * Add the current favourite set of warnings to the gcc invocation.
3187c478bd9Sstevel@tonic-gate  */
3197c478bd9Sstevel@tonic-gate static void
warnings(struct aelist * h)3207c478bd9Sstevel@tonic-gate warnings(struct aelist *h)
3217c478bd9Sstevel@tonic-gate {
3227c478bd9Sstevel@tonic-gate 	static int warningsonce;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	if (warningsonce++)
3257c478bd9Sstevel@tonic-gate 		return;
3267c478bd9Sstevel@tonic-gate 
3277014882cSRichard Lowe 	/*
3287014882cSRichard Lowe 	 * Enable as many warnings as exist, then disable those that we never
3297014882cSRichard Lowe 	 * ever want.
3307014882cSRichard Lowe 	 */
3317c478bd9Sstevel@tonic-gate 	newae(h, "-Wall");
3327014882cSRichard Lowe 	newae(h, "-Wextra");
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate static void
optim_disable(struct aelist * h,int level)3367c478bd9Sstevel@tonic-gate optim_disable(struct aelist *h, int level)
3377c478bd9Sstevel@tonic-gate {
3387c478bd9Sstevel@tonic-gate 	if (level >= 2) {
3397c478bd9Sstevel@tonic-gate 		newae(h, "-fno-strict-aliasing");
3407c478bd9Sstevel@tonic-gate 		newae(h, "-fno-unit-at-a-time");
3417c478bd9Sstevel@tonic-gate 		newae(h, "-fno-optimize-sibling-calls");
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate static void
Xsmode(struct aelist * h)3467c478bd9Sstevel@tonic-gate Xsmode(struct aelist *h)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate 	static int xsonce;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	if (xsonce++)
3517c478bd9Sstevel@tonic-gate 		return;
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	newae(h, "-traditional");
3547c478bd9Sstevel@tonic-gate 	newae(h, "-traditional-cpp");
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate static void
usage(void)35869b1fd3fSRichard Lowe usage(void)
3597c478bd9Sstevel@tonic-gate {
360aa9ef484SJohn Levon 	extern char *__progname;
3617c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
3629b9d39d2SRichard Lowe 	    "usage: %s [-C] [--tag arg] [--versions] --primary <compiler> "
363aa9ef484SJohn Levon 	    "[--shadow <compiler>]... -- cflags...\n",
364aa9ef484SJohn Levon 	    __progname);
365aa9ef484SJohn Levon 	(void) fprintf(stderr, "compilers take the form: name,path,style\n"
366aa9ef484SJohn Levon 	    " - name: a unique name usable in flag specifiers\n"
367aa9ef484SJohn Levon 	    " - path: path to the compiler binary\n"
368aa9ef484SJohn Levon 	    " - style: the style of flags expected: either sun or gnu\n");
3697c478bd9Sstevel@tonic-gate 	exit(2);
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate 
372e521259dSpetede static int
xlate_xtb(struct aelist * h,const char * xarg)373e521259dSpetede xlate_xtb(struct aelist *h, const char *xarg)
374e521259dSpetede {
375e521259dSpetede 	int	i, j;
376e521259dSpetede 
377e521259dSpetede 	for (i = 0; i < xtbl_size; i++) {
378e521259dSpetede 		if (strcmp(xtbl[i].x_arg, xarg) == 0)
379e521259dSpetede 			break;
380e521259dSpetede 	}
381e521259dSpetede 
382e521259dSpetede 	/*
383e521259dSpetede 	 * At the end of the table and so no matching "arg" entry
384e521259dSpetede 	 * found and so this must be a bad -xarch= flag.
385e521259dSpetede 	 */
386e521259dSpetede 	if (i == xtbl_size)
387e521259dSpetede 		error(xarg);
388e521259dSpetede 
389e521259dSpetede 	for (j = 0; j < TRANS_ENTRY; j++) {
390e521259dSpetede 		if (xtbl[i].x_trans[j] != NULL)
391e521259dSpetede 			newae(h, xtbl[i].x_trans[j]);
392e521259dSpetede 		else
393e521259dSpetede 			break;
394e521259dSpetede 	}
395e521259dSpetede 	return (xtbl[i].x_flags);
396e521259dSpetede 
397e521259dSpetede }
398e521259dSpetede 
3997c478bd9Sstevel@tonic-gate static void
xlate(struct aelist * h,const char * xarg,const char ** table)4007c478bd9Sstevel@tonic-gate xlate(struct aelist *h, const char *xarg, const char **table)
4017c478bd9Sstevel@tonic-gate {
4027c478bd9Sstevel@tonic-gate 	while (*table != NULL && strcmp(xarg, *table) != 0) {
4037c478bd9Sstevel@tonic-gate 		while (*table != NULL)
4047c478bd9Sstevel@tonic-gate 			table++;
4057c478bd9Sstevel@tonic-gate 		table++;
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	if (*table == NULL)
4097c478bd9Sstevel@tonic-gate 		error(xarg);
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	table++;
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	while (*table != NULL) {
4147c478bd9Sstevel@tonic-gate 		newae(h, *table);
4157c478bd9Sstevel@tonic-gate 		table++;
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate }
4187c478bd9Sstevel@tonic-gate 
41988e61e85SRichard Lowe /*
42088e61e85SRichard Lowe  * The compiler wants the output file to end in appropriate extension.  If
42188e61e85SRichard Lowe  * we're generating a name from whole cloth (path == NULL), we assume that
42288e61e85SRichard Lowe  * extension to be .o, otherwise we match the extension of the caller.
42388e61e85SRichard Lowe  */
42488e61e85SRichard Lowe static char *
discard_file_name(cw_ictx_t * ctx,const char * path)42588e61e85SRichard Lowe discard_file_name(cw_ictx_t *ctx, const char *path)
42688e61e85SRichard Lowe {
42788e61e85SRichard Lowe 	char *ret, *ext;
42888e61e85SRichard Lowe 	char tmpl[] = "cwXXXXXX";
42988e61e85SRichard Lowe 
43088e61e85SRichard Lowe 	if (path == NULL) {
43188e61e85SRichard Lowe 		ext = ".o";
43288e61e85SRichard Lowe 	} else {
43388e61e85SRichard Lowe 		ext = strrchr(path, '.');
43488e61e85SRichard Lowe 	}
43588e61e85SRichard Lowe 
43688e61e85SRichard Lowe 	/*
43788e61e85SRichard Lowe 	 * We need absolute control over where the temporary file goes, since
43888e61e85SRichard Lowe 	 * we rely on it for cleanup so tempnam(3C) and tmpnam(3C) are
43988e61e85SRichard Lowe 	 * inappropriate (they use TMPDIR, preferentially).
44088e61e85SRichard Lowe 	 *
44188e61e85SRichard Lowe 	 * mkstemp(3C) doesn't actually help us, since the temporary file
44288e61e85SRichard Lowe 	 * isn't used by us, only its name.
44388e61e85SRichard Lowe 	 */
44488e61e85SRichard Lowe 	if (mktemp(tmpl) == NULL)
44588e61e85SRichard Lowe 		nomem();
44688e61e85SRichard Lowe 
44788e61e85SRichard Lowe 	(void) asprintf(&ret, "%s/%s%s", ctx->i_tmpdir, tmpl,
44888e61e85SRichard Lowe 	    (ext != NULL) ? ext : "");
44988e61e85SRichard Lowe 
45088e61e85SRichard Lowe 	if (ret == NULL)
45188e61e85SRichard Lowe 		nomem();
45288e61e85SRichard Lowe 
45388e61e85SRichard Lowe 	return (ret);
45488e61e85SRichard Lowe }
45588e61e85SRichard Lowe 
456*bb9475a1SRobert Mustacchi static source_file_type_t
id_source_file(const char * path)457*bb9475a1SRobert Mustacchi id_source_file(const char *path)
45888e61e85SRichard Lowe {
459*bb9475a1SRobert Mustacchi 	const char *ext = strrchr(path, '.');
46088e61e85SRichard Lowe 
461406d4d29SJohn Levon 	if ((ext == NULL) || (*(ext + 1) == '\0'))
462*bb9475a1SRobert Mustacchi 		return (SOURCE_FILE_T_NONE);
46388e61e85SRichard Lowe 
46488e61e85SRichard Lowe 	ext += 1;
46588e61e85SRichard Lowe 
466*bb9475a1SRobert Mustacchi 	if (strcasecmp(ext, "c") == 0) {
467*bb9475a1SRobert Mustacchi 		return (SOURCE_FILE_T_C);
468*bb9475a1SRobert Mustacchi 	} else if (strcmp(ext, "cc") == 0) {
469*bb9475a1SRobert Mustacchi 		return (SOURCE_FILE_T_CCX);
470*bb9475a1SRobert Mustacchi 	} else if (strcmp(ext, "i") == 0) {
471*bb9475a1SRobert Mustacchi 		return (SOURCE_FILE_T_I);
472*bb9475a1SRobert Mustacchi 	} else if (strcasecmp(ext, "s") == 0) {
473*bb9475a1SRobert Mustacchi 		return (SOURCE_FILE_T_S);
474*bb9475a1SRobert Mustacchi 	} else if (strcmp(ext, "cpp") == 0) {
475*bb9475a1SRobert Mustacchi 		return (SOURCE_FILE_T_CPP);
47688e61e85SRichard Lowe 	}
47788e61e85SRichard Lowe 
478*bb9475a1SRobert Mustacchi 	return (SOURCE_FILE_T_NONE);
479*bb9475a1SRobert Mustacchi 
48088e61e85SRichard Lowe }
48188e61e85SRichard Lowe 
4825d9d9091SRichard Lowe static bool
is_asm_file(const char * path)4835d9d9091SRichard Lowe is_asm_file(const char *path)
4845d9d9091SRichard Lowe {
485*bb9475a1SRobert Mustacchi 	return (id_source_file(path) == SOURCE_FILE_T_S);
4865d9d9091SRichard Lowe }
48788e61e85SRichard Lowe 
4887c478bd9Sstevel@tonic-gate static void
do_gcc(cw_ictx_t * ctx)48980ab886dSwesolows do_gcc(cw_ictx_t *ctx)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 	int c;
492e1bf37b1SRichard Lowe 	int nolibc = 0;
493*bb9475a1SRobert Mustacchi 	int in_output = 0, seen_o = 0, src_files = 0;
49480ab886dSwesolows 	cw_op_t op = CW_O_LINK;
4957c478bd9Sstevel@tonic-gate 	char *model = NULL;
496aa9ef484SJohn Levon 	char *nameflag;
497e521259dSpetede 	int mflag = 0;
498*bb9475a1SRobert Mustacchi 	bool seen_cstd = false, check_cstd = false;
4997c478bd9Sstevel@tonic-gate 
5001912d2c4Swesolows 	if (ctx->i_flags & CW_F_PROG) {
5011912d2c4Swesolows 		newae(ctx->i_ae, "--version");
5021912d2c4Swesolows 		return;
5031912d2c4Swesolows 	}
5041912d2c4Swesolows 
50580ab886dSwesolows 	newae(ctx->i_ae, "-fident");
50680ab886dSwesolows 	newae(ctx->i_ae, "-finline");
50780ab886dSwesolows 	newae(ctx->i_ae, "-fno-inline-functions");
50880ab886dSwesolows 	newae(ctx->i_ae, "-fno-builtin");
50980ab886dSwesolows 	newae(ctx->i_ae, "-fno-asm");
5107014882cSRichard Lowe 	newae(ctx->i_ae, "-fdiagnostics-show-option");
51180ab886dSwesolows 	newae(ctx->i_ae, "-nodefaultlibs");
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	/*
5147c478bd9Sstevel@tonic-gate 	 * This is needed because 'u' is defined
5157c478bd9Sstevel@tonic-gate 	 * under a conditional on 'sun'.  Should
5167c478bd9Sstevel@tonic-gate 	 * probably just remove the conditional,
5177c478bd9Sstevel@tonic-gate 	 * or make it be dependent on '__sun'.
5187c478bd9Sstevel@tonic-gate 	 *
5197c478bd9Sstevel@tonic-gate 	 * -Dunix is also missing in enhanced ANSI mode
5207c478bd9Sstevel@tonic-gate 	 */
52180ab886dSwesolows 	newae(ctx->i_ae, "-D__sun");
5227c478bd9Sstevel@tonic-gate 
523aa9ef484SJohn Levon 	if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1)
524aa9ef484SJohn Levon 		nomem();
525aa9ef484SJohn Levon 
5267c478bd9Sstevel@tonic-gate 	/*
5277c478bd9Sstevel@tonic-gate 	 * Walk the argument list, translating as we go ..
5287c478bd9Sstevel@tonic-gate 	 */
52980ab886dSwesolows 	while (--ctx->i_oldargc > 0) {
53080ab886dSwesolows 		char *arg = *++ctx->i_oldargv;
5317c478bd9Sstevel@tonic-gate 		size_t arglen = strlen(arg);
5327c478bd9Sstevel@tonic-gate 
53380ab886dSwesolows 		if (*arg == '-') {
5347c478bd9Sstevel@tonic-gate 			arglen--;
53580ab886dSwesolows 		} else {
536*bb9475a1SRobert Mustacchi 			if (!in_output) {
537*bb9475a1SRobert Mustacchi 				source_file_type_t type = id_source_file(arg);
538*bb9475a1SRobert Mustacchi 				if (type != SOURCE_FILE_T_NONE)
539*bb9475a1SRobert Mustacchi 					src_files++;
540*bb9475a1SRobert Mustacchi 				if (type == SOURCE_FILE_T_C)
541*bb9475a1SRobert Mustacchi 					check_cstd = true;
542*bb9475a1SRobert Mustacchi 			}
54380ab886dSwesolows 
5447c478bd9Sstevel@tonic-gate 			/*
54580ab886dSwesolows 			 * Otherwise, filenames and partial arguments
54680ab886dSwesolows 			 * are passed through for gcc to chew on.  However,
54780ab886dSwesolows 			 * output is always discarded for the secondary
54880ab886dSwesolows 			 * compiler.
5497c478bd9Sstevel@tonic-gate 			 */
55088e61e85SRichard Lowe 			if ((ctx->i_flags & CW_F_SHADOW) && in_output) {
55188e61e85SRichard Lowe 				newae(ctx->i_ae, discard_file_name(ctx, arg));
55288e61e85SRichard Lowe 			} else {
55380ab886dSwesolows 				newae(ctx->i_ae, arg);
55488e61e85SRichard Lowe 			}
55580ab886dSwesolows 			in_output = 0;
5567c478bd9Sstevel@tonic-gate 			continue;
5577c478bd9Sstevel@tonic-gate 		}
5587c478bd9Sstevel@tonic-gate 
55980ab886dSwesolows 		if (ctx->i_flags & CW_F_CXX) {
560aa9ef484SJohn Levon 			if (strncmp(arg, "-_g++=", 6) == 0) {
561aa9ef484SJohn Levon 				newae(ctx->i_ae, strchr(arg, '=') + 1);
562aa9ef484SJohn Levon 				continue;
563aa9ef484SJohn Levon 			}
564d17be682SRichard Lowe 
5657c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-xwe") == 0) {
5667c478bd9Sstevel@tonic-gate 				/* turn warnings into errors */
56780ab886dSwesolows 				newae(ctx->i_ae, "-Werror");
5687c478bd9Sstevel@tonic-gate 				continue;
5697c478bd9Sstevel@tonic-gate 			}
5707c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-nolib") == 0) {
5717c478bd9Sstevel@tonic-gate 				/* -nodefaultlibs is on by default */
5727c478bd9Sstevel@tonic-gate 				nolibc = 1;
5737c478bd9Sstevel@tonic-gate 				continue;
5747c478bd9Sstevel@tonic-gate 			}
5757c478bd9Sstevel@tonic-gate 		}
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 		switch ((c = arg[1])) {
5787c478bd9Sstevel@tonic-gate 		case '_':
579aa9ef484SJohn Levon 			if ((strncmp(arg, nameflag, strlen(nameflag)) == 0) ||
580aa9ef484SJohn Levon 			    (strncmp(arg, "-_gcc=", 6) == 0) ||
581aa9ef484SJohn Levon 			    (strncmp(arg, "-_gnu=", 6) == 0)) {
582aa9ef484SJohn Levon 				newae(ctx->i_ae, strchr(arg, '=') + 1);
583aa9ef484SJohn Levon 			}
5847c478bd9Sstevel@tonic-gate 			break;
5857c478bd9Sstevel@tonic-gate 		case '#':
5867c478bd9Sstevel@tonic-gate 			if (arglen == 1) {
58780ab886dSwesolows 				newae(ctx->i_ae, "-v");
5887c478bd9Sstevel@tonic-gate 				break;
5897c478bd9Sstevel@tonic-gate 			}
5907c478bd9Sstevel@tonic-gate 			error(arg);
5917c478bd9Sstevel@tonic-gate 			break;
592e1bf37b1SRichard Lowe 		case 'f':
593e1bf37b1SRichard Lowe 			if ((strcmp(arg, "-fpic") == 0) ||
594e1bf37b1SRichard Lowe 			    (strcmp(arg, "-fPIC") == 0)) {
595e1bf37b1SRichard Lowe 				newae(ctx->i_ae, arg);
596e1bf37b1SRichard Lowe 				break;
597e1bf37b1SRichard Lowe 			}
598e1bf37b1SRichard Lowe 			error(arg);
599e1bf37b1SRichard Lowe 			break;
6007c478bd9Sstevel@tonic-gate 		case 'E':
6017c478bd9Sstevel@tonic-gate 			if (arglen == 1) {
60280ab886dSwesolows 				newae(ctx->i_ae, "-xc");
60380ab886dSwesolows 				newae(ctx->i_ae, arg);
60480ab886dSwesolows 				op = CW_O_PREPROCESS;
6057c478bd9Sstevel@tonic-gate 				nolibc = 1;
6067c478bd9Sstevel@tonic-gate 				break;
6077c478bd9Sstevel@tonic-gate 			}
6087c478bd9Sstevel@tonic-gate 			error(arg);
6097c478bd9Sstevel@tonic-gate 			break;
6107c478bd9Sstevel@tonic-gate 		case 'c':
6117c478bd9Sstevel@tonic-gate 		case 'S':
61280ab886dSwesolows 			if (arglen == 1) {
61380ab886dSwesolows 				op = CW_O_COMPILE;
6147c478bd9Sstevel@tonic-gate 				nolibc = 1;
61580ab886dSwesolows 			}
6167c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
6177c478bd9Sstevel@tonic-gate 		case 'C':
6187c478bd9Sstevel@tonic-gate 		case 'H':
6197c478bd9Sstevel@tonic-gate 		case 'p':
6207c478bd9Sstevel@tonic-gate 			if (arglen == 1) {
62180ab886dSwesolows 				newae(ctx->i_ae, arg);
6227c478bd9Sstevel@tonic-gate 				break;
6237c478bd9Sstevel@tonic-gate 			}
6247c478bd9Sstevel@tonic-gate 			error(arg);
6257c478bd9Sstevel@tonic-gate 			break;
6267c478bd9Sstevel@tonic-gate 		case 'A':
627299e09deSRichard Lowe 		case 'g':
6287c478bd9Sstevel@tonic-gate 		case 'I':
6297c478bd9Sstevel@tonic-gate 		case 'i':
6307c478bd9Sstevel@tonic-gate 		case 'L':
6317c478bd9Sstevel@tonic-gate 		case 'l':
6327c478bd9Sstevel@tonic-gate 		case 'R':
6337c478bd9Sstevel@tonic-gate 		case 'U':
6347c478bd9Sstevel@tonic-gate 		case 'u':
6357c478bd9Sstevel@tonic-gate 		case 'w':
63680ab886dSwesolows 			newae(ctx->i_ae, arg);
63780ab886dSwesolows 			break;
63880ab886dSwesolows 		case 'o':
63980ab886dSwesolows 			seen_o = 1;
64080ab886dSwesolows 			if (arglen == 1) {
64180ab886dSwesolows 				in_output = 1;
64280ab886dSwesolows 				newae(ctx->i_ae, arg);
64380ab886dSwesolows 			} else if (ctx->i_flags & CW_F_SHADOW) {
64480ab886dSwesolows 				newae(ctx->i_ae, "-o");
64588e61e85SRichard Lowe 				newae(ctx->i_ae, discard_file_name(ctx, arg));
64680ab886dSwesolows 			} else {
64780ab886dSwesolows 				newae(ctx->i_ae, arg);
64880ab886dSwesolows 			}
6497c478bd9Sstevel@tonic-gate 			break;
6507c478bd9Sstevel@tonic-gate 		case 'D':
65180ab886dSwesolows 			newae(ctx->i_ae, arg);
6527c478bd9Sstevel@tonic-gate 			/*
6537c478bd9Sstevel@tonic-gate 			 * XXX	Clearly a hack ... do we need _KADB too?
6547c478bd9Sstevel@tonic-gate 			 */
6557c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-D_KERNEL") == 0 ||
6567c478bd9Sstevel@tonic-gate 			    strcmp(arg, "-D_BOOT") == 0)
65780ab886dSwesolows 				newae(ctx->i_ae, "-ffreestanding");
6587c478bd9Sstevel@tonic-gate 			break;
6597c478bd9Sstevel@tonic-gate 		case 'e':
6607c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-errtags=yes") == 0) {
66180ab886dSwesolows 				warnings(ctx->i_ae);
6627c478bd9Sstevel@tonic-gate 				break;
6637c478bd9Sstevel@tonic-gate 			}
6647c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-errwarn=%all") == 0) {
66580ab886dSwesolows 				newae(ctx->i_ae, "-Werror");
6667c478bd9Sstevel@tonic-gate 				break;
6677c478bd9Sstevel@tonic-gate 			}
6687c478bd9Sstevel@tonic-gate 			error(arg);
6697c478bd9Sstevel@tonic-gate 			break;
6707c478bd9Sstevel@tonic-gate 		case 'k':
6717c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-keeptmp") == 0) {
67280ab886dSwesolows 				newae(ctx->i_ae, "-save-temps");
6737c478bd9Sstevel@tonic-gate 				break;
6747c478bd9Sstevel@tonic-gate 			}
6757c478bd9Sstevel@tonic-gate 			error(arg);
6767c478bd9Sstevel@tonic-gate 			break;
6777c478bd9Sstevel@tonic-gate 		case 'm':
6787c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-mt") == 0) {
67980ab886dSwesolows 				newae(ctx->i_ae, "-D_REENTRANT");
6807c478bd9Sstevel@tonic-gate 				break;
6817c478bd9Sstevel@tonic-gate 			}
682e521259dSpetede 			if (strcmp(arg, "-m64") == 0) {
683e521259dSpetede 				newae(ctx->i_ae, "-m64");
684e521259dSpetede #if defined(__x86)
685e521259dSpetede 				newae(ctx->i_ae, "-mtune=opteron");
686e521259dSpetede #endif
687e521259dSpetede 				mflag |= M64;
688e521259dSpetede 				break;
689e521259dSpetede 			}
690e521259dSpetede 			if (strcmp(arg, "-m32") == 0) {
691e521259dSpetede 				newae(ctx->i_ae, "-m32");
692e521259dSpetede 				mflag |= M32;
693e521259dSpetede 				break;
694e521259dSpetede 			}
6957c478bd9Sstevel@tonic-gate 			error(arg);
6967c478bd9Sstevel@tonic-gate 			break;
6977c478bd9Sstevel@tonic-gate 		case 'O':
6987c478bd9Sstevel@tonic-gate 			if (arglen == 1) {
69980ab886dSwesolows 				newae(ctx->i_ae, "-O");
7007c478bd9Sstevel@tonic-gate 				break;
7017c478bd9Sstevel@tonic-gate 			}
7027c478bd9Sstevel@tonic-gate 			error(arg);
7037c478bd9Sstevel@tonic-gate 			break;
7047c478bd9Sstevel@tonic-gate 		case 'P':
7057c478bd9Sstevel@tonic-gate 			/*
7067c478bd9Sstevel@tonic-gate 			 * We could do '-E -o filename.i', but that's hard,
7077c478bd9Sstevel@tonic-gate 			 * and we don't need it for the case that's triggering
7087c478bd9Sstevel@tonic-gate 			 * this addition.  We'll require the user to specify
7097c478bd9Sstevel@tonic-gate 			 * -o in the Makefile.  If they don't they'll find out
7107c478bd9Sstevel@tonic-gate 			 * in a hurry.
7117c478bd9Sstevel@tonic-gate 			 */
71280ab886dSwesolows 			newae(ctx->i_ae, "-E");
71380ab886dSwesolows 			op = CW_O_PREPROCESS;
7147c478bd9Sstevel@tonic-gate 			nolibc = 1;
7157c478bd9Sstevel@tonic-gate 			break;
7167c478bd9Sstevel@tonic-gate 		case 's':
71785f4cb87SRichard Lowe 			if (strcmp(arg, "-shared") == 0) {
71885f4cb87SRichard Lowe 				newae(ctx->i_ae, "-shared");
71985f4cb87SRichard Lowe 				nolibc = 1;
7207c478bd9Sstevel@tonic-gate 				break;
7217c478bd9Sstevel@tonic-gate 			}
722*bb9475a1SRobert Mustacchi 
723*bb9475a1SRobert Mustacchi 			if (strncmp(arg, "-std=", 4) == 0) {
724*bb9475a1SRobert Mustacchi 				seen_cstd = true;
725*bb9475a1SRobert Mustacchi 				newae(ctx->i_ae, arg);
726*bb9475a1SRobert Mustacchi 				break;
727*bb9475a1SRobert Mustacchi 			}
7287c478bd9Sstevel@tonic-gate 			error(arg);
7297c478bd9Sstevel@tonic-gate 			break;
73085f4cb87SRichard Lowe 
7317c478bd9Sstevel@tonic-gate 		case 'V':
7327c478bd9Sstevel@tonic-gate 			if (arglen == 1) {
73380ab886dSwesolows 				ctx->i_flags &= ~CW_F_ECHO;
73480ab886dSwesolows 				newae(ctx->i_ae, "--version");
7357c478bd9Sstevel@tonic-gate 				break;
7367c478bd9Sstevel@tonic-gate 			}
7377c478bd9Sstevel@tonic-gate 			error(arg);
7387c478bd9Sstevel@tonic-gate 			break;
7397c478bd9Sstevel@tonic-gate 		case 'v':
7407c478bd9Sstevel@tonic-gate 			if (arglen == 1) {
74180ab886dSwesolows 				warnings(ctx->i_ae);
7427c478bd9Sstevel@tonic-gate 				break;
7437c478bd9Sstevel@tonic-gate 			}
7447c478bd9Sstevel@tonic-gate 			error(arg);
7457c478bd9Sstevel@tonic-gate 			break;
7467c478bd9Sstevel@tonic-gate 		case 'W':
7477c478bd9Sstevel@tonic-gate 			if (strncmp(arg, "-Wa,", 4) == 0 ||
7487c478bd9Sstevel@tonic-gate 			    strncmp(arg, "-Wp,", 4) == 0 ||
7497c478bd9Sstevel@tonic-gate 			    strncmp(arg, "-Wl,", 4) == 0) {
75080ab886dSwesolows 				newae(ctx->i_ae, arg);
7517c478bd9Sstevel@tonic-gate 				break;
7527c478bd9Sstevel@tonic-gate 			}
753d17be682SRichard Lowe 
7547c478bd9Sstevel@tonic-gate #if defined(__x86)
755d430274bSsherrym 			if (strcmp(arg, "-Wu,-save_args") == 0) {
75680ab886dSwesolows 				newae(ctx->i_ae, "-msave-args");
757d430274bSsherrym 				break;
758d430274bSsherrym 			}
7597c478bd9Sstevel@tonic-gate #endif	/* __x86 */
7607c478bd9Sstevel@tonic-gate 			error(arg);
7617c478bd9Sstevel@tonic-gate 			break;
7627c478bd9Sstevel@tonic-gate 		case 'X':
7637c478bd9Sstevel@tonic-gate 			if (strcmp(arg, "-Xs") == 0) {
76480ab886dSwesolows 				Xsmode(ctx->i_ae);
7657c478bd9Sstevel@tonic-gate 				break;
7667c478bd9Sstevel@tonic-gate 			}
7677c478bd9Sstevel@tonic-gate 			error(arg);
7687c478bd9Sstevel@tonic-gate 			break;
7697c478bd9Sstevel@tonic-gate 		case 'x':
7707c478bd9Sstevel@tonic-gate 			if (arglen == 1)
7717c478bd9Sstevel@tonic-gate 				error(arg);
7727c478bd9Sstevel@tonic-gate 			switch (arg[2]) {
7737c478bd9Sstevel@tonic-gate 			case 'a':
7747c478bd9Sstevel@tonic-gate 				if (strncmp(arg, "-xarch=", 7) == 0) {
775e521259dSpetede 					mflag |= xlate_xtb(ctx->i_ae, arg + 7);
7767c478bd9Sstevel@tonic-gate 					break;
7777c478bd9Sstevel@tonic-gate 				}
7787c478bd9Sstevel@tonic-gate 				error(arg);
7797c478bd9Sstevel@tonic-gate 				break;
78002e56f3fSwesolows 			case 'b':
78102e56f3fSwesolows 				if (strncmp(arg, "-xbuiltin=", 10) == 0) {
78202e56f3fSwesolows 					if (strcmp(arg + 10, "%all"))
78380ab886dSwesolows 						newae(ctx->i_ae, "-fbuiltin");
78402e56f3fSwesolows 					break;
78502e56f3fSwesolows 				}
78602e56f3fSwesolows 				error(arg);
78702e56f3fSwesolows 				break;
7887c478bd9Sstevel@tonic-gate 			case 'c':
7897c478bd9Sstevel@tonic-gate 				if (strncmp(arg, "-xc99=%all", 10) == 0) {
790*bb9475a1SRobert Mustacchi 					seen_cstd = true;
79180ab886dSwesolows 					newae(ctx->i_ae, "-std=gnu99");
7927c478bd9Sstevel@tonic-gate 					break;
7937c478bd9Sstevel@tonic-gate 				}
7947c478bd9Sstevel@tonic-gate 				if (strncmp(arg, "-xc99=%none", 11) == 0) {
795*bb9475a1SRobert Mustacchi 					seen_cstd = true;
79680ab886dSwesolows 					newae(ctx->i_ae, "-std=gnu89");
7977c478bd9Sstevel@tonic-gate 					break;
7987c478bd9Sstevel@tonic-gate 				}
7997c478bd9Sstevel@tonic-gate 				if (strncmp(arg, "-xchip=", 7) == 0) {
80080ab886dSwesolows 					xlate(ctx->i_ae, arg + 7, xchip_tbl);
8017c478bd9Sstevel@tonic-gate 					break;
8027c478bd9Sstevel@tonic-gate 				}
803d17be682SRichard Lowe 
8047c478bd9Sstevel@tonic-gate 				error(arg);
8057c478bd9Sstevel@tonic-gate 				break;
80654836668Spetede #if defined(__x86)
80754836668Spetede 			case 'm':
80854836668Spetede 				if (strcmp(arg, "-xmodel=kernel") == 0) {
80954836668Spetede 					newae(ctx->i_ae, "-ffreestanding");
81054836668Spetede 					newae(ctx->i_ae, "-mno-red-zone");
81154836668Spetede 					model = "-mcmodel=kernel";
81254836668Spetede 					nolibc = 1;
81354836668Spetede 					break;
81454836668Spetede 				}
81554836668Spetede 				error(arg);
81654836668Spetede 				break;
81754836668Spetede #endif	/* __x86 */
8187c478bd9Sstevel@tonic-gate 			case 'O':
8197c478bd9Sstevel@tonic-gate 				if (strncmp(arg, "-xO", 3) == 0) {
8207c478bd9Sstevel@tonic-gate 					size_t len = strlen(arg);
821538ff303SToomas Soome 					char *s = NULL;
8227c478bd9Sstevel@tonic-gate 					int c = *(arg + 3);
8237c478bd9Sstevel@tonic-gate 					int level;
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 					if (len != 4 || !isdigit(c))
8267c478bd9Sstevel@tonic-gate 						error(arg);
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 					level = atoi(arg + 3);
8297c478bd9Sstevel@tonic-gate 					if (level > 5)
8307c478bd9Sstevel@tonic-gate 						error(arg);
8317c478bd9Sstevel@tonic-gate 					if (level >= 2) {
8327c478bd9Sstevel@tonic-gate 						/*
8337c478bd9Sstevel@tonic-gate 						 * For gcc-3.4.x at -O2 we
8347c478bd9Sstevel@tonic-gate 						 * need to disable optimizations
8357c478bd9Sstevel@tonic-gate 						 * that break ON.
8367c478bd9Sstevel@tonic-gate 						 */
83780ab886dSwesolows 						optim_disable(ctx->i_ae, level);
8387c478bd9Sstevel@tonic-gate 						/*
8397c478bd9Sstevel@tonic-gate 						 * limit -xO3 to -O2 as well.
8407c478bd9Sstevel@tonic-gate 						 */
8417c478bd9Sstevel@tonic-gate 						level = 2;
8427c478bd9Sstevel@tonic-gate 					}
843538ff303SToomas Soome 					if (asprintf(&s, "-O%d", level) == -1)
844538ff303SToomas Soome 						nomem();
84580ab886dSwesolows 					newae(ctx->i_ae, s);
8467c478bd9Sstevel@tonic-gate 					free(s);
8477c478bd9Sstevel@tonic-gate 					break;
8487c478bd9Sstevel@tonic-gate 				}
8497c478bd9Sstevel@tonic-gate 				error(arg);
8507c478bd9Sstevel@tonic-gate 				break;
8517c478bd9Sstevel@tonic-gate 			case 't':
8527c478bd9Sstevel@tonic-gate 				if (strncmp(arg, "-xtarget=", 9) == 0) {
85380ab886dSwesolows 					xlate(ctx->i_ae, arg + 9, xtarget_tbl);
8547c478bd9Sstevel@tonic-gate 					break;
8557c478bd9Sstevel@tonic-gate 				}
8567c478bd9Sstevel@tonic-gate 				error(arg);
8577c478bd9Sstevel@tonic-gate 				break;
8587c478bd9Sstevel@tonic-gate 			default:
8597c478bd9Sstevel@tonic-gate 				error(arg);
8607c478bd9Sstevel@tonic-gate 				break;
8617c478bd9Sstevel@tonic-gate 			}
8627c478bd9Sstevel@tonic-gate 			break;
8637c478bd9Sstevel@tonic-gate 		case 'Y':
8647c478bd9Sstevel@tonic-gate 			if (arglen == 1) {
86580ab886dSwesolows 				if ((arg = *++ctx->i_oldargv) == NULL ||
86680ab886dSwesolows 				    *arg == '\0')
8677c478bd9Sstevel@tonic-gate 					error("-Y");
86880ab886dSwesolows 				ctx->i_oldargc--;
8697c478bd9Sstevel@tonic-gate 				arglen = strlen(arg + 1);
8707c478bd9Sstevel@tonic-gate 			} else {
8717c478bd9Sstevel@tonic-gate 				arg += 2;
8727c478bd9Sstevel@tonic-gate 			}
8737c478bd9Sstevel@tonic-gate 			if (strncmp(arg, "I,", 2) == 0) {
8747c478bd9Sstevel@tonic-gate 				char *s = strdup(arg);
8757c478bd9Sstevel@tonic-gate 				s[0] = '-';
8767c478bd9Sstevel@tonic-gate 				s[1] = 'I';
87780ab886dSwesolows 				newae(ctx->i_ae, "-nostdinc");
87880ab886dSwesolows 				newae(ctx->i_ae, s);
8797c478bd9Sstevel@tonic-gate 				free(s);
8807c478bd9Sstevel@tonic-gate 				break;
8817c478bd9Sstevel@tonic-gate 			}
8827c478bd9Sstevel@tonic-gate 			error(arg);
8837c478bd9Sstevel@tonic-gate 			break;
8847c478bd9Sstevel@tonic-gate 		default:
8857c478bd9Sstevel@tonic-gate 			error(arg);
8867c478bd9Sstevel@tonic-gate 			break;
8877c478bd9Sstevel@tonic-gate 		}
8887c478bd9Sstevel@tonic-gate 	}
8897c478bd9Sstevel@tonic-gate 
890aa9ef484SJohn Levon 	free(nameflag);
891aa9ef484SJohn Levon 
89288e61e85SRichard Lowe 	/*
893*bb9475a1SRobert Mustacchi 	 * We would like to catch occurrences where we have left out a -std
894*bb9475a1SRobert Mustacchi 	 * argument so we don't end up with the compiler's default. The use of
895*bb9475a1SRobert Mustacchi 	 * check_cstd keys on seeing a .c file, which ensures that we don't
896*bb9475a1SRobert Mustacchi 	 * check C++, assembly, or other files, though we should check C++ at
897*bb9475a1SRobert Mustacchi 	 * some point. In addition, if we do a link in a single action, it will
898*bb9475a1SRobert Mustacchi 	 * actually catch it as well because we will see a .c file. However, if
899*bb9475a1SRobert Mustacchi 	 * we're doing a normal link of multiple files then it won't misfire.
900*bb9475a1SRobert Mustacchi 	 */
901*bb9475a1SRobert Mustacchi 	if (check_cstd && !seen_cstd) {
902*bb9475a1SRobert Mustacchi 		errx(2, "missing required -std= specification");
903*bb9475a1SRobert Mustacchi 	}
904*bb9475a1SRobert Mustacchi 
905*bb9475a1SRobert Mustacchi 	/*
90688e61e85SRichard Lowe 	 * When compiling multiple source files in a single invocation some
90788e61e85SRichard Lowe 	 * compilers output objects into the current directory with
90888e61e85SRichard Lowe 	 * predictable and conventional names.
90988e61e85SRichard Lowe 	 *
91088e61e85SRichard Lowe 	 * We prevent any attempt to compile multiple files at once so that
91188e61e85SRichard Lowe 	 * any such objects created by a shadow can't escape into a later
91288e61e85SRichard Lowe 	 * link-edit.
91388e61e85SRichard Lowe 	 */
914*bb9475a1SRobert Mustacchi 	if (src_files > 1 && op != CW_O_PREPROCESS) {
915aa9ef484SJohn Levon 		errx(2, "multiple source files are "
916aa9ef484SJohn Levon 		    "allowed only with -E or -P");
91780ab886dSwesolows 	}
918e521259dSpetede 
919e521259dSpetede 	/*
920e521259dSpetede 	 * Make sure that we do not have any unintended interactions between
921e521259dSpetede 	 * the xarch options passed in and the version of the Studio compiler
922e521259dSpetede 	 * used.
923e521259dSpetede 	 */
924e521259dSpetede 	if ((mflag & (SS11|SS12)) == (SS11|SS12)) {
925aa9ef484SJohn Levon 		errx(2,
926e521259dSpetede 		    "Conflicting \"-xarch=\" flags (both Studio 11 and 12)\n");
927e521259dSpetede 	}
928e521259dSpetede 
929e521259dSpetede 	switch (mflag) {
930e521259dSpetede 	case 0:
931e521259dSpetede 	case M32:
932e521259dSpetede 	case M64:
933e521259dSpetede 	case SS12:
934e521259dSpetede 	case SS11:
935e521259dSpetede 	case (SS11|M32):
936e521259dSpetede 	case (SS11|M64):
937e521259dSpetede 	case (SS12|M32):
938e521259dSpetede 	case (SS12|M64):
939e521259dSpetede 		break;
940e521259dSpetede 	default:
941e521259dSpetede 		(void) fprintf(stderr,
9427a6460b6Spetede 		    "Incompatible -xarch= and/or -m32/-m64 options used.\n");
943e521259dSpetede 		exit(2);
944e521259dSpetede 	}
945aa9ef484SJohn Levon 
94688e61e85SRichard Lowe 	if (ctx->i_flags & CW_F_SHADOW) {
94788e61e85SRichard Lowe 		if (op == CW_O_PREPROCESS)
94880ab886dSwesolows 			exit(0);
949*bb9475a1SRobert Mustacchi 		else if (op == CW_O_LINK && src_files == 0)
95088e61e85SRichard Lowe 			exit(0);
95188e61e85SRichard Lowe 	}
95280ab886dSwesolows 
953e1bf37b1SRichard Lowe 	if (model != NULL)
95480ab886dSwesolows 		newae(ctx->i_ae, model);
9557c478bd9Sstevel@tonic-gate 	if (!nolibc)
95680ab886dSwesolows 		newae(ctx->i_ae, "-lc");
95780ab886dSwesolows 	if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
95880ab886dSwesolows 		newae(ctx->i_ae, "-o");
95988e61e85SRichard Lowe 		newae(ctx->i_ae, discard_file_name(ctx, NULL));
96080ab886dSwesolows 	}
9617c478bd9Sstevel@tonic-gate }
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate static void
do_smatch(cw_ictx_t * ctx)9641f5207b7SJohn Levon do_smatch(cw_ictx_t *ctx)
9651f5207b7SJohn Levon {
9661f5207b7SJohn Levon 	if (ctx->i_flags & CW_F_PROG) {
9671f5207b7SJohn Levon 		newae(ctx->i_ae, "--version");
9681f5207b7SJohn Levon 		return;
9691f5207b7SJohn Levon 	}
9701f5207b7SJohn Levon 
9711f5207b7SJohn Levon 	/*
9721f5207b7SJohn Levon 	 * Some sources shouldn't run smatch at all.
9731f5207b7SJohn Levon 	 */
9741f5207b7SJohn Levon 	for (int i = 0; i < ctx->i_oldargc; i++) {
9751f5207b7SJohn Levon 		char *arg = ctx->i_oldargv[i];
9761f5207b7SJohn Levon 
9771f5207b7SJohn Levon 		if (strcmp(arg, "-_smatch=off") == 0) {
9781f5207b7SJohn Levon 			ctx->i_flags &= ~(CW_F_EXEC | CW_F_ECHO);
9791f5207b7SJohn Levon 			return;
9801f5207b7SJohn Levon 		}
9815d9d9091SRichard Lowe 
9825d9d9091SRichard Lowe 		/* smatch can't handle asm */
9835d9d9091SRichard Lowe 		if ((arg[0] != '-') && is_asm_file(arg)) {
9845d9d9091SRichard Lowe 			ctx->i_flags &= ~(CW_F_EXEC | CW_F_ECHO);
9855d9d9091SRichard Lowe 			return;
9865d9d9091SRichard Lowe 		}
9871f5207b7SJohn Levon 	}
9881f5207b7SJohn Levon 
9891f5207b7SJohn Levon 	/*
9901f5207b7SJohn Levon 	 * smatch can handle gcc's options.
9911f5207b7SJohn Levon 	 */
9921f5207b7SJohn Levon 	do_gcc(ctx);
9931f5207b7SJohn Levon }
9941f5207b7SJohn Levon 
9951f5207b7SJohn Levon static void
do_cc(cw_ictx_t * ctx)99680ab886dSwesolows do_cc(cw_ictx_t *ctx)
9977c478bd9Sstevel@tonic-gate {
99888e61e85SRichard Lowe 	int in_output = 0, seen_o = 0, c_files = 0;
99980ab886dSwesolows 	cw_op_t op = CW_O_LINK;
1000aa9ef484SJohn Levon 	char *nameflag;
10017c478bd9Sstevel@tonic-gate 
10021912d2c4Swesolows 	if (ctx->i_flags & CW_F_PROG) {
10031912d2c4Swesolows 		newae(ctx->i_ae, "-V");
10041912d2c4Swesolows 		return;
10051912d2c4Swesolows 	}
10061912d2c4Swesolows 
1007aa9ef484SJohn Levon 	if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1)
1008aa9ef484SJohn Levon 		nomem();
1009aa9ef484SJohn Levon 
101080ab886dSwesolows 	while (--ctx->i_oldargc > 0) {
101180ab886dSwesolows 		char *arg = *++ctx->i_oldargv;
10127c478bd9Sstevel@tonic-gate 
1013aa9ef484SJohn Levon 		if (strncmp(arg, "-_CC=", 5) == 0) {
1014aa9ef484SJohn Levon 			newae(ctx->i_ae, strchr(arg, '=') + 1);
1015aa9ef484SJohn Levon 			continue;
1016aa9ef484SJohn Levon 		}
1017aa9ef484SJohn Levon 
10187c478bd9Sstevel@tonic-gate 		if (*arg != '-') {
1019*bb9475a1SRobert Mustacchi 			if (!in_output && id_source_file(arg) !=
1020*bb9475a1SRobert Mustacchi 			    SOURCE_FILE_T_NONE)
102188e61e85SRichard Lowe 				c_files++;
102288e61e85SRichard Lowe 
102380ab886dSwesolows 			if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) {
102480ab886dSwesolows 				newae(ctx->i_ae, arg);
102580ab886dSwesolows 			} else {
102680ab886dSwesolows 				in_output = 0;
102788e61e85SRichard Lowe 				newae(ctx->i_ae, discard_file_name(ctx, arg));
102880ab886dSwesolows 			}
102980ab886dSwesolows 			continue;
103080ab886dSwesolows 		}
103180ab886dSwesolows 		switch (*(arg + 1)) {
103280ab886dSwesolows 		case '_':
1033aa9ef484SJohn Levon 			if ((strncmp(arg, nameflag, strlen(nameflag)) == 0) ||
1034aa9ef484SJohn Levon 			    (strncmp(arg, "-_cc=", 5) == 0) ||
1035aa9ef484SJohn Levon 			    (strncmp(arg, "-_sun=", 6) == 0)) {
1036aa9ef484SJohn Levon 				newae(ctx->i_ae, strchr(arg, '=') + 1);
10377c478bd9Sstevel@tonic-gate 			}
103880ab886dSwesolows 			break;
1039aa9ef484SJohn Levon 
104080ab886dSwesolows 		case 'V':
104180ab886dSwesolows 			ctx->i_flags &= ~CW_F_ECHO;
104280ab886dSwesolows 			newae(ctx->i_ae, arg);
104380ab886dSwesolows 			break;
104480ab886dSwesolows 		case 'o':
104580ab886dSwesolows 			seen_o = 1;
104680ab886dSwesolows 			if (strlen(arg) == 2) {
104780ab886dSwesolows 				in_output = 1;
104880ab886dSwesolows 				newae(ctx->i_ae, arg);
104980ab886dSwesolows 			} else if (ctx->i_flags & CW_F_SHADOW) {
105080ab886dSwesolows 				newae(ctx->i_ae, "-o");
105188e61e85SRichard Lowe 				newae(ctx->i_ae, discard_file_name(ctx, arg));
105280ab886dSwesolows 			} else {
105380ab886dSwesolows 				newae(ctx->i_ae, arg);
10547c478bd9Sstevel@tonic-gate 			}
105580ab886dSwesolows 			break;
105680ab886dSwesolows 		case 'c':
105780ab886dSwesolows 		case 'S':
10580bb3415fSrie 			if (strlen(arg) == 2)
105980ab886dSwesolows 				op = CW_O_COMPILE;
106080ab886dSwesolows 			newae(ctx->i_ae, arg);
106180ab886dSwesolows 			break;
106280ab886dSwesolows 		case 'E':
106380ab886dSwesolows 		case 'P':
10640bb3415fSrie 			if (strlen(arg) == 2)
106580ab886dSwesolows 				op = CW_O_PREPROCESS;
106680ab886dSwesolows 		/*FALLTHROUGH*/
106780ab886dSwesolows 		default:
106880ab886dSwesolows 			newae(ctx->i_ae, arg);
106980ab886dSwesolows 		}
107080ab886dSwesolows 	}
107180ab886dSwesolows 
1072aa9ef484SJohn Levon 	free(nameflag);
1073aa9ef484SJohn Levon 
107488e61e85SRichard Lowe 	/* See the comment on this same code in do_gcc() */
107588e61e85SRichard Lowe 	if (c_files > 1 && op != CW_O_PREPROCESS) {
107688e61e85SRichard Lowe 		errx(2, "multiple source files are "
107788e61e85SRichard Lowe 		    "allowed only with -E or -P");
107888e61e85SRichard Lowe 	}
107988e61e85SRichard Lowe 
108088e61e85SRichard Lowe 	if (ctx->i_flags & CW_F_SHADOW) {
108188e61e85SRichard Lowe 		if (op == CW_O_PREPROCESS)
108280ab886dSwesolows 			exit(0);
108388e61e85SRichard Lowe 		else if (op == CW_O_LINK && c_files == 0)
108488e61e85SRichard Lowe 			exit(0);
108588e61e85SRichard Lowe 	}
108680ab886dSwesolows 
108780ab886dSwesolows 	if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
108880ab886dSwesolows 		newae(ctx->i_ae, "-o");
108988e61e85SRichard Lowe 		newae(ctx->i_ae, discard_file_name(ctx, NULL));
109080ab886dSwesolows 	}
109180ab886dSwesolows }
109280ab886dSwesolows 
109380ab886dSwesolows static void
prepctx(cw_ictx_t * ctx)109480ab886dSwesolows prepctx(cw_ictx_t *ctx)
109580ab886dSwesolows {
1096aa9ef484SJohn Levon 	newae(ctx->i_ae, ctx->i_compiler->c_path);
109780ab886dSwesolows 
10981912d2c4Swesolows 	if (ctx->i_flags & CW_F_PROG) {
10991912d2c4Swesolows 		(void) printf("%s: %s\n", (ctx->i_flags & CW_F_SHADOW) ?
1100aa9ef484SJohn Levon 		    "shadow" : "primary", ctx->i_compiler->c_path);
11011912d2c4Swesolows 		(void) fflush(stdout);
11021912d2c4Swesolows 	}
11031912d2c4Swesolows 
110469b1fd3fSRichard Lowe 	/*
110569b1fd3fSRichard Lowe 	 * If LD_ALTEXEC is already set, the expectation would be that that
110669b1fd3fSRichard Lowe 	 * link-editor is run, as such we need to leave it the environment
110769b1fd3fSRichard Lowe 	 * alone and let that happen.
110869b1fd3fSRichard Lowe 	 */
110969b1fd3fSRichard Lowe 	if ((ctx->i_linker != NULL) && (getenv("LD_ALTEXEC") == NULL))
111069b1fd3fSRichard Lowe 		setenv("LD_ALTEXEC", ctx->i_linker, 1);
111169b1fd3fSRichard Lowe 
111280ab886dSwesolows 	if (!(ctx->i_flags & CW_F_XLATE))
111380ab886dSwesolows 		return;
111480ab886dSwesolows 
1115aa9ef484SJohn Levon 	switch (ctx->i_compiler->c_style) {
1116aa9ef484SJohn Levon 	case SUN:
111780ab886dSwesolows 		do_cc(ctx);
111880ab886dSwesolows 		break;
1119aa9ef484SJohn Levon 	case GNU:
112080ab886dSwesolows 		do_gcc(ctx);
112180ab886dSwesolows 		break;
11221f5207b7SJohn Levon 	case SMATCH:
11231f5207b7SJohn Levon 		do_smatch(ctx);
11241f5207b7SJohn Levon 		break;
112580ab886dSwesolows 	}
112680ab886dSwesolows }
112780ab886dSwesolows 
112880ab886dSwesolows static int
invoke(cw_ictx_t * ctx)112980ab886dSwesolows invoke(cw_ictx_t *ctx)
113080ab886dSwesolows {
1131c3d5f7c4SRyan Goodfellow 	char **newargv, *makeflags;
113280ab886dSwesolows 	int ac;
113380ab886dSwesolows 	struct ae *a;
113480ab886dSwesolows 
1135c3d5f7c4SRyan Goodfellow 	newargv = calloc(ctx->i_ae->ael_argc + 1, sizeof (*newargv));
1136c3d5f7c4SRyan Goodfellow 	if (newargv == NULL)
113780ab886dSwesolows 		nomem();
113880ab886dSwesolows 
1139c3d5f7c4SRyan Goodfellow 	/*
1140c3d5f7c4SRyan Goodfellow 	 * Check to see if the silent make flag is present (-s), if so, do not
1141c3d5f7c4SRyan Goodfellow 	 * echo. The MAKEFLAGS environment variable is set by dmake. By
1142c3d5f7c4SRyan Goodfellow 	 * observation it appears to place short flags without any arguments
1143c3d5f7c4SRyan Goodfellow 	 * first followed by any long form flags or flags with arguments.
1144c3d5f7c4SRyan Goodfellow 	 */
1145c3d5f7c4SRyan Goodfellow 	makeflags = getenv("MAKEFLAGS");
1146c3d5f7c4SRyan Goodfellow 	if (makeflags != NULL) {
1147c3d5f7c4SRyan Goodfellow 		size_t makeflags_len = strlen(makeflags);
1148c3d5f7c4SRyan Goodfellow 		for (size_t i = 0; i < makeflags_len; i++) {
1149c3d5f7c4SRyan Goodfellow 			if (makeflags[i] == 's') {
1150c3d5f7c4SRyan Goodfellow 				ctx->i_flags &= ~CW_F_ECHO;
1151c3d5f7c4SRyan Goodfellow 				break;
1152c3d5f7c4SRyan Goodfellow 			}
1153c3d5f7c4SRyan Goodfellow 			/* end of short flags */
1154c3d5f7c4SRyan Goodfellow 			if (makeflags[i] == ' ')
1155c3d5f7c4SRyan Goodfellow 				break;
1156c3d5f7c4SRyan Goodfellow 		}
1157c3d5f7c4SRyan Goodfellow 	}
1158c3d5f7c4SRyan Goodfellow 
115980ab886dSwesolows 	if (ctx->i_flags & CW_F_ECHO)
116080ab886dSwesolows 		(void) fprintf(stderr, "+ ");
116180ab886dSwesolows 
116280ab886dSwesolows 	for (ac = 0, a = ctx->i_ae->ael_head; a; a = a->ae_next, ac++) {
116380ab886dSwesolows 		newargv[ac] = a->ae_arg;
116480ab886dSwesolows 		if (ctx->i_flags & CW_F_ECHO)
116580ab886dSwesolows 			(void) fprintf(stderr, "%s ", a->ae_arg);
116680ab886dSwesolows 		if (a == ctx->i_ae->ael_tail)
116780ab886dSwesolows 			break;
116880ab886dSwesolows 	}
116980ab886dSwesolows 
117080ab886dSwesolows 	if (ctx->i_flags & CW_F_ECHO) {
117180ab886dSwesolows 		(void) fprintf(stderr, "\n");
117280ab886dSwesolows 		(void) fflush(stderr);
117380ab886dSwesolows 	}
117480ab886dSwesolows 
117580ab886dSwesolows 	if (!(ctx->i_flags & CW_F_EXEC))
117680ab886dSwesolows 		return (0);
117780ab886dSwesolows 
117880ab886dSwesolows 	/*
1179aa9ef484SJohn Levon 	 * We must fix up the environment here so that the dependency files are
1180aa9ef484SJohn Levon 	 * not trampled by the shadow compiler. Also take care of GCC
1181aa9ef484SJohn Levon 	 * environment variables that will throw off gcc. This assumes a primary
1182aa9ef484SJohn Levon 	 * gcc.
118380ab886dSwesolows 	 */
118480ab886dSwesolows 	if ((ctx->i_flags & CW_F_SHADOW) &&
118580ab886dSwesolows 	    (unsetenv("SUNPRO_DEPENDENCIES") != 0 ||
1186aa9ef484SJohn Levon 	    unsetenv("DEPENDENCIES_OUTPUT") != 0 ||
1187aa9ef484SJohn Levon 	    unsetenv("GCC_ROOT") != 0)) {
118880ab886dSwesolows 		(void) fprintf(stderr, "error: environment setup failed: %s\n",
118980ab886dSwesolows 		    strerror(errno));
119080ab886dSwesolows 		return (-1);
119180ab886dSwesolows 	}
119280ab886dSwesolows 
119380ab886dSwesolows 	(void) execv(newargv[0], newargv);
1194aa9ef484SJohn Levon 	warn("couldn't run %s", newargv[0]);
119580ab886dSwesolows 
119680ab886dSwesolows 	return (-1);
119780ab886dSwesolows }
119880ab886dSwesolows 
119980ab886dSwesolows static int
reap(cw_ictx_t * ctx)120080ab886dSwesolows reap(cw_ictx_t *ctx)
120180ab886dSwesolows {
12021912d2c4Swesolows 	int status, ret = 0;
120380ab886dSwesolows 	char buf[1024];
120480ab886dSwesolows 	struct stat s;
120580ab886dSwesolows 
1206c3f177eaSPeter Dennis - Sustaining Engineer 	/*
1207c3f177eaSPeter Dennis - Sustaining Engineer 	 * Only wait for one specific child.
1208c3f177eaSPeter Dennis - Sustaining Engineer 	 */
1209c3f177eaSPeter Dennis - Sustaining Engineer 	if (ctx->i_pid <= 0)
1210c3f177eaSPeter Dennis - Sustaining Engineer 		return (-1);
1211c3f177eaSPeter Dennis - Sustaining Engineer 
121280ab886dSwesolows 	do {
1213c3f177eaSPeter Dennis - Sustaining Engineer 		if (waitpid(ctx->i_pid, &status, 0) < 0) {
1214aa9ef484SJohn Levon 			warn("cannot reap child");
1215c3f177eaSPeter Dennis - Sustaining Engineer 			return (-1);
1216c3f177eaSPeter Dennis - Sustaining Engineer 		}
12171912d2c4Swesolows 		if (status != 0) {
12181912d2c4Swesolows 			if (WIFSIGNALED(status)) {
12191912d2c4Swesolows 				ret = -WTERMSIG(status);
122080ab886dSwesolows 				break;
12211912d2c4Swesolows 			} else if (WIFEXITED(status)) {
12221912d2c4Swesolows 				ret = WEXITSTATUS(status);
122380ab886dSwesolows 				break;
122480ab886dSwesolows 			}
122580ab886dSwesolows 		}
12261912d2c4Swesolows 	} while (!WIFEXITED(status) && !WIFSIGNALED(status));
122780ab886dSwesolows 
12281912d2c4Swesolows 	if (stat(ctx->i_stderr, &s) < 0) {
1229aa9ef484SJohn Levon 		warn("stat failed on child cleanup");
123080ab886dSwesolows 		return (-1);
123180ab886dSwesolows 	}
123280ab886dSwesolows 	if (s.st_size != 0) {
12331912d2c4Swesolows 		FILE *f;
123480ab886dSwesolows 
12351912d2c4Swesolows 		if ((f = fopen(ctx->i_stderr, "r")) != NULL) {
123680ab886dSwesolows 			while (fgets(buf, sizeof (buf), f))
123780ab886dSwesolows 				(void) fprintf(stderr, "%s", buf);
123880ab886dSwesolows 			(void) fflush(stderr);
123980ab886dSwesolows 			(void) fclose(f);
124080ab886dSwesolows 		}
12411912d2c4Swesolows 	}
12421912d2c4Swesolows 	(void) unlink(ctx->i_stderr);
12431912d2c4Swesolows 	free(ctx->i_stderr);
12441912d2c4Swesolows 
12451912d2c4Swesolows 	/*
12461912d2c4Swesolows 	 * cc returns an error code when given -V; we want that to succeed.
12471912d2c4Swesolows 	 */
12481912d2c4Swesolows 	if (ctx->i_flags & CW_F_PROG)
12491912d2c4Swesolows 		return (0);
125080ab886dSwesolows 
125180ab886dSwesolows 	return (ret);
125280ab886dSwesolows }
125380ab886dSwesolows 
125480ab886dSwesolows static int
exec_ctx(cw_ictx_t * ctx,int block)125580ab886dSwesolows exec_ctx(cw_ictx_t *ctx, int block)
125680ab886dSwesolows {
125788e61e85SRichard Lowe 	if ((ctx->i_stderr = tempnam(ctx->i_tmpdir, "cw")) == NULL) {
12581912d2c4Swesolows 		nomem();
125980ab886dSwesolows 		return (-1);
126080ab886dSwesolows 	}
126180ab886dSwesolows 
126280ab886dSwesolows 	if ((ctx->i_pid = fork()) == 0) {
12631912d2c4Swesolows 		int fd;
12641912d2c4Swesolows 
126580ab886dSwesolows 		(void) fclose(stderr);
12661912d2c4Swesolows 		if ((fd = open(ctx->i_stderr, O_WRONLY | O_CREAT | O_EXCL,
12671912d2c4Swesolows 		    0666)) < 0) {
1268aa9ef484SJohn Levon 			err(1, "open failed for standard error");
12691912d2c4Swesolows 		}
12701912d2c4Swesolows 		if (dup2(fd, 2) < 0) {
1271aa9ef484SJohn Levon 			err(1, "dup2 failed for standard error");
127280ab886dSwesolows 		}
12731912d2c4Swesolows 		if (fd != 2)
12741912d2c4Swesolows 			(void) close(fd);
127580ab886dSwesolows 		if (freopen("/dev/fd/2", "w", stderr) == NULL) {
1276aa9ef484SJohn Levon 			err(1, "freopen failed for /dev/fd/2");
127780ab886dSwesolows 		}
1278aa9ef484SJohn Levon 
127980ab886dSwesolows 		prepctx(ctx);
128080ab886dSwesolows 		exit(invoke(ctx));
128180ab886dSwesolows 	}
128280ab886dSwesolows 
128380ab886dSwesolows 	if (ctx->i_pid < 0) {
1284aa9ef484SJohn Levon 		err(1, "fork failed");
128580ab886dSwesolows 	}
128680ab886dSwesolows 
128780ab886dSwesolows 	if (block)
128880ab886dSwesolows 		return (reap(ctx));
128980ab886dSwesolows 
129080ab886dSwesolows 	return (0);
12917c478bd9Sstevel@tonic-gate }
12927c478bd9Sstevel@tonic-gate 
1293aa9ef484SJohn Levon static void
parse_compiler(const char * spec,cw_compiler_t * compiler)1294aa9ef484SJohn Levon parse_compiler(const char *spec, cw_compiler_t *compiler)
1295aa9ef484SJohn Levon {
1296aa9ef484SJohn Levon 	char *tspec, *token;
1297aa9ef484SJohn Levon 
1298aa9ef484SJohn Levon 	if ((tspec = strdup(spec)) == NULL)
1299aa9ef484SJohn Levon 		nomem();
1300aa9ef484SJohn Levon 
1301aa9ef484SJohn Levon 	if ((token = strsep(&tspec, ",")) == NULL)
1302aa9ef484SJohn Levon 		errx(1, "Compiler is missing a name: %s", spec);
1303aa9ef484SJohn Levon 	compiler->c_name = token;
1304aa9ef484SJohn Levon 
1305aa9ef484SJohn Levon 	if ((token = strsep(&tspec, ",")) == NULL)
1306aa9ef484SJohn Levon 		errx(1, "Compiler is missing a path: %s", spec);
1307aa9ef484SJohn Levon 	compiler->c_path = token;
1308aa9ef484SJohn Levon 
1309aa9ef484SJohn Levon 	if ((token = strsep(&tspec, ",")) == NULL)
1310aa9ef484SJohn Levon 		errx(1, "Compiler is missing a style: %s", spec);
1311aa9ef484SJohn Levon 
1312aa9ef484SJohn Levon 	if ((strcasecmp(token, "gnu") == 0) ||
13131f5207b7SJohn Levon 	    (strcasecmp(token, "gcc") == 0)) {
1314aa9ef484SJohn Levon 		compiler->c_style = GNU;
13151f5207b7SJohn Levon 	} else if ((strcasecmp(token, "sun") == 0) ||
13161f5207b7SJohn Levon 	    (strcasecmp(token, "cc") == 0)) {
1317aa9ef484SJohn Levon 		compiler->c_style = SUN;
13181f5207b7SJohn Levon 	} else if ((strcasecmp(token, "smatch") == 0)) {
13191f5207b7SJohn Levon 		compiler->c_style = SMATCH;
13201f5207b7SJohn Levon 	} else {
1321aa9ef484SJohn Levon 		errx(1, "unknown compiler style: %s", token);
13221f5207b7SJohn Levon 	}
1323aa9ef484SJohn Levon 
1324aa9ef484SJohn Levon 	if (tspec != NULL)
1325aa9ef484SJohn Levon 		errx(1, "Excess tokens in compiler: %s", spec);
1326aa9ef484SJohn Levon }
1327aa9ef484SJohn Levon 
132888e61e85SRichard Lowe static void
cleanup(cw_ictx_t * ctx)132988e61e85SRichard Lowe cleanup(cw_ictx_t *ctx)
133088e61e85SRichard Lowe {
133188e61e85SRichard Lowe 	DIR *dirp;
133288e61e85SRichard Lowe 	struct dirent *dp;
133388e61e85SRichard Lowe 	char buf[MAXPATHLEN];
133488e61e85SRichard Lowe 
133588e61e85SRichard Lowe 	if ((dirp = opendir(ctx->i_tmpdir)) == NULL) {
133688e61e85SRichard Lowe 		if (errno != ENOENT) {
133788e61e85SRichard Lowe 			err(1, "couldn't open temp directory: %s",
133888e61e85SRichard Lowe 			    ctx->i_tmpdir);
133988e61e85SRichard Lowe 		} else {
134088e61e85SRichard Lowe 			return;
134188e61e85SRichard Lowe 		}
134288e61e85SRichard Lowe 	}
134388e61e85SRichard Lowe 
134488e61e85SRichard Lowe 	errno = 0;
134588e61e85SRichard Lowe 	while ((dp = readdir(dirp)) != NULL) {
134688e61e85SRichard Lowe 		(void) snprintf(buf, MAXPATHLEN, "%s/%s", ctx->i_tmpdir,
134788e61e85SRichard Lowe 		    dp->d_name);
134888e61e85SRichard Lowe 
134988e61e85SRichard Lowe 		if (strcmp(dp->d_name, ".") == 0 ||
135088e61e85SRichard Lowe 		    strcmp(dp->d_name, "..") == 0) {
135188e61e85SRichard Lowe 			continue;
135288e61e85SRichard Lowe 		}
135388e61e85SRichard Lowe 
135488e61e85SRichard Lowe 		if (unlink(buf) == -1)
135588e61e85SRichard Lowe 			err(1, "failed to unlink temp file: %s", dp->d_name);
135688e61e85SRichard Lowe 		errno = 0;
135788e61e85SRichard Lowe 	}
135888e61e85SRichard Lowe 
135988e61e85SRichard Lowe 	if (errno != 0) {
136088e61e85SRichard Lowe 		err(1, "failed to read temporary directory: %s",
136188e61e85SRichard Lowe 		    ctx->i_tmpdir);
136288e61e85SRichard Lowe 	}
136388e61e85SRichard Lowe 
136488e61e85SRichard Lowe 	(void) closedir(dirp);
136588e61e85SRichard Lowe 	if (rmdir(ctx->i_tmpdir) != 0) {
136688e61e85SRichard Lowe 		err(1, "failed to unlink temporary directory: %s",
136788e61e85SRichard Lowe 		    ctx->i_tmpdir);
136888e61e85SRichard Lowe 	}
136988e61e85SRichard Lowe }
137088e61e85SRichard Lowe 
13717c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)13727c478bd9Sstevel@tonic-gate main(int argc, char **argv)
13737c478bd9Sstevel@tonic-gate {
1374aa9ef484SJohn Levon 	int ch;
1375aa9ef484SJohn Levon 	cw_compiler_t primary = { NULL, NULL, 0 };
1376aa9ef484SJohn Levon 	cw_compiler_t shadows[10];
1377aa9ef484SJohn Levon 	int nshadows = 0;
137880ab886dSwesolows 	int ret = 0;
137922a8b493SToomas Soome 	bool do_serial;
138022a8b493SToomas Soome 	bool do_exec;
138122a8b493SToomas Soome 	bool vflg = false;
138222a8b493SToomas Soome 	bool Cflg = false;
138322a8b493SToomas Soome 	bool cflg = false;
138422a8b493SToomas Soome 	bool nflg = false;
138588e61e85SRichard Lowe 	char *tmpdir;
13867c478bd9Sstevel@tonic-gate 
1387aa9ef484SJohn Levon 	cw_ictx_t *main_ctx;
13887c478bd9Sstevel@tonic-gate 
1389aa9ef484SJohn Levon 	static struct option longopts[] = {
1390aa9ef484SJohn Levon 		{ "compiler", no_argument, NULL, 'c' },
139169b1fd3fSRichard Lowe 		{ "linker", required_argument, NULL, 'l' },
1392aa9ef484SJohn Levon 		{ "noecho", no_argument, NULL, 'n' },
1393aa9ef484SJohn Levon 		{ "primary", required_argument, NULL, 'p' },
1394aa9ef484SJohn Levon 		{ "shadow", required_argument, NULL, 's' },
13959b9d39d2SRichard Lowe 		{ "tag", required_argument, NULL, 't' },
1396aa9ef484SJohn Levon 		{ "versions", no_argument, NULL, 'v' },
1397aa9ef484SJohn Levon 		{ NULL, 0, NULL, 0 },
1398aa9ef484SJohn Levon 	};
1399aa9ef484SJohn Levon 
1400aa9ef484SJohn Levon 
1401aa9ef484SJohn Levon 	if ((main_ctx = newictx()) == NULL)
140280ab886dSwesolows 		nomem();
140380ab886dSwesolows 
1404aa9ef484SJohn Levon 	while ((ch = getopt_long(argc, argv, "C", longopts, NULL)) != -1) {
1405aa9ef484SJohn Levon 		switch (ch) {
1406aa9ef484SJohn Levon 		case 'c':
140722a8b493SToomas Soome 			cflg = true;
1408aa9ef484SJohn Levon 			break;
1409aa9ef484SJohn Levon 		case 'C':
141022a8b493SToomas Soome 			Cflg = true;
1411aa9ef484SJohn Levon 			break;
141269b1fd3fSRichard Lowe 		case 'l':
141369b1fd3fSRichard Lowe 			if ((main_ctx->i_linker = strdup(optarg)) == NULL)
141469b1fd3fSRichard Lowe 				nomem();
141569b1fd3fSRichard Lowe 			break;
1416aa9ef484SJohn Levon 		case 'n':
141722a8b493SToomas Soome 			nflg = true;
1418aa9ef484SJohn Levon 			break;
1419aa9ef484SJohn Levon 		case 'p':
1420aa9ef484SJohn Levon 			if (primary.c_path != NULL) {
1421aa9ef484SJohn Levon 				warnx("Only one primary compiler may "
1422aa9ef484SJohn Levon 				    "be specified");
14237c478bd9Sstevel@tonic-gate 				usage();
14247c478bd9Sstevel@tonic-gate 			}
14257c478bd9Sstevel@tonic-gate 
1426aa9ef484SJohn Levon 			parse_compiler(optarg, &primary);
1427aa9ef484SJohn Levon 			break;
1428aa9ef484SJohn Levon 		case 's':
1429aa9ef484SJohn Levon 			if (nshadows >= 10)
1430aa9ef484SJohn Levon 				errx(1, "May only use 10 shadows at "
1431aa9ef484SJohn Levon 				    "the moment");
1432aa9ef484SJohn Levon 			parse_compiler(optarg, &shadows[nshadows]);
1433aa9ef484SJohn Levon 			nshadows++;
1434aa9ef484SJohn Levon 			break;
14359b9d39d2SRichard Lowe 		case 't':	/* Ignored, a diagnostic in build logs only */
14369b9d39d2SRichard Lowe 			break;
1437aa9ef484SJohn Levon 		case 'v':
143822a8b493SToomas Soome 			vflg = true;
1439aa9ef484SJohn Levon 			break;
1440aa9ef484SJohn Levon 		default:
1441aa9ef484SJohn Levon 			(void) fprintf(stderr, "Did you forget '--'?\n");
1442aa9ef484SJohn Levon 			usage();
1443aa9ef484SJohn Levon 		}
14447c478bd9Sstevel@tonic-gate 	}
14457c478bd9Sstevel@tonic-gate 
1446aa9ef484SJohn Levon 	if (primary.c_path == NULL) {
1447aa9ef484SJohn Levon 		warnx("A primary compiler must be specified");
1448aa9ef484SJohn Levon 		usage();
1449aa9ef484SJohn Levon 	}
1450aa9ef484SJohn Levon 
145122a8b493SToomas Soome 	do_serial = getenv("CW_SHADOW_SERIAL") != NULL;
145222a8b493SToomas Soome 	do_exec = getenv("CW_NO_EXEC") == NULL;
1453aa9ef484SJohn Levon 
1454aa9ef484SJohn Levon 	/* Leave room for argv[0] */
1455aa9ef484SJohn Levon 	argc -= (optind - 1);
1456aa9ef484SJohn Levon 	argv += (optind - 1);
1457aa9ef484SJohn Levon 
1458aa9ef484SJohn Levon 	main_ctx->i_oldargc = argc;
1459aa9ef484SJohn Levon 	main_ctx->i_oldargv = argv;
1460aa9ef484SJohn Levon 	main_ctx->i_flags = CW_F_XLATE;
1461aa9ef484SJohn Levon 	if (nflg == 0)
1462aa9ef484SJohn Levon 		main_ctx->i_flags |= CW_F_ECHO;
1463aa9ef484SJohn Levon 	if (do_exec)
1464aa9ef484SJohn Levon 		main_ctx->i_flags |= CW_F_EXEC;
1465aa9ef484SJohn Levon 	if (Cflg)
1466aa9ef484SJohn Levon 		main_ctx->i_flags |= CW_F_CXX;
1467aa9ef484SJohn Levon 	main_ctx->i_compiler = &primary;
1468aa9ef484SJohn Levon 
1469aa9ef484SJohn Levon 	if (cflg) {
1470aa9ef484SJohn Levon 		(void) fputs(primary.c_path, stdout);
1471aa9ef484SJohn Levon 	}
1472aa9ef484SJohn Levon 
1473aa9ef484SJohn Levon 	if (vflg) {
1474aa9ef484SJohn Levon 		(void) printf("cw version %s\n", CW_VERSION);
14751912d2c4Swesolows 		(void) fflush(stdout);
1476aa9ef484SJohn Levon 		main_ctx->i_flags &= ~CW_F_ECHO;
1477aa9ef484SJohn Levon 		main_ctx->i_flags |= CW_F_PROG | CW_F_EXEC;
14781912d2c4Swesolows 		do_serial = 1;
14791912d2c4Swesolows 	}
14801912d2c4Swesolows 
148188e61e85SRichard Lowe 	tmpdir = getenv("TMPDIR");
148288e61e85SRichard Lowe 	if (tmpdir == NULL)
148388e61e85SRichard Lowe 		tmpdir = "/tmp";
148488e61e85SRichard Lowe 
148588e61e85SRichard Lowe 	if (asprintf(&main_ctx->i_tmpdir, "%s/cw.XXXXXX", tmpdir) == -1)
148688e61e85SRichard Lowe 		nomem();
148788e61e85SRichard Lowe 
148888e61e85SRichard Lowe 	if ((main_ctx->i_tmpdir = mkdtemp(main_ctx->i_tmpdir)) == NULL)
148988e61e85SRichard Lowe 		errx(1, "failed to create temporary directory");
149088e61e85SRichard Lowe 
1491aa9ef484SJohn Levon 	ret |= exec_ctx(main_ctx, do_serial);
14921912d2c4Swesolows 
1493aa9ef484SJohn Levon 	for (int i = 0; i < nshadows; i++) {
1494aa9ef484SJohn Levon 		int r;
1495aa9ef484SJohn Levon 		cw_ictx_t *shadow_ctx;
149680ab886dSwesolows 
1497aa9ef484SJohn Levon 		if ((shadow_ctx = newictx()) == NULL)
1498aa9ef484SJohn Levon 			nomem();
1499aa9ef484SJohn Levon 
150088e61e85SRichard Lowe 		(void) memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t));
1501aa9ef484SJohn Levon 
1502aa9ef484SJohn Levon 		shadow_ctx->i_flags |= CW_F_SHADOW;
1503aa9ef484SJohn Levon 		shadow_ctx->i_compiler = &shadows[i];
1504aa9ef484SJohn Levon 
1505aa9ef484SJohn Levon 		r = exec_ctx(shadow_ctx, do_serial);
1506aa9ef484SJohn Levon 		if (r == 0) {
1507aa9ef484SJohn Levon 			shadow_ctx->i_next = main_ctx->i_next;
1508aa9ef484SJohn Levon 			main_ctx->i_next = shadow_ctx;
1509aa9ef484SJohn Levon 		}
1510aa9ef484SJohn Levon 		ret |= r;
15117c478bd9Sstevel@tonic-gate 	}
15127c478bd9Sstevel@tonic-gate 
1513aa9ef484SJohn Levon 	if (!do_serial) {
1514aa9ef484SJohn Levon 		cw_ictx_t *next = main_ctx;
1515aa9ef484SJohn Levon 		while (next != NULL) {
1516aa9ef484SJohn Levon 			cw_ictx_t *toreap = next;
1517aa9ef484SJohn Levon 			next = next->i_next;
1518aa9ef484SJohn Levon 			ret |= reap(toreap);
1519aa9ef484SJohn Levon 		}
1520aa9ef484SJohn Levon 	}
15217c478bd9Sstevel@tonic-gate 
152288e61e85SRichard Lowe 	cleanup(main_ctx);
152380ab886dSwesolows 	return (ret);
15247c478bd9Sstevel@tonic-gate }
1525