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