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