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