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