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,-Rcond_elim") == 0) { 1014 /* 1015 * Elimination and expansion of conditionals; 1016 * gcc has no direct equivalent. 1017 */ 1018 break; 1019 } 1020 if (strcmp(arg, "-Wd,-xsafe=unboundsym") == 0) { 1021 /* 1022 * Prevents optimizing away checks for 1023 * unbound weak symbol addresses. gcc does 1024 * not do this, so it's not needed. 1025 */ 1026 break; 1027 } 1028 if (strncmp(arg, "-Wc,-xcode=", 11) == 0) { 1029 xlate(ctx->i_ae, arg + 11, xcode_tbl); 1030 if (strncmp(arg + 11, "pic", 3) == 0) 1031 pic = 1; 1032 break; 1033 } 1034 if (strncmp(arg, "-Wc,-Qiselect", 13) == 0) { 1035 /* 1036 * Prevents insertion of register symbols. 1037 * gcc doesn't do this, so ignore it. 1038 */ 1039 break; 1040 } 1041 #if defined(__x86) 1042 if (strcmp(arg, "-Wu,-no_got_reloc") == 0) { 1043 newae(ctx->i_ae, "-fno-jump-tables"); 1044 newae(ctx->i_ae, "-fno-constant-pools"); 1045 break; 1046 } 1047 if (strcmp(arg, "-Wu,-xmodel=kernel") == 0) { 1048 newae(ctx->i_ae, "-ffreestanding"); 1049 newae(ctx->i_ae, "-mno-red-zone"); 1050 model = "-mcmodel=kernel"; 1051 nolibc = 1; 1052 break; 1053 } 1054 if (strcmp(arg, "-Wu,-save_args") == 0) { 1055 newae(ctx->i_ae, "-msave-args"); 1056 break; 1057 } 1058 #endif /* __x86 */ 1059 error(arg); 1060 break; 1061 case 'X': 1062 if (strcmp(arg, "-Xa") == 0 || 1063 strcmp(arg, "-Xt") == 0) { 1064 Xamode(ctx->i_ae); 1065 break; 1066 } 1067 if (strcmp(arg, "-Xc") == 0) { 1068 Xcmode(ctx->i_ae); 1069 break; 1070 } 1071 if (strcmp(arg, "-Xs") == 0) { 1072 Xsmode(ctx->i_ae); 1073 break; 1074 } 1075 error(arg); 1076 break; 1077 case 'x': 1078 if (arglen == 1) 1079 error(arg); 1080 switch (arg[2]) { 1081 #if defined(__x86) 1082 case '3': 1083 if (strcmp(arg, "-x386") == 0) { 1084 newae(ctx->i_ae, "-march=i386"); 1085 break; 1086 } 1087 error(arg); 1088 break; 1089 case '4': 1090 if (strcmp(arg, "-x486") == 0) { 1091 newae(ctx->i_ae, "-march=i486"); 1092 break; 1093 } 1094 error(arg); 1095 break; 1096 #endif /* __x86 */ 1097 case 'a': 1098 if (strncmp(arg, "-xarch=", 7) == 0) { 1099 xlate(ctx->i_ae, arg + 7, xarch_tbl); 1100 break; 1101 } 1102 error(arg); 1103 break; 1104 case 'b': 1105 if (strncmp(arg, "-xbuiltin=", 10) == 0) { 1106 if (strcmp(arg + 10, "%all")) 1107 newae(ctx->i_ae, "-fbuiltin"); 1108 break; 1109 } 1110 error(arg); 1111 break; 1112 case 'C': 1113 /* Accept C++ style comments -- ignore */ 1114 if (strcmp(arg, "-xCC") == 0) 1115 break; 1116 error(arg); 1117 break; 1118 case 'c': 1119 if (strncmp(arg, "-xc99=%all", 10) == 0) { 1120 newae(ctx->i_ae, "-std=gnu99"); 1121 break; 1122 } 1123 if (strncmp(arg, "-xc99=%none", 11) == 0) { 1124 newae(ctx->i_ae, "-std=gnu89"); 1125 break; 1126 } 1127 if (strncmp(arg, "-xchip=", 7) == 0) { 1128 xlate(ctx->i_ae, arg + 7, xchip_tbl); 1129 break; 1130 } 1131 if (strncmp(arg, "-xcode=", 7) == 0) { 1132 xlate(ctx->i_ae, arg + 7, xcode_tbl); 1133 if (strncmp(arg + 7, "pic", 3) == 0) 1134 pic = 1; 1135 break; 1136 } 1137 if (strncmp(arg, "-xcache=", 8) == 0) 1138 break; 1139 if (strncmp(arg, "-xcrossfile", 11) == 0) 1140 break; 1141 error(arg); 1142 break; 1143 case 'd': 1144 if (strcmp(arg, "-xdepend") == 0) 1145 break; 1146 if (strncmp(arg, "-xdebugformat=", 14) == 0) 1147 break; 1148 error(arg); 1149 break; 1150 case 'F': 1151 /* compile for mapfile reordering -- ignore */ 1152 if (strcmp(arg, "-xF") == 0) 1153 break; 1154 error(arg); 1155 break; 1156 case 'i': 1157 if (strncmp(arg, "-xinline", 8) == 0) 1158 /* No inlining; ignore */ 1159 break; 1160 if (strcmp(arg, "-xildon") == 0 || 1161 strcmp(arg, "-xildoff") == 0) 1162 /* No incremental linking; ignore */ 1163 break; 1164 error(arg); 1165 break; 1166 case 'M': 1167 if (strcmp(arg, "-xM") == 0) { 1168 newae(ctx->i_ae, "-M"); 1169 break; 1170 } 1171 if (strcmp(arg, "-xM1") == 0) { 1172 newae(ctx->i_ae, "-MM"); 1173 break; 1174 } 1175 error(arg); 1176 break; 1177 case 'n': 1178 if (strcmp(arg, "-xnolib") == 0) { 1179 nolibc = 1; 1180 break; 1181 } 1182 error(arg); 1183 break; 1184 case 'O': 1185 if (strncmp(arg, "-xO", 3) == 0) { 1186 size_t len = strlen(arg); 1187 char *s; 1188 int c = *(arg + 3); 1189 int level; 1190 1191 if (len != 4 || !isdigit(c)) 1192 error(arg); 1193 1194 if ((s = malloc(len)) == NULL) 1195 nomem(); 1196 1197 level = atoi(arg + 3); 1198 if (level > 5) 1199 error(arg); 1200 if (level >= 2) { 1201 /* 1202 * For gcc-3.4.x at -O2 we 1203 * need to disable optimizations 1204 * that break ON. 1205 */ 1206 optim_disable(ctx->i_ae, level); 1207 /* 1208 * limit -xO3 to -O2 as well. 1209 */ 1210 level = 2; 1211 } 1212 (void) snprintf(s, len, "-O%d", level); 1213 newae(ctx->i_ae, s); 1214 free(s); 1215 break; 1216 } 1217 error(arg); 1218 break; 1219 case 'p': 1220 if (strcmp(arg, "-xpentium") == 0) { 1221 newae(ctx->i_ae, "-march=pentium"); 1222 break; 1223 } 1224 if (strcmp(arg, "-xpg") == 0) { 1225 newae(ctx->i_ae, "-pg"); 1226 break; 1227 } 1228 error(arg); 1229 break; 1230 case 'r': 1231 if (strncmp(arg, "-xregs=", 7) == 0) { 1232 xlate(ctx->i_ae, arg + 7, xregs_tbl); 1233 break; 1234 } 1235 error(arg); 1236 break; 1237 case 's': 1238 if (strcmp(arg, "-xs") == 0 || 1239 strcmp(arg, "-xspace") == 0 || 1240 strcmp(arg, "-xstrconst") == 0) 1241 break; 1242 error(arg); 1243 break; 1244 case 't': 1245 if (strcmp(arg, "-xtransition") == 0) { 1246 newae(ctx->i_ae, "-Wtransition"); 1247 break; 1248 } 1249 if (strcmp(arg, "-xtrigraphs=yes") == 0) { 1250 newae(ctx->i_ae, "-trigraphs"); 1251 break; 1252 } 1253 if (strcmp(arg, "-xtrigraphs=no") == 0) { 1254 newae(ctx->i_ae, "-notrigraphs"); 1255 break; 1256 } 1257 if (strncmp(arg, "-xtarget=", 9) == 0) { 1258 xlate(ctx->i_ae, arg + 9, xtarget_tbl); 1259 break; 1260 } 1261 error(arg); 1262 break; 1263 case 'e': 1264 case 'h': 1265 case 'l': 1266 default: 1267 error(arg); 1268 break; 1269 } 1270 break; 1271 case 'Y': 1272 if (arglen == 1) { 1273 if ((arg = *++ctx->i_oldargv) == NULL || 1274 *arg == '\0') 1275 error("-Y"); 1276 ctx->i_oldargc--; 1277 arglen = strlen(arg + 1); 1278 } else { 1279 arg += 2; 1280 } 1281 /* Just ignore -YS,... for now */ 1282 if (strncmp(arg, "S,", 2) == 0) 1283 break; 1284 if (strncmp(arg, "l,", 2) == 0) { 1285 char *s = strdup(arg); 1286 s[0] = '-'; 1287 s[1] = 'B'; 1288 newae(ctx->i_ae, s); 1289 free(s); 1290 break; 1291 } 1292 if (strncmp(arg, "I,", 2) == 0) { 1293 char *s = strdup(arg); 1294 s[0] = '-'; 1295 s[1] = 'I'; 1296 newae(ctx->i_ae, "-nostdinc"); 1297 newae(ctx->i_ae, s); 1298 free(s); 1299 break; 1300 } 1301 error(arg); 1302 break; 1303 case 'Q': 1304 /* 1305 * We could map -Qy into -Wl,-Qy etc. 1306 */ 1307 default: 1308 error(arg); 1309 break; 1310 } 1311 } 1312 1313 if (c_files > 1 && (ctx->i_flags & CW_F_SHADOW) && 1314 op != CW_O_PREPROCESS) { 1315 (void) fprintf(stderr, "%s: error: multiple source files are " 1316 "allowed only with -E or -P\n", progname); 1317 exit(2); 1318 } 1319 if (op == CW_O_LINK && (ctx->i_flags & CW_F_SHADOW)) 1320 exit(0); 1321 1322 if (model && !pic) 1323 newae(ctx->i_ae, model); 1324 if (!nolibc) 1325 newae(ctx->i_ae, "-lc"); 1326 if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) { 1327 newae(ctx->i_ae, "-o"); 1328 newae(ctx->i_ae, ctx->i_discard); 1329 } 1330 } 1331 1332 static void 1333 do_cc(cw_ictx_t *ctx) 1334 { 1335 int in_output = 0, seen_o = 0; 1336 cw_op_t op = CW_O_LINK; 1337 1338 if (ctx->i_flags & CW_F_PROG) { 1339 newae(ctx->i_ae, "-V"); 1340 return; 1341 } 1342 1343 while (--ctx->i_oldargc > 0) { 1344 char *arg = *++ctx->i_oldargv; 1345 1346 if (*arg != '-') { 1347 if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) { 1348 newae(ctx->i_ae, arg); 1349 } else { 1350 in_output = 0; 1351 newae(ctx->i_ae, ctx->i_discard); 1352 } 1353 continue; 1354 } 1355 switch (*(arg + 1)) { 1356 case '_': 1357 if (strcmp(arg, "-_noecho") == 0) { 1358 ctx->i_flags &= ~CW_F_ECHO; 1359 } else if (strncmp(arg, "-_cc=", 5) == 0 || 1360 strncmp(arg, "-_CC=", 5) == 0) { 1361 newae(ctx->i_ae, arg + 5); 1362 } else if (strncmp(arg, "-_gcc=", 6) != 0 && 1363 strncmp(arg, "-_g++=", 6) != 0) { 1364 (void) fprintf(stderr, 1365 "%s: invalid argument '%s'\n", progname, 1366 arg); 1367 exit(2); 1368 } 1369 break; 1370 case 'V': 1371 ctx->i_flags &= ~CW_F_ECHO; 1372 newae(ctx->i_ae, arg); 1373 break; 1374 case 'o': 1375 seen_o = 1; 1376 if (strlen(arg) == 2) { 1377 in_output = 1; 1378 newae(ctx->i_ae, arg); 1379 } else if (ctx->i_flags & CW_F_SHADOW) { 1380 newae(ctx->i_ae, "-o"); 1381 newae(ctx->i_ae, ctx->i_discard); 1382 } else { 1383 newae(ctx->i_ae, arg); 1384 } 1385 break; 1386 case 'c': 1387 case 'S': 1388 op = CW_O_COMPILE; 1389 newae(ctx->i_ae, arg); 1390 break; 1391 case 'E': 1392 case 'P': 1393 op = CW_O_PREPROCESS; 1394 /*FALLTHROUGH*/ 1395 default: 1396 newae(ctx->i_ae, arg); 1397 } 1398 } 1399 1400 if ((op == CW_O_LINK || op == CW_O_PREPROCESS) && 1401 (ctx->i_flags & CW_F_SHADOW)) 1402 exit(0); 1403 1404 if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) { 1405 newae(ctx->i_ae, "-o"); 1406 newae(ctx->i_ae, ctx->i_discard); 1407 } 1408 } 1409 1410 static void 1411 prepctx(cw_ictx_t *ctx) 1412 { 1413 const char *dir, *cmd; 1414 char *program; 1415 size_t len; 1416 1417 dir = dirs[CIDX(CC(ctx), ctx->i_flags)]; 1418 cmd = cmds[CIDX(CC(ctx), ctx->i_flags)]; 1419 len = strlen(dir) + strlen(cmd) + 2; 1420 if ((program = malloc(len)) == NULL) 1421 nomem(); 1422 (void) snprintf(program, len, "%s/%s", dir, cmd); 1423 1424 newae(ctx->i_ae, program); 1425 1426 if (ctx->i_flags & CW_F_PROG) { 1427 (void) printf("%s: %s\n", (ctx->i_flags & CW_F_SHADOW) ? 1428 "shadow" : "primary", program); 1429 (void) fflush(stdout); 1430 } 1431 1432 if (!(ctx->i_flags & CW_F_XLATE)) 1433 return; 1434 1435 switch (CC(ctx)) { 1436 case CW_C_CC: 1437 do_cc(ctx); 1438 break; 1439 case CW_C_GCC: 1440 do_gcc(ctx); 1441 break; 1442 } 1443 } 1444 1445 static int 1446 invoke(cw_ictx_t *ctx) 1447 { 1448 char **newargv; 1449 int ac; 1450 struct ae *a; 1451 1452 if ((newargv = calloc(sizeof (*newargv), ctx->i_ae->ael_argc + 1)) == 1453 NULL) 1454 nomem(); 1455 1456 if (ctx->i_flags & CW_F_ECHO) 1457 (void) fprintf(stderr, "+ "); 1458 1459 for (ac = 0, a = ctx->i_ae->ael_head; a; a = a->ae_next, ac++) { 1460 newargv[ac] = a->ae_arg; 1461 if (ctx->i_flags & CW_F_ECHO) 1462 (void) fprintf(stderr, "%s ", a->ae_arg); 1463 if (a == ctx->i_ae->ael_tail) 1464 break; 1465 } 1466 1467 if (ctx->i_flags & CW_F_ECHO) { 1468 (void) fprintf(stderr, "\n"); 1469 (void) fflush(stderr); 1470 } 1471 1472 if (!(ctx->i_flags & CW_F_EXEC)) 1473 return (0); 1474 1475 /* 1476 * We must fix up the environment here so that the 1477 * dependency files are not trampled by the shadow compiler. 1478 */ 1479 if ((ctx->i_flags & CW_F_SHADOW) && 1480 (unsetenv("SUNPRO_DEPENDENCIES") != 0 || 1481 unsetenv("DEPENDENCIES_OUTPUT") != 0)) { 1482 (void) fprintf(stderr, "error: environment setup failed: %s\n", 1483 strerror(errno)); 1484 return (-1); 1485 } 1486 1487 (void) execv(newargv[0], newargv); 1488 cw_perror("couldn't run %s", newargv[0]); 1489 1490 return (-1); 1491 } 1492 1493 static int 1494 reap(cw_ictx_t *ctx) 1495 { 1496 int status, ret = 0; 1497 char buf[1024]; 1498 struct stat s; 1499 1500 do { 1501 (void) waitpid(ctx->i_pid, &status, 0); 1502 if (status != 0) { 1503 if (WIFSIGNALED(status)) { 1504 ret = -WTERMSIG(status); 1505 break; 1506 } else if (WIFEXITED(status)) { 1507 ret = WEXITSTATUS(status); 1508 break; 1509 } 1510 } 1511 } while (!WIFEXITED(status) && !WIFSIGNALED(status)); 1512 1513 (void) unlink(ctx->i_discard); 1514 1515 if (stat(ctx->i_stderr, &s) < 0) { 1516 cw_perror("stat failed on child cleanup"); 1517 return (-1); 1518 } 1519 if (s.st_size != 0) { 1520 FILE *f; 1521 1522 if ((f = fopen(ctx->i_stderr, "r")) != NULL) { 1523 while (fgets(buf, sizeof (buf), f)) 1524 (void) fprintf(stderr, "%s", buf); 1525 (void) fflush(stderr); 1526 (void) fclose(f); 1527 } 1528 } 1529 (void) unlink(ctx->i_stderr); 1530 free(ctx->i_stderr); 1531 1532 /* 1533 * cc returns an error code when given -V; we want that to succeed. 1534 */ 1535 if (ctx->i_flags & CW_F_PROG) 1536 return (0); 1537 1538 return (ret); 1539 } 1540 1541 static int 1542 exec_ctx(cw_ictx_t *ctx, int block) 1543 { 1544 char *file; 1545 1546 /* 1547 * To avoid offending cc's sensibilities, the name of its output 1548 * file must end in '.o'. 1549 */ 1550 if ((file = tempnam(NULL, ".cw")) == NULL) { 1551 nomem(); 1552 return (-1); 1553 } 1554 (void) strlcpy(ctx->i_discard, file, MAXPATHLEN); 1555 (void) strlcat(ctx->i_discard, ".o", MAXPATHLEN); 1556 free(file); 1557 1558 if ((ctx->i_stderr = tempnam(NULL, ".cw")) == NULL) { 1559 nomem(); 1560 return (-1); 1561 } 1562 1563 if ((ctx->i_pid = fork()) == 0) { 1564 int fd; 1565 1566 (void) fclose(stderr); 1567 if ((fd = open(ctx->i_stderr, O_WRONLY | O_CREAT | O_EXCL, 1568 0666)) < 0) { 1569 cw_perror("open failed for standard error"); 1570 exit(1); 1571 } 1572 if (dup2(fd, 2) < 0) { 1573 cw_perror("dup2 failed for standard error"); 1574 exit(1); 1575 } 1576 if (fd != 2) 1577 (void) close(fd); 1578 if (freopen("/dev/fd/2", "w", stderr) == NULL) { 1579 cw_perror("freopen failed for /dev/fd/2"); 1580 exit(1); 1581 } 1582 prepctx(ctx); 1583 exit(invoke(ctx)); 1584 } 1585 1586 if (ctx->i_pid < 0) { 1587 cw_perror("fork failed"); 1588 return (1); 1589 } 1590 1591 if (block) 1592 return (reap(ctx)); 1593 1594 return (0); 1595 } 1596 1597 int 1598 main(int argc, char **argv) 1599 { 1600 cw_ictx_t *ctx = newictx(); 1601 cw_ictx_t *ctx_shadow = newictx(); 1602 const char *dir; 1603 char cc_buf[MAXPATHLEN], gcc_buf[MAXPATHLEN]; 1604 int do_serial, do_shadow; 1605 int ret = 0; 1606 1607 if ((progname = strrchr(argv[0], '/')) == NULL) 1608 progname = argv[0]; 1609 else 1610 progname++; 1611 1612 if (ctx == NULL || ctx_shadow == NULL) 1613 nomem(); 1614 1615 ctx->i_flags = CW_F_ECHO|CW_F_XLATE; 1616 1617 /* 1618 * Figure out where to get our tools from. This depends on 1619 * the environment variables set at run time. 1620 */ 1621 if ((dir = getenv("SPRO_VROOT")) != NULL) { 1622 (void) snprintf(cc_buf, MAXPATHLEN, "%s/bin", dir); 1623 } else if ((dir = getenv("SPRO_ROOT")) != NULL) { 1624 (void) snprintf(cc_buf, MAXPATHLEN, "%s/SOS10/bin", dir); 1625 } else if ((dir = getenv("BUILD_TOOLS")) != NULL) { 1626 (void) snprintf(cc_buf, MAXPATHLEN, 1627 "%s/SUNWspro/SOS10/bin", dir); 1628 } 1629 if (dir != NULL) { 1630 dirs[CIDX(CW_C_CC, 0)] = (const char *)cc_buf; 1631 dirs[CIDX(CW_C_CC, CW_F_CXX)] = (const char *)cc_buf; 1632 } 1633 1634 if ((dir = getenv("GNU_ROOT")) != NULL) { 1635 (void) snprintf(gcc_buf, MAXPATHLEN, "%s/bin", dir); 1636 dirs[CIDX(CW_C_GCC, 0)] = (const char *)gcc_buf; 1637 dirs[CIDX(CW_C_GCC, CW_F_CXX)] = (const char *)gcc_buf; 1638 } 1639 1640 if ((dir = getenv("CW_CC_DIR")) != NULL) 1641 dirs[CIDX(CW_C_CC, 0)] = dir; 1642 if ((dir = getenv("CW_CPLUSPLUS_DIR")) != NULL) 1643 dirs[CIDX(CW_C_CC, CW_F_CXX)] = dir; 1644 if ((dir = getenv("CW_GCC_DIR")) != NULL) 1645 dirs[CIDX(CW_C_GCC, 0)] = dir; 1646 if ((dir = getenv("CW_GPLUSPLUS_DIR")) != NULL) 1647 dirs[CIDX(CW_C_GCC, CW_F_CXX)] = dir; 1648 1649 do_shadow = (getenv("CW_NO_SHADOW") ? 0 : 1); 1650 do_serial = (getenv("CW_SHADOW_SERIAL") ? 1 : 0); 1651 1652 if (getenv("CW_NO_EXEC") == NULL) 1653 ctx->i_flags |= CW_F_EXEC; 1654 1655 /* 1656 * The first argument must be one of "-_cc", "-_gcc", "-_CC", or "-_g++" 1657 */ 1658 if (argc == 1) 1659 usage(); 1660 argc--; 1661 argv++; 1662 if (strcmp(argv[0], "-_cc") == 0) { 1663 ctx->i_compiler = CW_C_CC; 1664 } else if (strcmp(argv[0], "-_gcc") == 0) { 1665 ctx->i_compiler = CW_C_GCC; 1666 } else if (strcmp(argv[0], "-_CC") == 0) { 1667 ctx->i_compiler = CW_C_CC; 1668 ctx->i_flags |= CW_F_CXX; 1669 } else if (strcmp(argv[0], "-_g++") == 0) { 1670 ctx->i_compiler = CW_C_GCC; 1671 ctx->i_flags |= CW_F_CXX; 1672 } else { 1673 /* assume "-_gcc" by default */ 1674 argc++; 1675 argv--; 1676 ctx->i_compiler = CW_C_GCC; 1677 } 1678 1679 /* 1680 * -_compiler - tell us the path to the primary compiler only 1681 */ 1682 if (argc > 1 && strcmp(argv[1], "-_compiler") == 0) { 1683 ctx->i_flags &= ~CW_F_XLATE; 1684 prepctx(ctx); 1685 (void) printf("%s\n", ctx->i_ae->ael_head->ae_arg); 1686 return (0); 1687 } 1688 1689 /* 1690 * -_versions - tell us the cw version, paths to all compilers, and 1691 * ask each for its version if we know how. 1692 */ 1693 if (argc > 1 && strcmp(argv[1], "-_versions") == 0) { 1694 (void) printf("%s", "cw version %I%"); 1695 if (!do_shadow) 1696 (void) printf(" (SHADOW MODE DISABLED)"); 1697 (void) printf("\n"); 1698 (void) fflush(stdout); 1699 ctx->i_flags &= ~CW_F_ECHO; 1700 ctx->i_flags |= CW_F_PROG|CW_F_EXEC; 1701 argc--; 1702 argv++; 1703 do_serial = 1; 1704 } 1705 1706 ctx->i_oldargc = argc; 1707 ctx->i_oldargv = argv; 1708 1709 ret |= exec_ctx(ctx, do_serial); 1710 1711 if (do_shadow) { 1712 (void) memcpy(ctx_shadow, ctx, sizeof (cw_ictx_t)); 1713 ctx_shadow->i_flags |= CW_F_SHADOW; 1714 ret |= exec_ctx(ctx_shadow, 1); 1715 } 1716 1717 if (!do_serial) 1718 ret |= reap(ctx); 1719 1720 return (ret); 1721 } 1722