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