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 2006 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 * -Wu,-save_args -msave-args 229 * -w pass-thru 230 * -Xa -std=iso9899:199409 or -ansi 231 * -Xc -ansi -pedantic 232 * -Xt error 233 * -Xs -traditional -std=c89 234 * -x386 -march=i386 (x86 only) 235 * -x486 -march=i486 (x86 only) 236 * -xarch=<a> table 237 * -xbuiltin[=<b>] -fbuiltin (-fno-builtin otherwise) 238 * -xCC ignore 239 * -xchar_byte_order=<o> error 240 * -xchip=<c> table 241 * -xcode=<c> table 242 * -xdebugformat=<format> ignore (always use dwarf-2 for gcc) 243 * -xcrossfile[=<n>] ignore 244 * -xe error 245 * -xF error 246 * -xhelp=<f> error 247 * -xildoff ignore 248 * -xildon ignore 249 * -xinline ignore 250 * -xlibmieee error 251 * -xlibmil error 252 * -xlic_lib=sunperf error 253 * -xM -M 254 * -xM1 -MM 255 * -xmaxopt=[...] error 256 * -xnolib -nodefaultlibs 257 * -xnolibmil error 258 * -xO<n> -O<n> 259 * -xP error 260 * -xpentium -march=pentium (x86 only) 261 * -xpg error 262 * -xprofile=<p> error 263 * -xregs=<r> table 264 * -xs error 265 * -xsb error 266 * -xsbfast error 267 * -xsfpconst error 268 * -xspace ignore (-not -Os) 269 * -xstrconst ignore 270 * -xtarget=<t> table 271 * -xtemp=<dir> error 272 * -xtime error 273 * -xtransition -Wtransition 274 * -xtrigraphs=<yes|no> -trigraphs -notrigraphs 275 * -xunroll=n error 276 * -W0,-xdbggen=no%usedonly -fno-eliminate-unused-debug-symbols 277 * -fno-eliminate-unused-debug-types 278 * -Y<c>,<dir> error 279 * -YA,<dir> error 280 * -YI,<dir> -nostdinc -I<dir> 281 * -YP,<dir> error 282 * -YS,<dir> error 283 */ 284 285 #include <stdio.h> 286 #include <sys/types.h> 287 #include <unistd.h> 288 #include <string.h> 289 #include <stdlib.h> 290 #include <ctype.h> 291 #include <fcntl.h> 292 #include <errno.h> 293 #include <stdarg.h> 294 #include <sys/utsname.h> 295 #include <sys/param.h> 296 #include <sys/isa_defs.h> 297 #include <sys/wait.h> 298 #include <sys/stat.h> 299 300 #define CW_F_CXX 0x01 301 #define CW_F_SHADOW 0x02 302 #define CW_F_EXEC 0x04 303 #define CW_F_ECHO 0x08 304 #define CW_F_XLATE 0x10 305 #define CW_F_PROG 0x20 306 307 typedef enum cw_compiler { 308 CW_C_CC = 0, 309 CW_C_GCC 310 } cw_compiler_t; 311 312 static const char *cmds[] = { 313 "cc", "CC", 314 "gcc", "g++" 315 }; 316 317 static const char *dirs[] = { 318 DEFAULT_CC_DIR, DEFAULT_CPLUSPLUS_DIR, 319 DEFAULT_GCC_DIR, DEFAULT_GPLUSPLUS_DIR 320 }; 321 322 #define CC(ctx) \ 323 (((ctx)->i_flags & CW_F_SHADOW) ? \ 324 ((ctx)->i_compiler == CW_C_CC ? CW_C_GCC : CW_C_CC) : \ 325 (ctx)->i_compiler) 326 327 #define CIDX(compiler, flags) \ 328 ((int)(compiler) << 1) + ((flags) & CW_F_CXX ? 1 : 0) 329 330 typedef enum cw_op { 331 CW_O_NONE = 0, 332 CW_O_PREPROCESS, 333 CW_O_COMPILE, 334 CW_O_LINK 335 } cw_op_t; 336 337 struct aelist { 338 struct ae { 339 struct ae *ae_next; 340 char *ae_arg; 341 } *ael_head, *ael_tail; 342 int ael_argc; 343 }; 344 345 typedef struct cw_ictx { 346 cw_compiler_t i_compiler; 347 struct aelist *i_ae; 348 uint32_t i_flags; 349 int i_oldargc; 350 char **i_oldargv; 351 pid_t i_pid; 352 char i_discard[MAXPATHLEN]; 353 char *i_stderr; 354 } cw_ictx_t; 355 356 static const char *progname; 357 358 static const char *xarch_tbl[] = { 359 #if defined(__x86) 360 "generic", NULL, 361 "generic64", "-m64", "-mtune=opteron", NULL, 362 "amd64", "-m64", "-mtune=opteron", NULL, 363 "386", "-march=i386", NULL, 364 "pentium_pro", "-march=pentiumpro", NULL, 365 #elif defined(__sparc) 366 "generic", "-m32", "-mcpu=v8", NULL, 367 "generic64", "-m64", "-mcpu=v9", NULL, 368 "v8", "-m32", "-mcpu=v8", "-mno-v8plus", NULL, 369 "v8plus", "-m32", "-mcpu=v9", "-mv8plus", NULL, 370 "v8plusa", "-m32", "-mcpu=ultrasparc", "-mv8plus", "-mvis", NULL, 371 "v8plusb", "-m32", "-mcpu=ultrasparc3", "-mv8plus", "-mvis", NULL, 372 "v9", "-m64", "-mcpu=v9", NULL, 373 "v9a", "-m64", "-mcpu=ultrasparc", "-mvis", NULL, 374 "v9b", "-m64", "-mcpu=ultrasparc3", "-mvis", NULL, 375 #endif 376 NULL, NULL 377 }; 378 379 static const char *xchip_tbl[] = { 380 #if defined(__x86) 381 "386", "-mtune=i386", NULL, 382 "486", "-mtune=i486", NULL, 383 "pentium", "-mtune=pentium", NULL, 384 "pentium_pro", "-mtune=pentiumpro", NULL, 385 #elif defined(__sparc) 386 "super", "-mtune=supersparc", NULL, 387 "ultra", "-mtune=ultrasparc", NULL, 388 "ultra3", "-mtune=ultrasparc3", NULL, 389 #endif 390 NULL, NULL 391 }; 392 393 static const char *xcode_tbl[] = { 394 #if defined(__sparc) 395 "abs32", "-fno-pic", "-mcmodel=medlow", NULL, 396 "abs44", "-fno-pic", "-mcmodel=medmid", NULL, 397 "abs64", "-fno-pic", "-mcmodel=medany", NULL, 398 "pic13", "-fpic", NULL, 399 "pic32", "-fPIC", NULL, 400 #endif 401 NULL, NULL 402 }; 403 404 static const char *xtarget_tbl[] = { 405 #if defined(__x86) 406 "pentium_pro", "-march=pentiumpro", NULL, 407 #endif /* __x86 */ 408 NULL, NULL 409 }; 410 411 static const char *xregs_tbl[] = { 412 #if defined(__sparc) 413 "appl", "-mapp-regs", NULL, 414 "no%appl", "-mno-app-regs", NULL, 415 "float", "-mfpu", NULL, 416 "no%float", "-mno-fpu", NULL, 417 #endif /* __sparc */ 418 NULL, NULL 419 }; 420 421 static void 422 nomem(void) 423 { 424 (void) fprintf(stderr, "%s: error: out of memory\n", progname); 425 exit(1); 426 } 427 428 static void 429 cw_perror(const char *fmt, ...) 430 { 431 va_list ap; 432 int saved_errno = errno; 433 434 (void) fprintf(stderr, "%s: error: ", progname); 435 436 va_start(ap, fmt); 437 (void) vfprintf(stderr, fmt, ap); 438 va_end(ap); 439 440 (void) fprintf(stderr, " (%s)\n", strerror(saved_errno)); 441 } 442 443 static void 444 newae(struct aelist *ael, const char *arg) 445 { 446 struct ae *ae; 447 448 if ((ae = calloc(sizeof (*ae), 1)) == NULL) 449 nomem(); 450 ae->ae_arg = strdup(arg); 451 if (ael->ael_tail == NULL) 452 ael->ael_head = ae; 453 else 454 ael->ael_tail->ae_next = ae; 455 ael->ael_tail = ae; 456 ael->ael_argc++; 457 } 458 459 static cw_ictx_t * 460 newictx(void) 461 { 462 cw_ictx_t *ctx = calloc(sizeof (cw_ictx_t), 1); 463 if (ctx) 464 if ((ctx->i_ae = calloc(sizeof (struct aelist), 1)) == NULL) { 465 free(ctx); 466 return (NULL); 467 } 468 469 return (ctx); 470 } 471 472 static void 473 error(const char *arg) 474 { 475 (void) fprintf(stderr, 476 "%s: error: mapping failed at or near arg '%s'\n", progname, arg); 477 exit(2); 478 } 479 480 /* 481 * Add the current favourite set of warnings to the gcc invocation. 482 */ 483 static void 484 warnings(struct aelist *h) 485 { 486 static int warningsonce; 487 488 if (warningsonce++) 489 return; 490 491 newae(h, "-Wall"); 492 newae(h, "-Wno-unknown-pragmas"); 493 newae(h, "-Wno-missing-braces"); 494 newae(h, "-Wno-sign-compare"); 495 newae(h, "-Wno-parentheses"); 496 newae(h, "-Wno-uninitialized"); 497 newae(h, "-Wno-implicit-function-declaration"); 498 newae(h, "-Wno-unused"); 499 newae(h, "-Wno-trigraphs"); 500 newae(h, "-Wno-char-subscripts"); 501 newae(h, "-Wno-switch"); 502 } 503 504 static void 505 optim_disable(struct aelist *h, int level) 506 { 507 if (level >= 2) { 508 newae(h, "-fno-strict-aliasing"); 509 newae(h, "-fno-unit-at-a-time"); 510 newae(h, "-fno-optimize-sibling-calls"); 511 } 512 } 513 514 /* ARGSUSED */ 515 static void 516 Xamode(struct aelist *h) 517 { 518 } 519 520 static void 521 Xcmode(struct aelist *h) 522 { 523 static int xconce; 524 525 if (xconce++) 526 return; 527 528 newae(h, "-ansi"); 529 newae(h, "-pedantic-errors"); 530 } 531 532 static void 533 Xsmode(struct aelist *h) 534 { 535 static int xsonce; 536 537 if (xsonce++) 538 return; 539 540 newae(h, "-traditional"); 541 newae(h, "-traditional-cpp"); 542 } 543 544 static void 545 usage() 546 { 547 (void) fprintf(stderr, 548 "usage: %s { -_cc | -_gcc | -_CC | -_g++ } [ -_compiler | ... ]\n", 549 progname); 550 exit(2); 551 } 552 553 static void 554 xlate(struct aelist *h, const char *xarg, const char **table) 555 { 556 while (*table != NULL && strcmp(xarg, *table) != 0) { 557 while (*table != NULL) 558 table++; 559 table++; 560 } 561 562 if (*table == NULL) 563 error(xarg); 564 565 table++; 566 567 while (*table != NULL) { 568 newae(h, *table); 569 table++; 570 } 571 } 572 573 static void 574 do_gcc(cw_ictx_t *ctx) 575 { 576 int c; 577 int pic = 0, nolibc = 0; 578 int in_output = 0, seen_o = 0, c_files = 0; 579 cw_op_t op = CW_O_LINK; 580 char *model = NULL; 581 582 if (ctx->i_flags & CW_F_PROG) { 583 newae(ctx->i_ae, "--version"); 584 return; 585 } 586 587 newae(ctx->i_ae, "-fident"); 588 newae(ctx->i_ae, "-finline"); 589 newae(ctx->i_ae, "-fno-inline-functions"); 590 newae(ctx->i_ae, "-fno-builtin"); 591 newae(ctx->i_ae, "-fno-asm"); 592 newae(ctx->i_ae, "-nodefaultlibs"); 593 594 #if defined(__sparc) 595 /* 596 * The SPARC ldd and std instructions require 8-byte alignment of 597 * their address operand. gcc correctly uses them only when the 598 * ABI requires 8-byte alignment; unfortunately we have a number of 599 * pieces of buggy code that doesn't conform to the ABI. This 600 * flag makes gcc work more like Studio with -xmemalign=4. 601 */ 602 newae(ctx->i_ae, "-mno-integer-ldd-std"); 603 #endif 604 605 /* 606 * This is needed because 'u' is defined 607 * under a conditional on 'sun'. Should 608 * probably just remove the conditional, 609 * or make it be dependent on '__sun'. 610 * 611 * -Dunix is also missing in enhanced ANSI mode 612 */ 613 newae(ctx->i_ae, "-D__sun"); 614 615 /* 616 * Walk the argument list, translating as we go .. 617 */ 618 619 while (--ctx->i_oldargc > 0) { 620 char *arg = *++ctx->i_oldargv; 621 size_t arglen = strlen(arg); 622 623 if (*arg == '-') { 624 arglen--; 625 } else { 626 /* 627 * Discard inline files that gcc doesn't grok 628 */ 629 if (!in_output && arglen > 3 && 630 strcmp(arg + arglen - 3, ".il") == 0) 631 continue; 632 633 if (!in_output && arglen > 2 && 634 arg[arglen - 2] == '.' && 635 (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' || 636 arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i')) 637 c_files++; 638 639 /* 640 * Otherwise, filenames and partial arguments 641 * are passed through for gcc to chew on. However, 642 * output is always discarded for the secondary 643 * compiler. 644 */ 645 if ((ctx->i_flags & CW_F_SHADOW) && in_output) 646 newae(ctx->i_ae, ctx->i_discard); 647 else 648 newae(ctx->i_ae, arg); 649 in_output = 0; 650 continue; 651 } 652 653 if (ctx->i_flags & CW_F_CXX) { 654 if (strncmp(arg, "-compat=", 8) == 0) { 655 /* discard -compat=4 and -compat=5 */ 656 continue; 657 } 658 if (strcmp(arg, "-Qoption") == 0) { 659 /* discard -Qoption and its two arguments */ 660 if (ctx->i_oldargc < 3) 661 error(arg); 662 ctx->i_oldargc -= 2; 663 ctx->i_oldargv += 2; 664 continue; 665 } 666 if (strcmp(arg, "-xwe") == 0) { 667 /* turn warnings into errors */ 668 newae(ctx->i_ae, "-Werror"); 669 continue; 670 } 671 if (strcmp(arg, "-noex") == 0) { 672 /* no exceptions */ 673 newae(ctx->i_ae, "-fno-exceptions"); 674 /* no run time type descriptor information */ 675 newae(ctx->i_ae, "-fno-rtti"); 676 continue; 677 } 678 if (strcmp(arg, "-pic") == 0) { 679 newae(ctx->i_ae, "-fpic"); 680 pic = 1; 681 continue; 682 } 683 if (strcmp(arg, "-PIC") == 0) { 684 newae(ctx->i_ae, "-fPIC"); 685 pic = 1; 686 continue; 687 } 688 if (strcmp(arg, "-norunpath") == 0) { 689 /* gcc has no corresponding option */ 690 continue; 691 } 692 if (strcmp(arg, "-nolib") == 0) { 693 /* -nodefaultlibs is on by default */ 694 nolibc = 1; 695 continue; 696 } 697 #if defined(__sparc) 698 if (strcmp(arg, "-cg92") == 0) { 699 xlate(ctx->i_ae, "v8", xarch_tbl); 700 xlate(ctx->i_ae, "super", xchip_tbl); 701 continue; 702 } 703 #endif /* __sparc */ 704 } 705 706 switch ((c = arg[1])) { 707 case '_': 708 if (strcmp(arg, "-_noecho") == 0) 709 ctx->i_flags &= ~CW_F_ECHO; 710 else if (strncmp(arg, "-_cc=", 5) == 0 || 711 strncmp(arg, "-_CC=", 5) == 0) 712 /* EMPTY */; 713 else if (strncmp(arg, "-_gcc=", 6) == 0 || 714 strncmp(arg, "-_g++=", 6) == 0) 715 newae(ctx->i_ae, arg + 6); 716 else 717 error(arg); 718 break; 719 case '#': 720 if (arglen == 1) { 721 newae(ctx->i_ae, "-v"); 722 break; 723 } 724 error(arg); 725 break; 726 case 'g': 727 newae(ctx->i_ae, "-gdwarf-2"); 728 break; 729 case 'E': 730 if (arglen == 1) { 731 newae(ctx->i_ae, "-xc"); 732 newae(ctx->i_ae, arg); 733 op = CW_O_PREPROCESS; 734 nolibc = 1; 735 break; 736 } 737 error(arg); 738 break; 739 case 'c': 740 case 'S': 741 if (arglen == 1) { 742 op = CW_O_COMPILE; 743 nolibc = 1; 744 } 745 /* FALLTHROUGH */ 746 case 'C': 747 case 'H': 748 case 'p': 749 if (arglen == 1) { 750 newae(ctx->i_ae, arg); 751 break; 752 } 753 error(arg); 754 break; 755 case 'A': 756 case 'h': 757 case 'I': 758 case 'i': 759 case 'L': 760 case 'l': 761 case 'R': 762 case 'U': 763 case 'u': 764 case 'w': 765 newae(ctx->i_ae, arg); 766 break; 767 case 'o': 768 seen_o = 1; 769 if (arglen == 1) { 770 in_output = 1; 771 newae(ctx->i_ae, arg); 772 } else if (ctx->i_flags & CW_F_SHADOW) { 773 newae(ctx->i_ae, "-o"); 774 newae(ctx->i_ae, ctx->i_discard); 775 } else { 776 newae(ctx->i_ae, arg); 777 } 778 break; 779 case 'D': 780 newae(ctx->i_ae, arg); 781 /* 782 * XXX Clearly a hack ... do we need _KADB too? 783 */ 784 if (strcmp(arg, "-D_KERNEL") == 0 || 785 strcmp(arg, "-D_BOOT") == 0) 786 newae(ctx->i_ae, "-ffreestanding"); 787 break; 788 case 'd': 789 if (arglen == 2) { 790 if (strcmp(arg, "-dy") == 0) { 791 newae(ctx->i_ae, "-Wl,-dy"); 792 break; 793 } 794 if (strcmp(arg, "-dn") == 0) { 795 newae(ctx->i_ae, "-Wl,-dn"); 796 break; 797 } 798 } 799 if (strcmp(arg, "-dalign") == 0) { 800 /* 801 * -dalign forces alignment in some cases; 802 * gcc does not need any flag to do this. 803 */ 804 break; 805 } 806 error(arg); 807 break; 808 case 'e': 809 if (strcmp(arg, 810 "-erroff=E_EMPTY_TRANSLATION_UNIT") == 0) { 811 /* 812 * Accept but ignore this -- gcc doesn't 813 * seem to complain about empty translation 814 * units 815 */ 816 break; 817 } 818 /* XX64 -- ignore all -erroff= options, for now */ 819 if (strncmp(arg, "-erroff=", 8) == 0) 820 break; 821 if (strcmp(arg, "-errtags=yes") == 0) { 822 warnings(ctx->i_ae); 823 break; 824 } 825 if (strcmp(arg, "-errwarn=%all") == 0) { 826 newae(ctx->i_ae, "-Werror"); 827 break; 828 } 829 error(arg); 830 break; 831 case 'f': 832 if (strcmp(arg, "-flags") == 0) { 833 newae(ctx->i_ae, "--help"); 834 break; 835 } 836 error(arg); 837 break; 838 case 'G': 839 newae(ctx->i_ae, "-shared"); 840 nolibc = 1; 841 break; 842 case 'k': 843 if (strcmp(arg, "-keeptmp") == 0) { 844 newae(ctx->i_ae, "-save-temps"); 845 break; 846 } 847 error(arg); 848 break; 849 case 'K': 850 if (arglen == 1) { 851 if ((arg = *++ctx->i_oldargv) == NULL || 852 *arg == '\0') 853 error("-K"); 854 ctx->i_oldargc--; 855 } else { 856 arg += 2; 857 } 858 if (strcmp(arg, "pic") == 0) { 859 newae(ctx->i_ae, "-fpic"); 860 pic = 1; 861 break; 862 } 863 if (strcmp(arg, "PIC") == 0) { 864 newae(ctx->i_ae, "-fPIC"); 865 pic = 1; 866 break; 867 } 868 error("-K"); 869 break; 870 case 'm': 871 if (strcmp(arg, "-mt") == 0) { 872 newae(ctx->i_ae, "-D_REENTRANT"); 873 break; 874 } 875 error(arg); 876 break; 877 case 'B': /* linker options */ 878 case 'M': 879 case 'z': 880 { 881 char *opt; 882 size_t len; 883 char *s; 884 885 if (arglen == 1) { 886 opt = *++ctx->i_oldargv; 887 if (opt == NULL || *opt == '\0') 888 error(arg); 889 ctx->i_oldargc--; 890 } else { 891 opt = arg + 2; 892 } 893 len = strlen(opt) + 7; 894 if ((s = malloc(len)) == NULL) 895 nomem(); 896 (void) snprintf(s, len, "-Wl,-%c%s", c, opt); 897 newae(ctx->i_ae, s); 898 free(s); 899 } 900 break; 901 case 'n': 902 if (strcmp(arg, "-noqueue") == 0) { 903 /* 904 * Horrid license server stuff - n/a 905 */ 906 break; 907 } 908 error(arg); 909 break; 910 case 'O': 911 if (arglen == 1) { 912 newae(ctx->i_ae, "-O"); 913 break; 914 } 915 error(arg); 916 break; 917 case 'P': 918 /* 919 * We could do '-E -o filename.i', but that's hard, 920 * and we don't need it for the case that's triggering 921 * this addition. We'll require the user to specify 922 * -o in the Makefile. If they don't they'll find out 923 * in a hurry. 924 */ 925 newae(ctx->i_ae, "-E"); 926 op = CW_O_PREPROCESS; 927 nolibc = 1; 928 break; 929 case 'q': 930 if (strcmp(arg, "-qp") == 0) { 931 newae(ctx->i_ae, "-p"); 932 break; 933 } 934 error(arg); 935 break; 936 case 's': 937 if (arglen == 1) { 938 newae(ctx->i_ae, "-Wl,-s"); 939 break; 940 } 941 error(arg); 942 break; 943 case 't': 944 if (arglen == 1) { 945 newae(ctx->i_ae, "-Wl,-t"); 946 break; 947 } 948 error(arg); 949 break; 950 case 'V': 951 if (arglen == 1) { 952 ctx->i_flags &= ~CW_F_ECHO; 953 newae(ctx->i_ae, "--version"); 954 break; 955 } 956 error(arg); 957 break; 958 case 'v': 959 if (arglen == 1) { 960 warnings(ctx->i_ae); 961 break; 962 } 963 error(arg); 964 break; 965 case 'W': 966 if (strncmp(arg, "-Wp,-xc99", 9) == 0) { 967 /* 968 * gcc's preprocessor will accept c99 969 * regardless, so accept and ignore. 970 */ 971 break; 972 } 973 if (strncmp(arg, "-Wa,", 4) == 0 || 974 strncmp(arg, "-Wp,", 4) == 0 || 975 strncmp(arg, "-Wl,", 4) == 0) { 976 newae(ctx->i_ae, arg); 977 break; 978 } 979 if (strcmp(arg, "-W0,-xc99=pragma") == 0) { 980 /* (undocumented) enables _Pragma */ 981 break; 982 } 983 if (strcmp(arg, "-W0,-xc99=%none") == 0) { 984 /* 985 * This is a polite way of saying 986 * "no c99 constructs allowed!" 987 * For now, just accept and ignore this. 988 */ 989 break; 990 } 991 if (strcmp(arg, "-W0,-noglobal") == 0 || 992 strcmp(arg, "-W0,-xglobalstatic") == 0) { 993 /* 994 * gcc doesn't prefix local symbols 995 * in debug mode, so this is not needed. 996 */ 997 break; 998 } 999 if (strcmp(arg, "-W0,-Lt") == 0) { 1000 /* 1001 * Generate tests at the top of loops. 1002 * There is no direct gcc equivalent, ignore. 1003 */ 1004 break; 1005 } 1006 if (strcmp(arg, "-W0,-xdbggen=no%usedonly") == 0) { 1007 newae(ctx->i_ae, 1008 "-fno-eliminate-unused-debug-symbols"); 1009 newae(ctx->i_ae, 1010 "-fno-eliminate-unused-debug-types"); 1011 break; 1012 } 1013 if (strcmp(arg, "-W2,-xwrap_int") == 0) { 1014 /* 1015 * Use the legacy behaviour (pre-SS11) 1016 * for integer wrapping. 1017 * gcc does not need this. 1018 */ 1019 break; 1020 } 1021 if (strcmp(arg, "-W2,-Rcond_elim") == 0) { 1022 /* 1023 * Elimination and expansion of conditionals; 1024 * gcc has no direct equivalent. 1025 */ 1026 break; 1027 } 1028 if (strcmp(arg, "-Wd,-xsafe=unboundsym") == 0) { 1029 /* 1030 * Prevents optimizing away checks for 1031 * unbound weak symbol addresses. gcc does 1032 * not do this, so it's not needed. 1033 */ 1034 break; 1035 } 1036 if (strncmp(arg, "-Wc,-xcode=", 11) == 0) { 1037 xlate(ctx->i_ae, arg + 11, xcode_tbl); 1038 if (strncmp(arg + 11, "pic", 3) == 0) 1039 pic = 1; 1040 break; 1041 } 1042 if (strncmp(arg, "-Wc,-Qiselect", 13) == 0) { 1043 /* 1044 * Prevents insertion of register symbols. 1045 * gcc doesn't do this, so ignore it. 1046 */ 1047 break; 1048 } 1049 if (strcmp(arg, "-Wc,-Qassembler-ounrefsym=0") == 0) { 1050 /* 1051 * Prevents optimizing away of static variables. 1052 * gcc does not do this, so it's not needed. 1053 */ 1054 break; 1055 } 1056 #if defined(__x86) 1057 if (strcmp(arg, "-Wu,-no_got_reloc") == 0) { 1058 newae(ctx->i_ae, "-fno-jump-tables"); 1059 newae(ctx->i_ae, "-fno-constant-pools"); 1060 break; 1061 } 1062 if (strcmp(arg, "-Wu,-xmodel=kernel") == 0) { 1063 newae(ctx->i_ae, "-ffreestanding"); 1064 newae(ctx->i_ae, "-mno-red-zone"); 1065 model = "-mcmodel=kernel"; 1066 nolibc = 1; 1067 break; 1068 } 1069 if (strcmp(arg, "-Wu,-save_args") == 0) { 1070 newae(ctx->i_ae, "-msave-args"); 1071 break; 1072 } 1073 #endif /* __x86 */ 1074 error(arg); 1075 break; 1076 case 'X': 1077 if (strcmp(arg, "-Xa") == 0 || 1078 strcmp(arg, "-Xt") == 0) { 1079 Xamode(ctx->i_ae); 1080 break; 1081 } 1082 if (strcmp(arg, "-Xc") == 0) { 1083 Xcmode(ctx->i_ae); 1084 break; 1085 } 1086 if (strcmp(arg, "-Xs") == 0) { 1087 Xsmode(ctx->i_ae); 1088 break; 1089 } 1090 error(arg); 1091 break; 1092 case 'x': 1093 if (arglen == 1) 1094 error(arg); 1095 switch (arg[2]) { 1096 #if defined(__x86) 1097 case '3': 1098 if (strcmp(arg, "-x386") == 0) { 1099 newae(ctx->i_ae, "-march=i386"); 1100 break; 1101 } 1102 error(arg); 1103 break; 1104 case '4': 1105 if (strcmp(arg, "-x486") == 0) { 1106 newae(ctx->i_ae, "-march=i486"); 1107 break; 1108 } 1109 error(arg); 1110 break; 1111 #endif /* __x86 */ 1112 case 'a': 1113 if (strncmp(arg, "-xarch=", 7) == 0) { 1114 xlate(ctx->i_ae, arg + 7, xarch_tbl); 1115 break; 1116 } 1117 error(arg); 1118 break; 1119 case 'b': 1120 if (strncmp(arg, "-xbuiltin=", 10) == 0) { 1121 if (strcmp(arg + 10, "%all")) 1122 newae(ctx->i_ae, "-fbuiltin"); 1123 break; 1124 } 1125 error(arg); 1126 break; 1127 case 'C': 1128 /* Accept C++ style comments -- ignore */ 1129 if (strcmp(arg, "-xCC") == 0) 1130 break; 1131 error(arg); 1132 break; 1133 case 'c': 1134 if (strncmp(arg, "-xc99=%all", 10) == 0) { 1135 newae(ctx->i_ae, "-std=gnu99"); 1136 break; 1137 } 1138 if (strncmp(arg, "-xc99=%none", 11) == 0) { 1139 newae(ctx->i_ae, "-std=gnu89"); 1140 break; 1141 } 1142 if (strncmp(arg, "-xchip=", 7) == 0) { 1143 xlate(ctx->i_ae, arg + 7, xchip_tbl); 1144 break; 1145 } 1146 if (strncmp(arg, "-xcode=", 7) == 0) { 1147 xlate(ctx->i_ae, arg + 7, xcode_tbl); 1148 if (strncmp(arg + 7, "pic", 3) == 0) 1149 pic = 1; 1150 break; 1151 } 1152 if (strncmp(arg, "-xcache=", 8) == 0) 1153 break; 1154 if (strncmp(arg, "-xcrossfile", 11) == 0) 1155 break; 1156 error(arg); 1157 break; 1158 case 'd': 1159 if (strcmp(arg, "-xdepend") == 0) 1160 break; 1161 if (strncmp(arg, "-xdebugformat=", 14) == 0) 1162 break; 1163 error(arg); 1164 break; 1165 case 'F': 1166 /* compile for mapfile reordering -- ignore */ 1167 if (strcmp(arg, "-xF") == 0) 1168 break; 1169 error(arg); 1170 break; 1171 case 'i': 1172 if (strncmp(arg, "-xinline", 8) == 0) 1173 /* No inlining; ignore */ 1174 break; 1175 if (strcmp(arg, "-xildon") == 0 || 1176 strcmp(arg, "-xildoff") == 0) 1177 /* No incremental linking; ignore */ 1178 break; 1179 error(arg); 1180 break; 1181 case 'M': 1182 if (strcmp(arg, "-xM") == 0) { 1183 newae(ctx->i_ae, "-M"); 1184 break; 1185 } 1186 if (strcmp(arg, "-xM1") == 0) { 1187 newae(ctx->i_ae, "-MM"); 1188 break; 1189 } 1190 error(arg); 1191 break; 1192 case 'n': 1193 if (strcmp(arg, "-xnolib") == 0) { 1194 nolibc = 1; 1195 break; 1196 } 1197 error(arg); 1198 break; 1199 case 'O': 1200 if (strncmp(arg, "-xO", 3) == 0) { 1201 size_t len = strlen(arg); 1202 char *s; 1203 int c = *(arg + 3); 1204 int level; 1205 1206 if (len != 4 || !isdigit(c)) 1207 error(arg); 1208 1209 if ((s = malloc(len)) == NULL) 1210 nomem(); 1211 1212 level = atoi(arg + 3); 1213 if (level > 5) 1214 error(arg); 1215 if (level >= 2) { 1216 /* 1217 * For gcc-3.4.x at -O2 we 1218 * need to disable optimizations 1219 * that break ON. 1220 */ 1221 optim_disable(ctx->i_ae, level); 1222 /* 1223 * limit -xO3 to -O2 as well. 1224 */ 1225 level = 2; 1226 } 1227 (void) snprintf(s, len, "-O%d", level); 1228 newae(ctx->i_ae, s); 1229 free(s); 1230 break; 1231 } 1232 error(arg); 1233 break; 1234 case 'p': 1235 if (strcmp(arg, "-xpentium") == 0) { 1236 newae(ctx->i_ae, "-march=pentium"); 1237 break; 1238 } 1239 if (strcmp(arg, "-xpg") == 0) { 1240 newae(ctx->i_ae, "-pg"); 1241 break; 1242 } 1243 error(arg); 1244 break; 1245 case 'r': 1246 if (strncmp(arg, "-xregs=", 7) == 0) { 1247 xlate(ctx->i_ae, arg + 7, xregs_tbl); 1248 break; 1249 } 1250 error(arg); 1251 break; 1252 case 's': 1253 if (strcmp(arg, "-xs") == 0 || 1254 strcmp(arg, "-xspace") == 0 || 1255 strcmp(arg, "-xstrconst") == 0) 1256 break; 1257 error(arg); 1258 break; 1259 case 't': 1260 if (strcmp(arg, "-xtransition") == 0) { 1261 newae(ctx->i_ae, "-Wtransition"); 1262 break; 1263 } 1264 if (strcmp(arg, "-xtrigraphs=yes") == 0) { 1265 newae(ctx->i_ae, "-trigraphs"); 1266 break; 1267 } 1268 if (strcmp(arg, "-xtrigraphs=no") == 0) { 1269 newae(ctx->i_ae, "-notrigraphs"); 1270 break; 1271 } 1272 if (strncmp(arg, "-xtarget=", 9) == 0) { 1273 xlate(ctx->i_ae, arg + 9, xtarget_tbl); 1274 break; 1275 } 1276 error(arg); 1277 break; 1278 case 'e': 1279 case 'h': 1280 case 'l': 1281 default: 1282 error(arg); 1283 break; 1284 } 1285 break; 1286 case 'Y': 1287 if (arglen == 1) { 1288 if ((arg = *++ctx->i_oldargv) == NULL || 1289 *arg == '\0') 1290 error("-Y"); 1291 ctx->i_oldargc--; 1292 arglen = strlen(arg + 1); 1293 } else { 1294 arg += 2; 1295 } 1296 /* Just ignore -YS,... for now */ 1297 if (strncmp(arg, "S,", 2) == 0) 1298 break; 1299 if (strncmp(arg, "l,", 2) == 0) { 1300 char *s = strdup(arg); 1301 s[0] = '-'; 1302 s[1] = 'B'; 1303 newae(ctx->i_ae, s); 1304 free(s); 1305 break; 1306 } 1307 if (strncmp(arg, "I,", 2) == 0) { 1308 char *s = strdup(arg); 1309 s[0] = '-'; 1310 s[1] = 'I'; 1311 newae(ctx->i_ae, "-nostdinc"); 1312 newae(ctx->i_ae, s); 1313 free(s); 1314 break; 1315 } 1316 error(arg); 1317 break; 1318 case 'Q': 1319 /* 1320 * We could map -Qy into -Wl,-Qy etc. 1321 */ 1322 default: 1323 error(arg); 1324 break; 1325 } 1326 } 1327 1328 if (c_files > 1 && (ctx->i_flags & CW_F_SHADOW) && 1329 op != CW_O_PREPROCESS) { 1330 (void) fprintf(stderr, "%s: error: multiple source files are " 1331 "allowed only with -E or -P\n", progname); 1332 exit(2); 1333 } 1334 if (op == CW_O_LINK && (ctx->i_flags & CW_F_SHADOW)) 1335 exit(0); 1336 1337 if (model && !pic) 1338 newae(ctx->i_ae, model); 1339 if (!nolibc) 1340 newae(ctx->i_ae, "-lc"); 1341 if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) { 1342 newae(ctx->i_ae, "-o"); 1343 newae(ctx->i_ae, ctx->i_discard); 1344 } 1345 } 1346 1347 static void 1348 do_cc(cw_ictx_t *ctx) 1349 { 1350 int in_output = 0, seen_o = 0; 1351 cw_op_t op = CW_O_LINK; 1352 1353 if (ctx->i_flags & CW_F_PROG) { 1354 newae(ctx->i_ae, "-V"); 1355 return; 1356 } 1357 1358 while (--ctx->i_oldargc > 0) { 1359 char *arg = *++ctx->i_oldargv; 1360 1361 if (*arg != '-') { 1362 if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) { 1363 newae(ctx->i_ae, arg); 1364 } else { 1365 in_output = 0; 1366 newae(ctx->i_ae, ctx->i_discard); 1367 } 1368 continue; 1369 } 1370 switch (*(arg + 1)) { 1371 case '_': 1372 if (strcmp(arg, "-_noecho") == 0) { 1373 ctx->i_flags &= ~CW_F_ECHO; 1374 } else if (strncmp(arg, "-_cc=", 5) == 0 || 1375 strncmp(arg, "-_CC=", 5) == 0) { 1376 newae(ctx->i_ae, arg + 5); 1377 } else if (strncmp(arg, "-_gcc=", 6) != 0 && 1378 strncmp(arg, "-_g++=", 6) != 0) { 1379 (void) fprintf(stderr, 1380 "%s: invalid argument '%s'\n", progname, 1381 arg); 1382 exit(2); 1383 } 1384 break; 1385 case 'V': 1386 ctx->i_flags &= ~CW_F_ECHO; 1387 newae(ctx->i_ae, arg); 1388 break; 1389 case 'o': 1390 seen_o = 1; 1391 if (strlen(arg) == 2) { 1392 in_output = 1; 1393 newae(ctx->i_ae, arg); 1394 } else if (ctx->i_flags & CW_F_SHADOW) { 1395 newae(ctx->i_ae, "-o"); 1396 newae(ctx->i_ae, ctx->i_discard); 1397 } else { 1398 newae(ctx->i_ae, arg); 1399 } 1400 break; 1401 case 'c': 1402 case 'S': 1403 op = CW_O_COMPILE; 1404 newae(ctx->i_ae, arg); 1405 break; 1406 case 'E': 1407 case 'P': 1408 op = CW_O_PREPROCESS; 1409 /*FALLTHROUGH*/ 1410 default: 1411 newae(ctx->i_ae, arg); 1412 } 1413 } 1414 1415 if ((op == CW_O_LINK || op == CW_O_PREPROCESS) && 1416 (ctx->i_flags & CW_F_SHADOW)) 1417 exit(0); 1418 1419 if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) { 1420 newae(ctx->i_ae, "-o"); 1421 newae(ctx->i_ae, ctx->i_discard); 1422 } 1423 } 1424 1425 static void 1426 prepctx(cw_ictx_t *ctx) 1427 { 1428 const char *dir, *cmd; 1429 char *program; 1430 size_t len; 1431 1432 dir = dirs[CIDX(CC(ctx), ctx->i_flags)]; 1433 cmd = cmds[CIDX(CC(ctx), ctx->i_flags)]; 1434 len = strlen(dir) + strlen(cmd) + 2; 1435 if ((program = malloc(len)) == NULL) 1436 nomem(); 1437 (void) snprintf(program, len, "%s/%s", dir, cmd); 1438 1439 newae(ctx->i_ae, program); 1440 1441 if (ctx->i_flags & CW_F_PROG) { 1442 (void) printf("%s: %s\n", (ctx->i_flags & CW_F_SHADOW) ? 1443 "shadow" : "primary", program); 1444 (void) fflush(stdout); 1445 } 1446 1447 if (!(ctx->i_flags & CW_F_XLATE)) 1448 return; 1449 1450 switch (CC(ctx)) { 1451 case CW_C_CC: 1452 do_cc(ctx); 1453 break; 1454 case CW_C_GCC: 1455 do_gcc(ctx); 1456 break; 1457 } 1458 } 1459 1460 static int 1461 invoke(cw_ictx_t *ctx) 1462 { 1463 char **newargv; 1464 int ac; 1465 struct ae *a; 1466 1467 if ((newargv = calloc(sizeof (*newargv), ctx->i_ae->ael_argc + 1)) == 1468 NULL) 1469 nomem(); 1470 1471 if (ctx->i_flags & CW_F_ECHO) 1472 (void) fprintf(stderr, "+ "); 1473 1474 for (ac = 0, a = ctx->i_ae->ael_head; a; a = a->ae_next, ac++) { 1475 newargv[ac] = a->ae_arg; 1476 if (ctx->i_flags & CW_F_ECHO) 1477 (void) fprintf(stderr, "%s ", a->ae_arg); 1478 if (a == ctx->i_ae->ael_tail) 1479 break; 1480 } 1481 1482 if (ctx->i_flags & CW_F_ECHO) { 1483 (void) fprintf(stderr, "\n"); 1484 (void) fflush(stderr); 1485 } 1486 1487 if (!(ctx->i_flags & CW_F_EXEC)) 1488 return (0); 1489 1490 /* 1491 * We must fix up the environment here so that the 1492 * dependency files are not trampled by the shadow compiler. 1493 */ 1494 if ((ctx->i_flags & CW_F_SHADOW) && 1495 (unsetenv("SUNPRO_DEPENDENCIES") != 0 || 1496 unsetenv("DEPENDENCIES_OUTPUT") != 0)) { 1497 (void) fprintf(stderr, "error: environment setup failed: %s\n", 1498 strerror(errno)); 1499 return (-1); 1500 } 1501 1502 (void) execv(newargv[0], newargv); 1503 cw_perror("couldn't run %s", newargv[0]); 1504 1505 return (-1); 1506 } 1507 1508 static int 1509 reap(cw_ictx_t *ctx) 1510 { 1511 int status, ret = 0; 1512 char buf[1024]; 1513 struct stat s; 1514 1515 do { 1516 (void) waitpid(ctx->i_pid, &status, 0); 1517 if (status != 0) { 1518 if (WIFSIGNALED(status)) { 1519 ret = -WTERMSIG(status); 1520 break; 1521 } else if (WIFEXITED(status)) { 1522 ret = WEXITSTATUS(status); 1523 break; 1524 } 1525 } 1526 } while (!WIFEXITED(status) && !WIFSIGNALED(status)); 1527 1528 (void) unlink(ctx->i_discard); 1529 1530 if (stat(ctx->i_stderr, &s) < 0) { 1531 cw_perror("stat failed on child cleanup"); 1532 return (-1); 1533 } 1534 if (s.st_size != 0) { 1535 FILE *f; 1536 1537 if ((f = fopen(ctx->i_stderr, "r")) != NULL) { 1538 while (fgets(buf, sizeof (buf), f)) 1539 (void) fprintf(stderr, "%s", buf); 1540 (void) fflush(stderr); 1541 (void) fclose(f); 1542 } 1543 } 1544 (void) unlink(ctx->i_stderr); 1545 free(ctx->i_stderr); 1546 1547 /* 1548 * cc returns an error code when given -V; we want that to succeed. 1549 */ 1550 if (ctx->i_flags & CW_F_PROG) 1551 return (0); 1552 1553 return (ret); 1554 } 1555 1556 static int 1557 exec_ctx(cw_ictx_t *ctx, int block) 1558 { 1559 char *file; 1560 1561 /* 1562 * To avoid offending cc's sensibilities, the name of its output 1563 * file must end in '.o'. 1564 */ 1565 if ((file = tempnam(NULL, ".cw")) == NULL) { 1566 nomem(); 1567 return (-1); 1568 } 1569 (void) strlcpy(ctx->i_discard, file, MAXPATHLEN); 1570 (void) strlcat(ctx->i_discard, ".o", MAXPATHLEN); 1571 free(file); 1572 1573 if ((ctx->i_stderr = tempnam(NULL, ".cw")) == NULL) { 1574 nomem(); 1575 return (-1); 1576 } 1577 1578 if ((ctx->i_pid = fork()) == 0) { 1579 int fd; 1580 1581 (void) fclose(stderr); 1582 if ((fd = open(ctx->i_stderr, O_WRONLY | O_CREAT | O_EXCL, 1583 0666)) < 0) { 1584 cw_perror("open failed for standard error"); 1585 exit(1); 1586 } 1587 if (dup2(fd, 2) < 0) { 1588 cw_perror("dup2 failed for standard error"); 1589 exit(1); 1590 } 1591 if (fd != 2) 1592 (void) close(fd); 1593 if (freopen("/dev/fd/2", "w", stderr) == NULL) { 1594 cw_perror("freopen failed for /dev/fd/2"); 1595 exit(1); 1596 } 1597 prepctx(ctx); 1598 exit(invoke(ctx)); 1599 } 1600 1601 if (ctx->i_pid < 0) { 1602 cw_perror("fork failed"); 1603 return (1); 1604 } 1605 1606 if (block) 1607 return (reap(ctx)); 1608 1609 return (0); 1610 } 1611 1612 int 1613 main(int argc, char **argv) 1614 { 1615 cw_ictx_t *ctx = newictx(); 1616 cw_ictx_t *ctx_shadow = newictx(); 1617 const char *dir; 1618 char cc_buf[MAXPATHLEN], gcc_buf[MAXPATHLEN]; 1619 int do_serial, do_shadow; 1620 int ret = 0; 1621 1622 if ((progname = strrchr(argv[0], '/')) == NULL) 1623 progname = argv[0]; 1624 else 1625 progname++; 1626 1627 if (ctx == NULL || ctx_shadow == NULL) 1628 nomem(); 1629 1630 ctx->i_flags = CW_F_ECHO|CW_F_XLATE; 1631 1632 /* 1633 * Figure out where to get our tools from. This depends on 1634 * the environment variables set at run time. 1635 */ 1636 if ((dir = getenv("SPRO_VROOT")) != NULL) { 1637 (void) snprintf(cc_buf, MAXPATHLEN, "%s/bin", dir); 1638 } else if ((dir = getenv("SPRO_ROOT")) != NULL) { 1639 (void) snprintf(cc_buf, MAXPATHLEN, "%s/SS11/bin", dir); 1640 } else if ((dir = getenv("BUILD_TOOLS")) != NULL) { 1641 (void) snprintf(cc_buf, MAXPATHLEN, 1642 "%s/SUNWspro/SS11/bin", dir); 1643 } 1644 if (dir != NULL) { 1645 dirs[CIDX(CW_C_CC, 0)] = (const char *)cc_buf; 1646 dirs[CIDX(CW_C_CC, CW_F_CXX)] = (const char *)cc_buf; 1647 } 1648 1649 if ((dir = getenv("GNU_ROOT")) != NULL) { 1650 (void) snprintf(gcc_buf, MAXPATHLEN, "%s/bin", dir); 1651 dirs[CIDX(CW_C_GCC, 0)] = (const char *)gcc_buf; 1652 dirs[CIDX(CW_C_GCC, CW_F_CXX)] = (const char *)gcc_buf; 1653 } 1654 1655 if ((dir = getenv("CW_CC_DIR")) != NULL) 1656 dirs[CIDX(CW_C_CC, 0)] = dir; 1657 if ((dir = getenv("CW_CPLUSPLUS_DIR")) != NULL) 1658 dirs[CIDX(CW_C_CC, CW_F_CXX)] = dir; 1659 if ((dir = getenv("CW_GCC_DIR")) != NULL) 1660 dirs[CIDX(CW_C_GCC, 0)] = dir; 1661 if ((dir = getenv("CW_GPLUSPLUS_DIR")) != NULL) 1662 dirs[CIDX(CW_C_GCC, CW_F_CXX)] = dir; 1663 1664 do_shadow = (getenv("CW_NO_SHADOW") ? 0 : 1); 1665 do_serial = (getenv("CW_SHADOW_SERIAL") ? 1 : 0); 1666 1667 if (getenv("CW_NO_EXEC") == NULL) 1668 ctx->i_flags |= CW_F_EXEC; 1669 1670 /* 1671 * The first argument must be one of "-_cc", "-_gcc", "-_CC", or "-_g++" 1672 */ 1673 if (argc == 1) 1674 usage(); 1675 argc--; 1676 argv++; 1677 if (strcmp(argv[0], "-_cc") == 0) { 1678 ctx->i_compiler = CW_C_CC; 1679 } else if (strcmp(argv[0], "-_gcc") == 0) { 1680 ctx->i_compiler = CW_C_GCC; 1681 } else if (strcmp(argv[0], "-_CC") == 0) { 1682 ctx->i_compiler = CW_C_CC; 1683 ctx->i_flags |= CW_F_CXX; 1684 } else if (strcmp(argv[0], "-_g++") == 0) { 1685 ctx->i_compiler = CW_C_GCC; 1686 ctx->i_flags |= CW_F_CXX; 1687 } else { 1688 /* assume "-_gcc" by default */ 1689 argc++; 1690 argv--; 1691 ctx->i_compiler = CW_C_GCC; 1692 } 1693 1694 /* 1695 * -_compiler - tell us the path to the primary compiler only 1696 */ 1697 if (argc > 1 && strcmp(argv[1], "-_compiler") == 0) { 1698 ctx->i_flags &= ~CW_F_XLATE; 1699 prepctx(ctx); 1700 (void) printf("%s\n", ctx->i_ae->ael_head->ae_arg); 1701 return (0); 1702 } 1703 1704 /* 1705 * -_versions - tell us the cw version, paths to all compilers, and 1706 * ask each for its version if we know how. 1707 */ 1708 if (argc > 1 && strcmp(argv[1], "-_versions") == 0) { 1709 (void) printf("%s", "cw version %I%"); 1710 if (!do_shadow) 1711 (void) printf(" (SHADOW MODE DISABLED)"); 1712 (void) printf("\n"); 1713 (void) fflush(stdout); 1714 ctx->i_flags &= ~CW_F_ECHO; 1715 ctx->i_flags |= CW_F_PROG|CW_F_EXEC; 1716 argc--; 1717 argv++; 1718 do_serial = 1; 1719 } 1720 1721 ctx->i_oldargc = argc; 1722 ctx->i_oldargv = argv; 1723 1724 ret |= exec_ctx(ctx, do_serial); 1725 1726 if (do_shadow) { 1727 (void) memcpy(ctx_shadow, ctx, sizeof (cw_ictx_t)); 1728 ctx_shadow->i_flags |= CW_F_SHADOW; 1729 ret |= exec_ctx(ctx_shadow, 1); 1730 } 1731 1732 if (!do_serial) 1733 ret |= reap(ctx); 1734 1735 return (ret); 1736 } 1737