1 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2018, Richard Lowe. 25 */ 26 /* 27 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 /* 32 * Wrapper for the GNU C compiler to make it accept the Sun C compiler 33 * arguments where possible. 34 * 35 * Since the translation is inexact, this is something of a work-in-progress. 36 * 37 */ 38 39 /* If you modify this file, you must increment CW_VERSION */ 40 #define CW_VERSION "3.0" 41 42 /* 43 * -# Verbose mode 44 * -### Show compiler commands built by driver, no compilation 45 * -A<name[(tokens)]> Preprocessor predicate assertion 46 * -B<[static|dynamic]> Specify dynamic or static binding 47 * -C Prevent preprocessor from removing comments 48 * -c Compile only - produce .o files, suppress linking 49 * -cg92 Alias for -xtarget=ss1000 50 * -D<name[=token]> Associate name with token as if by #define 51 * -d[y|n] dynamic [-dy] or static [-dn] option to linker 52 * -E Compile source through preprocessor only, output to stdout 53 * -erroff=<t> Suppress warnings specified by tags t(%none, %all, <tag list>) 54 * -errtags=<a> Display messages with tags a(no, yes) 55 * -errwarn=<t> Treats warnings specified by tags t(%none, %all, <tag list>) 56 * as errors 57 * -fast Optimize using a selection of options 58 * -fd Report old-style function definitions and declarations 59 * -fnonstd Initialize floating-point hardware to non-standard preferences 60 * -fns[=<yes|no>] Select non-standard floating point mode 61 * -fprecision=<p> Set FP rounding precision mode p(single, double, extended) 62 * -fround=<r> Select the IEEE rounding mode in effect at startup 63 * -fsimple[=<n>] Select floating-point optimization preferences <n> 64 * -fsingle Use single-precision arithmetic (-Xt and -Xs modes only) 65 * -ftrap=<t> Select floating-point trapping mode in effect at startup 66 * -fstore force floating pt. values to target precision on assignment 67 * -G Build a dynamic shared library 68 * -g Compile for debugging 69 * -H Print path name of each file included during compilation 70 * -h <name> Assign <name> to generated dynamic shared library 71 * -I<dir> Add <dir> to preprocessor #include file search path 72 * -i Passed to linker to ignore any LD_LIBRARY_PATH setting 73 * -keeptmp Keep temporary files created during compilation 74 * -L<dir> Pass to linker to add <dir> to the library search path 75 * -l<name> Link with library lib<name>.a or lib<name>.so 76 * -mc Remove duplicate strings from .comment section of output files 77 * -mr Remove all strings from .comment section of output files 78 * -mr,"string" Remove all strings and append "string" to .comment section 79 * -mt Specify options needed when compiling multi-threaded code 80 * -native Find available processor, generate code accordingly 81 * -nofstore Do not force floating pt. values to target precision 82 * on assignment 83 * -norunpath Do not build in a runtime path for shared libraries 84 * -O Use default optimization level (-xO2 or -xO3. Check man page.) 85 * -o <outputfile> Set name of output file to <outputfile> 86 * -P Compile source through preprocessor only, output to .i file 87 * -p Compile for profiling with prof 88 * -Q[y|n] Emit/don't emit identification info to output file 89 * -R<dir[:dir]> Build runtime search path list into executable 90 * -S Compile and only generate assembly code (.s) 91 * -s Strip symbol table from the executable file 92 * -t Turn off duplicate symbol warnings when linking 93 * -U<name> Delete initial definition of preprocessor symbol <name> 94 * -V Report version number of each compilation phase 95 * -v Do stricter semantic checking 96 * -W<c>,<arg> Pass <arg> to specified component <c> (a,l,m,p,0,2,h,i,u) 97 * -w Suppress compiler warning messages 98 * -Xa Compile assuming ANSI C conformance, allow K & R extensions 99 * (default mode) 100 * -Xs Compile assuming (pre-ANSI) K & R C style code 101 * -Xt Compile assuming K & R conformance, allow ANSI C 102 * -xarch=<a> Specify target architecture instruction set 103 * -xbuiltin[=<b>] When profitable inline, or substitute intrinisic functions 104 * for system functions, b={%all,%none} 105 * -xCC Accept C++ style comments 106 * -xchip=<c> Specify the target processor for use by the optimizer 107 * -xcode=<c> Generate different code for forming addresses 108 * -xcrossfile[=<n>] Enable optimization and inlining across source files, 109 * n={0|1} 110 * -xe Perform only syntax/semantic checking, no code generation 111 * -xF Compile for later mapfile reordering or unused section 112 * elimination 113 * -xhelp=<f> Display on-line help information f(flags, readme, errors) 114 * -xildoff Cancel -xildon 115 * -xildon Enable use of the incremental linker, ild 116 * -xinline=[<a>,...,<a>] Attempt inlining of specified user routines, 117 * <a>={%auto,func,no%func} 118 * -xlibmieee Force IEEE 754 return values for math routines in 119 * exceptional cases 120 * -xlibmil Inline selected libm math routines for optimization 121 * -xlic_lib=sunperf Link in the Sun supplied performance libraries 122 * -xlicinfo Show license server information 123 * -xmaxopt=[off,1,2,3,4,5] maximum optimization level allowed on #pragma opt 124 * -xO<n> Generate optimized code (n={1|2|3|4|5}) 125 * -xP Print prototypes for function definitions 126 * -xprofile=<p> Collect data for a profile or use a profile to optimize 127 * <p>={{collect,use}[:<path>],tcov} 128 * -xregs=<r> Control register allocation 129 * -xs Allow debugging without object (.o) files 130 * -xsb Compile for use with the WorkShop source browser 131 * -xsbfast Generate only WorkShop source browser info, no compilation 132 * -xsfpconst Represent unsuffixed floating point constants as single 133 * precision 134 * -xspace Do not do optimizations that increase code size 135 * -xstrconst Place string literals into read-only data segment 136 * -xtarget=<t> Specify target system for optimization 137 * -xtemp=<dir> Set directory for temporary files to <dir> 138 * -xtime Report the execution time for each compilation phase 139 * -xunroll=n Enable unrolling loops n times where possible 140 * -Y<c>,<dir> Specify <dir> for location of component <c> (a,l,m,p,0,h,i,u) 141 * -YA,<dir> Change default directory searched for components 142 * -YI,<dir> Change default directory searched for include files 143 * -YP,<dir> Change default directory for finding libraries files 144 * -YS,<dir> Change default directory for startup object files 145 */ 146 147 /* 148 * Translation table: 149 */ 150 /* 151 * -# -v 152 * -### error 153 * -A<name[(tokens)]> pass-thru 154 * -B<[static|dynamic]> pass-thru (syntax error for anything else) 155 * -C pass-thru 156 * -c pass-thru 157 * -cg92 -m32 -mcpu=v8 -mtune=supersparc (SPARC only) 158 * -D<name[=token]> pass-thru 159 * -dy or -dn -Wl,-dy or -Wl,-dn 160 * -E pass-thru 161 * -erroff=E_EMPTY_TRANSLATION_UNIT ignore 162 * -errtags=%all -Wall 163 * -errwarn=%all -Werror else -Wno-error 164 * -fast error 165 * -fd error 166 * -fnonstd error 167 * -fns[=<yes|no>] error 168 * -fprecision=<p> error 169 * -fround=<r> error 170 * -fsimple[=<n>] error 171 * -fsingle[=<n>] error 172 * -ftrap=<t> error 173 * -fstore error 174 * -G pass-thru 175 * -g pass-thru 176 * -H pass-thru 177 * -h <name> pass-thru 178 * -I<dir> pass-thru 179 * -i pass-thru 180 * -keeptmp -save-temps 181 * -L<dir> pass-thru 182 * -l<name> pass-thru 183 * -mc error 184 * -mr error 185 * -mr,"string" error 186 * -mt -D_REENTRANT 187 * -native error 188 * -nofstore error 189 * -nolib -nodefaultlibs 190 * -norunpath ignore 191 * -O -O1 (Check the man page to be certain) 192 * -o <outputfile> pass-thru 193 * -P -E -o filename.i (or error) 194 * -p pass-thru 195 * -Q[y|n] error 196 * -R<dir[:dir]> pass-thru 197 * -S pass-thru 198 * -s -Wl,-s 199 * -t -Wl,-t 200 * -U<name> pass-thru 201 * -V --version 202 * -v -Wall 203 * -Wa,<arg> pass-thru 204 * -Wp,<arg> pass-thru except -xc99=<a> 205 * -Wl,<arg> pass-thru 206 * -W{m,0,2,h,i,u> error/ignore 207 * -xmodel=kernel -ffreestanding -mcmodel=kernel -mno-red-zone 208 * -Wu,-save_args -msave-args 209 * -w pass-thru 210 * -Xa -std=iso9899:199409 or -ansi 211 * -Xt error 212 * -Xs -traditional -std=c89 213 * -xarch=<a> table 214 * -xbuiltin[=<b>] -fbuiltin (-fno-builtin otherwise) 215 * -xCC ignore 216 * -xchip=<c> table 217 * -xcode=<c> table 218 * -xdebugformat=<format> ignore (always use dwarf-2 for gcc) 219 * -xcrossfile[=<n>] ignore 220 * -xe error 221 * -xF error 222 * -xhelp=<f> error 223 * -xildoff ignore 224 * -xildon ignore 225 * -xinline ignore 226 * -xlibmieee error 227 * -xlibmil error 228 * -xlic_lib=sunperf error 229 * -xmaxopt=[...] error 230 * -xO<n> -O<n> 231 * -xP error 232 * -xprofile=<p> error 233 * -xregs=<r> table 234 * -xs error 235 * -xsb error 236 * -xsbfast error 237 * -xsfpconst error 238 * -xspace ignore (-not -Os) 239 * -xstrconst ignore 240 * -xtarget=<t> table 241 * -xtemp=<dir> error 242 * -xtime error 243 * -xtransition -Wtransition 244 * -xunroll=n error 245 * -W0,-xdbggen=no%usedonly -fno-eliminate-unused-debug-symbols 246 * -fno-eliminate-unused-debug-types 247 * -Y<c>,<dir> error 248 * -YA,<dir> error 249 * -YI,<dir> -nostdinc -I<dir> 250 * -YP,<dir> error 251 * -YS,<dir> error 252 */ 253 254 #include <ctype.h> 255 #include <err.h> 256 #include <errno.h> 257 #include <fcntl.h> 258 #include <getopt.h> 259 #include <stdio.h> 260 #include <stdlib.h> 261 #include <string.h> 262 #include <unistd.h> 263 264 #include <sys/param.h> 265 #include <sys/stat.h> 266 #include <sys/types.h> 267 #include <sys/utsname.h> 268 #include <sys/wait.h> 269 270 #define CW_F_CXX 0x01 271 #define CW_F_SHADOW 0x02 272 #define CW_F_EXEC 0x04 273 #define CW_F_ECHO 0x08 274 #define CW_F_XLATE 0x10 275 #define CW_F_PROG 0x20 276 277 typedef enum cw_op { 278 CW_O_NONE = 0, 279 CW_O_PREPROCESS, 280 CW_O_COMPILE, 281 CW_O_LINK 282 } cw_op_t; 283 284 struct aelist { 285 struct ae { 286 struct ae *ae_next; 287 char *ae_arg; 288 } *ael_head, *ael_tail; 289 int ael_argc; 290 }; 291 292 typedef enum { 293 GNU, 294 SUN 295 } compiler_style_t; 296 297 typedef struct { 298 char *c_name; 299 char *c_path; 300 compiler_style_t c_style; 301 } cw_compiler_t; 302 303 typedef struct cw_ictx { 304 struct cw_ictx *i_next; 305 cw_compiler_t *i_compiler; 306 struct aelist *i_ae; 307 uint32_t i_flags; 308 int i_oldargc; 309 char **i_oldargv; 310 pid_t i_pid; 311 char i_discard[MAXPATHLEN]; 312 char *i_stderr; 313 } cw_ictx_t; 314 315 /* 316 * Status values to indicate which Studio compiler and associated 317 * flags are being used. 318 */ 319 #define M32 0x01 /* -m32 - only on Studio 12 */ 320 #define M64 0x02 /* -m64 - only on Studio 12 */ 321 #define SS11 0x100 /* Studio 11 */ 322 #define SS12 0x200 /* Studio 12 */ 323 324 #define TRANS_ENTRY 5 325 /* 326 * Translation table definition for the -xarch= flag. The "x_arg" 327 * value is translated into the appropriate gcc flags according 328 * to the values in x_trans[n]. The x_flags indicates what compiler 329 * is being used and what flags have been set via the use of 330 * "x_arg". 331 */ 332 typedef struct xarch_table { 333 char *x_arg; 334 int x_flags; 335 char *x_trans[TRANS_ENTRY]; 336 } xarch_table_t; 337 338 /* 339 * The translation table for the -xarch= flag used in the Studio compilers. 340 */ 341 static const xarch_table_t xtbl[] = { 342 #if defined(__x86) 343 { "generic", SS11, {NULL} }, 344 { "generic64", (SS11|M64), { "-m64", "-mtune=opteron" } }, 345 { "amd64", (SS11|M64), { "-m64", "-mtune=opteron" } }, 346 { "386", SS11, { "-march=i386" } }, 347 { "pentium_pro", SS11, { "-march=pentiumpro" } }, 348 { "sse", SS11, { "-msse", "-mfpmath=sse" } }, 349 { "sse2", SS11, { "-msse2", "-mfpmath=sse" } }, 350 #elif defined(__sparc) 351 { "generic", (SS11|M32), { "-m32", "-mcpu=v8" } }, 352 { "generic64", (SS11|M64), { "-m64", "-mcpu=v9" } }, 353 { "v8", (SS11|M32), { "-m32", "-mcpu=v8", "-mno-v8plus" } }, 354 { "v8plus", (SS11|M32), { "-m32", "-mcpu=v9", "-mv8plus" } }, 355 { "v8plusa", (SS11|M32), { "-m32", "-mcpu=ultrasparc", "-mv8plus", 356 "-mvis" } }, 357 { "v8plusb", (SS11|M32), { "-m32", "-mcpu=ultrasparc3", "-mv8plus", 358 "-mvis" } }, 359 { "v9", (SS11|M64), { "-m64", "-mcpu=v9" } }, 360 { "v9a", (SS11|M64), { "-m64", "-mcpu=ultrasparc", "-mvis" } }, 361 { "v9b", (SS11|M64), { "-m64", "-mcpu=ultrasparc3", "-mvis" } }, 362 { "sparc", SS12, { "-mcpu=v9", "-mv8plus" } }, 363 { "sparcvis", SS12, { "-mcpu=ultrasparc", "-mvis" } }, 364 { "sparcvis2", SS12, { "-mcpu=ultrasparc3", "-mvis" } } 365 #endif 366 }; 367 368 static int xtbl_size = sizeof (xtbl) / sizeof (xarch_table_t); 369 370 static const char *xchip_tbl[] = { 371 #if defined(__x86) 372 "386", "-mtune=i386", NULL, 373 "486", "-mtune=i486", NULL, 374 "pentium", "-mtune=pentium", NULL, 375 "pentium_pro", "-mtune=pentiumpro", NULL, 376 #elif defined(__sparc) 377 "super", "-mtune=supersparc", NULL, 378 "ultra", "-mtune=ultrasparc", NULL, 379 "ultra3", "-mtune=ultrasparc3", NULL, 380 #endif 381 NULL, NULL 382 }; 383 384 static const char *xcode_tbl[] = { 385 #if defined(__sparc) 386 "abs32", "-fno-pic", "-mcmodel=medlow", NULL, 387 "abs44", "-fno-pic", "-mcmodel=medmid", NULL, 388 "abs64", "-fno-pic", "-mcmodel=medany", NULL, 389 "pic13", "-fpic", NULL, 390 "pic32", "-fPIC", NULL, 391 #endif 392 NULL, NULL 393 }; 394 395 static const char *xtarget_tbl[] = { 396 #if defined(__x86) 397 "pentium_pro", "-march=pentiumpro", NULL, 398 #endif /* __x86 */ 399 NULL, NULL 400 }; 401 402 static const char *xregs_tbl[] = { 403 #if defined(__sparc) 404 "appl", "-mapp-regs", NULL, 405 "no%appl", "-mno-app-regs", NULL, 406 "float", "-mfpu", NULL, 407 "no%float", "-mno-fpu", NULL, 408 #endif /* __sparc */ 409 NULL, NULL 410 }; 411 412 static void 413 nomem(void) 414 { 415 errx(1, "out of memory"); 416 } 417 418 static void 419 newae(struct aelist *ael, const char *arg) 420 { 421 struct ae *ae; 422 423 if ((ae = calloc(sizeof (*ae), 1)) == NULL) 424 nomem(); 425 ae->ae_arg = strdup(arg); 426 if (ael->ael_tail == NULL) 427 ael->ael_head = ae; 428 else 429 ael->ael_tail->ae_next = ae; 430 ael->ael_tail = ae; 431 ael->ael_argc++; 432 } 433 434 static cw_ictx_t * 435 newictx(void) 436 { 437 cw_ictx_t *ctx = calloc(sizeof (cw_ictx_t), 1); 438 if (ctx) 439 if ((ctx->i_ae = calloc(sizeof (struct aelist), 1)) == NULL) { 440 free(ctx); 441 return (NULL); 442 } 443 444 return (ctx); 445 } 446 447 static void 448 error(const char *arg) 449 { 450 errx(2, "error: mapping failed at or near arg '%s'", arg); 451 } 452 453 /* 454 * Add the current favourite set of warnings to the gcc invocation. 455 */ 456 static void 457 warnings(struct aelist *h) 458 { 459 static int warningsonce; 460 461 if (warningsonce++) 462 return; 463 464 /* 465 * Enable as many warnings as exist, then disable those that we never 466 * ever want. 467 */ 468 newae(h, "-Wall"); 469 newae(h, "-Wextra"); 470 } 471 472 static void 473 optim_disable(struct aelist *h, int level) 474 { 475 if (level >= 2) { 476 newae(h, "-fno-strict-aliasing"); 477 newae(h, "-fno-unit-at-a-time"); 478 newae(h, "-fno-optimize-sibling-calls"); 479 } 480 } 481 482 /* ARGSUSED */ 483 static void 484 Xamode(struct aelist __unused *h) 485 { 486 } 487 488 static void 489 Xsmode(struct aelist *h) 490 { 491 static int xsonce; 492 493 if (xsonce++) 494 return; 495 496 newae(h, "-traditional"); 497 newae(h, "-traditional-cpp"); 498 } 499 500 static void 501 usage() 502 { 503 extern char *__progname; 504 (void) fprintf(stderr, 505 "usage: %s [-C] [--versions] --primary <compiler> " 506 "[--shadow <compiler>]... -- cflags...\n", 507 __progname); 508 (void) fprintf(stderr, "compilers take the form: name,path,style\n" 509 " - name: a unique name usable in flag specifiers\n" 510 " - path: path to the compiler binary\n" 511 " - style: the style of flags expected: either sun or gnu\n"); 512 exit(2); 513 } 514 515 static int 516 xlate_xtb(struct aelist *h, const char *xarg) 517 { 518 int i, j; 519 520 for (i = 0; i < xtbl_size; i++) { 521 if (strcmp(xtbl[i].x_arg, xarg) == 0) 522 break; 523 } 524 525 /* 526 * At the end of the table and so no matching "arg" entry 527 * found and so this must be a bad -xarch= flag. 528 */ 529 if (i == xtbl_size) 530 error(xarg); 531 532 for (j = 0; j < TRANS_ENTRY; j++) { 533 if (xtbl[i].x_trans[j] != NULL) 534 newae(h, xtbl[i].x_trans[j]); 535 else 536 break; 537 } 538 return (xtbl[i].x_flags); 539 540 } 541 542 static void 543 xlate(struct aelist *h, const char *xarg, const char **table) 544 { 545 while (*table != NULL && strcmp(xarg, *table) != 0) { 546 while (*table != NULL) 547 table++; 548 table++; 549 } 550 551 if (*table == NULL) 552 error(xarg); 553 554 table++; 555 556 while (*table != NULL) { 557 newae(h, *table); 558 table++; 559 } 560 } 561 562 static void 563 do_gcc(cw_ictx_t *ctx) 564 { 565 int c; 566 int nolibc = 0; 567 int in_output = 0, seen_o = 0, c_files = 0; 568 cw_op_t op = CW_O_LINK; 569 char *model = NULL; 570 char *nameflag; 571 int mflag = 0; 572 573 if (ctx->i_flags & CW_F_PROG) { 574 newae(ctx->i_ae, "--version"); 575 return; 576 } 577 578 newae(ctx->i_ae, "-fident"); 579 newae(ctx->i_ae, "-finline"); 580 newae(ctx->i_ae, "-fno-inline-functions"); 581 newae(ctx->i_ae, "-fno-builtin"); 582 newae(ctx->i_ae, "-fno-asm"); 583 newae(ctx->i_ae, "-fdiagnostics-show-option"); 584 newae(ctx->i_ae, "-nodefaultlibs"); 585 586 #if defined(__sparc) 587 /* 588 * The SPARC ldd and std instructions require 8-byte alignment of 589 * their address operand. gcc correctly uses them only when the 590 * ABI requires 8-byte alignment; unfortunately we have a number of 591 * pieces of buggy code that doesn't conform to the ABI. This 592 * flag makes gcc work more like Studio with -xmemalign=4. 593 */ 594 newae(ctx->i_ae, "-mno-integer-ldd-std"); 595 #endif 596 597 /* 598 * This is needed because 'u' is defined 599 * under a conditional on 'sun'. Should 600 * probably just remove the conditional, 601 * or make it be dependent on '__sun'. 602 * 603 * -Dunix is also missing in enhanced ANSI mode 604 */ 605 newae(ctx->i_ae, "-D__sun"); 606 607 if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1) 608 nomem(); 609 610 /* 611 * Walk the argument list, translating as we go .. 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, "-_g++=", 6) == 0) { 649 newae(ctx->i_ae, strchr(arg, '=') + 1); 650 continue; 651 } 652 if (strncmp(arg, "-compat=", 8) == 0) { 653 /* discard -compat=4 and -compat=5 */ 654 continue; 655 } 656 if (strcmp(arg, "-Qoption") == 0) { 657 /* discard -Qoption and its two arguments */ 658 if (ctx->i_oldargc < 3) 659 error(arg); 660 ctx->i_oldargc -= 2; 661 ctx->i_oldargv += 2; 662 continue; 663 } 664 if (strcmp(arg, "-xwe") == 0) { 665 /* turn warnings into errors */ 666 newae(ctx->i_ae, "-Werror"); 667 continue; 668 } 669 if (strcmp(arg, "-norunpath") == 0) { 670 /* gcc has no corresponding option */ 671 continue; 672 } 673 if (strcmp(arg, "-nolib") == 0) { 674 /* -nodefaultlibs is on by default */ 675 nolibc = 1; 676 continue; 677 } 678 #if defined(__sparc) 679 if (strcmp(arg, "-cg92") == 0) { 680 mflag |= xlate_xtb(ctx->i_ae, "v8"); 681 xlate(ctx->i_ae, "super", xchip_tbl); 682 continue; 683 } 684 #endif /* __sparc */ 685 } 686 687 switch ((c = arg[1])) { 688 case '_': 689 if ((strncmp(arg, nameflag, strlen(nameflag)) == 0) || 690 (strncmp(arg, "-_gcc=", 6) == 0) || 691 (strncmp(arg, "-_gnu=", 6) == 0)) { 692 newae(ctx->i_ae, strchr(arg, '=') + 1); 693 } 694 break; 695 case '#': 696 if (arglen == 1) { 697 newae(ctx->i_ae, "-v"); 698 break; 699 } 700 error(arg); 701 break; 702 case 'f': 703 if ((strcmp(arg, "-fpic") == 0) || 704 (strcmp(arg, "-fPIC") == 0)) { 705 newae(ctx->i_ae, arg); 706 break; 707 } 708 error(arg); 709 break; 710 case 'g': 711 newae(ctx->i_ae, "-gdwarf-2"); 712 break; 713 case 'E': 714 if (arglen == 1) { 715 newae(ctx->i_ae, "-xc"); 716 newae(ctx->i_ae, arg); 717 op = CW_O_PREPROCESS; 718 nolibc = 1; 719 break; 720 } 721 error(arg); 722 break; 723 case 'c': 724 case 'S': 725 if (arglen == 1) { 726 op = CW_O_COMPILE; 727 nolibc = 1; 728 } 729 /* FALLTHROUGH */ 730 case 'C': 731 case 'H': 732 case 'p': 733 if (arglen == 1) { 734 newae(ctx->i_ae, arg); 735 break; 736 } 737 error(arg); 738 break; 739 case 'A': 740 case 'h': 741 case 'I': 742 case 'i': 743 case 'L': 744 case 'l': 745 case 'R': 746 case 'U': 747 case 'u': 748 case 'w': 749 newae(ctx->i_ae, arg); 750 break; 751 case 'o': 752 seen_o = 1; 753 if (arglen == 1) { 754 in_output = 1; 755 newae(ctx->i_ae, arg); 756 } else if (ctx->i_flags & CW_F_SHADOW) { 757 newae(ctx->i_ae, "-o"); 758 newae(ctx->i_ae, ctx->i_discard); 759 } else { 760 newae(ctx->i_ae, arg); 761 } 762 break; 763 case 'D': 764 newae(ctx->i_ae, arg); 765 /* 766 * XXX Clearly a hack ... do we need _KADB too? 767 */ 768 if (strcmp(arg, "-D_KERNEL") == 0 || 769 strcmp(arg, "-D_BOOT") == 0) 770 newae(ctx->i_ae, "-ffreestanding"); 771 break; 772 case 'd': 773 if (arglen == 2) { 774 if (strcmp(arg, "-dy") == 0) { 775 newae(ctx->i_ae, "-Wl,-dy"); 776 break; 777 } 778 if (strcmp(arg, "-dn") == 0) { 779 newae(ctx->i_ae, "-Wl,-dn"); 780 break; 781 } 782 } 783 if (strcmp(arg, "-dalign") == 0) { 784 /* 785 * -dalign forces alignment in some cases; 786 * gcc does not need any flag to do this. 787 */ 788 break; 789 } 790 error(arg); 791 break; 792 case 'e': 793 if (strcmp(arg, 794 "-erroff=E_EMPTY_TRANSLATION_UNIT") == 0) { 795 /* 796 * Accept but ignore this -- gcc doesn't 797 * seem to complain about empty translation 798 * units 799 */ 800 break; 801 } 802 /* XX64 -- ignore all -erroff= options, for now */ 803 if (strncmp(arg, "-erroff=", 8) == 0) 804 break; 805 if (strcmp(arg, "-errtags=yes") == 0) { 806 warnings(ctx->i_ae); 807 break; 808 } 809 if (strcmp(arg, "-errwarn=%all") == 0) { 810 newae(ctx->i_ae, "-Werror"); 811 break; 812 } 813 error(arg); 814 break; 815 case 'G': 816 newae(ctx->i_ae, "-shared"); 817 nolibc = 1; 818 break; 819 case 'k': 820 if (strcmp(arg, "-keeptmp") == 0) { 821 newae(ctx->i_ae, "-save-temps"); 822 break; 823 } 824 error(arg); 825 break; 826 case 'm': 827 if (strcmp(arg, "-mt") == 0) { 828 newae(ctx->i_ae, "-D_REENTRANT"); 829 break; 830 } 831 if (strcmp(arg, "-m64") == 0) { 832 newae(ctx->i_ae, "-m64"); 833 #if defined(__x86) 834 newae(ctx->i_ae, "-mtune=opteron"); 835 #endif 836 mflag |= M64; 837 break; 838 } 839 if (strcmp(arg, "-m32") == 0) { 840 newae(ctx->i_ae, "-m32"); 841 mflag |= M32; 842 break; 843 } 844 error(arg); 845 break; 846 case 'B': /* linker options */ 847 case 'M': 848 case 'z': 849 { 850 char *opt; 851 size_t len; 852 char *s; 853 854 if (arglen == 1) { 855 opt = *++ctx->i_oldargv; 856 if (opt == NULL || *opt == '\0') 857 error(arg); 858 ctx->i_oldargc--; 859 } else { 860 opt = arg + 2; 861 } 862 len = strlen(opt) + 7; 863 if ((s = malloc(len)) == NULL) 864 nomem(); 865 (void) snprintf(s, len, "-Wl,-%c%s", c, opt); 866 newae(ctx->i_ae, s); 867 free(s); 868 } 869 break; 870 case 'O': 871 if (arglen == 1) { 872 newae(ctx->i_ae, "-O"); 873 break; 874 } 875 error(arg); 876 break; 877 case 'P': 878 /* 879 * We could do '-E -o filename.i', but that's hard, 880 * and we don't need it for the case that's triggering 881 * this addition. We'll require the user to specify 882 * -o in the Makefile. If they don't they'll find out 883 * in a hurry. 884 */ 885 newae(ctx->i_ae, "-E"); 886 op = CW_O_PREPROCESS; 887 nolibc = 1; 888 break; 889 case 's': 890 if (arglen == 1) { 891 newae(ctx->i_ae, "-Wl,-s"); 892 break; 893 } 894 error(arg); 895 break; 896 case 't': 897 if (arglen == 1) { 898 newae(ctx->i_ae, "-Wl,-t"); 899 break; 900 } 901 error(arg); 902 break; 903 case 'V': 904 if (arglen == 1) { 905 ctx->i_flags &= ~CW_F_ECHO; 906 newae(ctx->i_ae, "--version"); 907 break; 908 } 909 error(arg); 910 break; 911 case 'v': 912 if (arglen == 1) { 913 warnings(ctx->i_ae); 914 break; 915 } 916 error(arg); 917 break; 918 case 'W': 919 if (strncmp(arg, "-Wp,-xc99", 9) == 0) { 920 /* 921 * gcc's preprocessor will accept c99 922 * regardless, so accept and ignore. 923 */ 924 break; 925 } 926 if (strncmp(arg, "-Wa,", 4) == 0 || 927 strncmp(arg, "-Wp,", 4) == 0 || 928 strncmp(arg, "-Wl,", 4) == 0) { 929 newae(ctx->i_ae, arg); 930 break; 931 } 932 if (strcmp(arg, "-W0,-noglobal") == 0 || 933 strcmp(arg, "-W0,-xglobalstatic") == 0) { 934 /* 935 * gcc doesn't prefix local symbols 936 * in debug mode, so this is not needed. 937 */ 938 break; 939 } 940 if (strcmp(arg, "-W0,-Lt") == 0) { 941 /* 942 * Generate tests at the top of loops. 943 * There is no direct gcc equivalent, ignore. 944 */ 945 break; 946 } 947 if (strcmp(arg, "-W0,-xdbggen=no%usedonly") == 0) { 948 newae(ctx->i_ae, 949 "-fno-eliminate-unused-debug-symbols"); 950 newae(ctx->i_ae, 951 "-fno-eliminate-unused-debug-types"); 952 break; 953 } 954 if (strcmp(arg, "-W2,-xwrap_int") == 0) { 955 /* 956 * Use the legacy behaviour (pre-SS11) 957 * for integer wrapping. 958 * gcc does not need this. 959 */ 960 break; 961 } 962 if (strcmp(arg, "-Wd,-xsafe=unboundsym") == 0) { 963 /* 964 * Prevents optimizing away checks for 965 * unbound weak symbol addresses. gcc does 966 * not do this, so it's not needed. 967 */ 968 break; 969 } 970 if (strncmp(arg, "-Wc,-xcode=", 11) == 0) { 971 xlate(ctx->i_ae, arg + 11, xcode_tbl); 972 break; 973 } 974 if (strncmp(arg, "-Wc,-Qiselect", 13) == 0) { 975 /* 976 * Prevents insertion of register symbols. 977 * gcc doesn't do this, so ignore it. 978 */ 979 break; 980 } 981 if (strcmp(arg, "-Wc,-Qassembler-ounrefsym=0") == 0) { 982 /* 983 * Prevents optimizing away of static variables. 984 * gcc does not do this, so it's not needed. 985 */ 986 break; 987 } 988 #if defined(__x86) 989 if (strcmp(arg, "-Wu,-save_args") == 0) { 990 newae(ctx->i_ae, "-msave-args"); 991 break; 992 } 993 #endif /* __x86 */ 994 error(arg); 995 break; 996 case 'X': 997 if (strcmp(arg, "-Xa") == 0 || 998 strcmp(arg, "-Xt") == 0) { 999 Xamode(ctx->i_ae); 1000 break; 1001 } 1002 if (strcmp(arg, "-Xs") == 0) { 1003 Xsmode(ctx->i_ae); 1004 break; 1005 } 1006 error(arg); 1007 break; 1008 case 'x': 1009 if (arglen == 1) 1010 error(arg); 1011 switch (arg[2]) { 1012 case 'a': 1013 if (strncmp(arg, "-xarch=", 7) == 0) { 1014 mflag |= xlate_xtb(ctx->i_ae, arg + 7); 1015 break; 1016 } 1017 error(arg); 1018 break; 1019 case 'b': 1020 if (strncmp(arg, "-xbuiltin=", 10) == 0) { 1021 if (strcmp(arg + 10, "%all")) 1022 newae(ctx->i_ae, "-fbuiltin"); 1023 break; 1024 } 1025 error(arg); 1026 break; 1027 case 'C': 1028 /* Accept C++ style comments -- ignore */ 1029 if (strcmp(arg, "-xCC") == 0) 1030 break; 1031 error(arg); 1032 break; 1033 case 'c': 1034 if (strncmp(arg, "-xc99=%all", 10) == 0) { 1035 newae(ctx->i_ae, "-std=gnu99"); 1036 break; 1037 } 1038 if (strncmp(arg, "-xc99=%none", 11) == 0) { 1039 newae(ctx->i_ae, "-std=gnu89"); 1040 break; 1041 } 1042 if (strncmp(arg, "-xchip=", 7) == 0) { 1043 xlate(ctx->i_ae, arg + 7, xchip_tbl); 1044 break; 1045 } 1046 if (strncmp(arg, "-xcode=", 7) == 0) { 1047 xlate(ctx->i_ae, arg + 7, xcode_tbl); 1048 break; 1049 } 1050 if (strncmp(arg, "-xcrossfile", 11) == 0) 1051 break; 1052 error(arg); 1053 break; 1054 case 'd': 1055 if (strncmp(arg, "-xdebugformat=", 14) == 0) 1056 break; 1057 error(arg); 1058 break; 1059 case 'F': 1060 /* 1061 * Compile for mapfile reordering, or unused 1062 * section elimination, syntax can be -xF or 1063 * more complex, like -xF=%all -- ignore. 1064 */ 1065 if (strncmp(arg, "-xF", 3) == 0) 1066 break; 1067 error(arg); 1068 break; 1069 case 'i': 1070 if (strncmp(arg, "-xinline", 8) == 0) 1071 /* No inlining; ignore */ 1072 break; 1073 if (strcmp(arg, "-xildon") == 0 || 1074 strcmp(arg, "-xildoff") == 0) 1075 /* No incremental linking; ignore */ 1076 break; 1077 error(arg); 1078 break; 1079 #if defined(__x86) 1080 case 'm': 1081 if (strcmp(arg, "-xmodel=kernel") == 0) { 1082 newae(ctx->i_ae, "-ffreestanding"); 1083 newae(ctx->i_ae, "-mno-red-zone"); 1084 model = "-mcmodel=kernel"; 1085 nolibc = 1; 1086 break; 1087 } 1088 error(arg); 1089 break; 1090 #endif /* __x86 */ 1091 case 'O': 1092 if (strncmp(arg, "-xO", 3) == 0) { 1093 size_t len = strlen(arg); 1094 char *s = NULL; 1095 int c = *(arg + 3); 1096 int level; 1097 1098 if (len != 4 || !isdigit(c)) 1099 error(arg); 1100 1101 level = atoi(arg + 3); 1102 if (level > 5) 1103 error(arg); 1104 if (level >= 2) { 1105 /* 1106 * For gcc-3.4.x at -O2 we 1107 * need to disable optimizations 1108 * that break ON. 1109 */ 1110 optim_disable(ctx->i_ae, level); 1111 /* 1112 * limit -xO3 to -O2 as well. 1113 */ 1114 level = 2; 1115 } 1116 if (asprintf(&s, "-O%d", level) == -1) 1117 nomem(); 1118 newae(ctx->i_ae, s); 1119 free(s); 1120 break; 1121 } 1122 error(arg); 1123 break; 1124 case 'r': 1125 if (strncmp(arg, "-xregs=", 7) == 0) { 1126 xlate(ctx->i_ae, arg + 7, xregs_tbl); 1127 break; 1128 } 1129 error(arg); 1130 break; 1131 case 's': 1132 if (strcmp(arg, "-xs") == 0 || 1133 strcmp(arg, "-xspace") == 0 || 1134 strcmp(arg, "-xstrconst") == 0) 1135 break; 1136 error(arg); 1137 break; 1138 case 't': 1139 if (strncmp(arg, "-xtarget=", 9) == 0) { 1140 xlate(ctx->i_ae, arg + 9, xtarget_tbl); 1141 break; 1142 } 1143 error(arg); 1144 break; 1145 case 'e': 1146 case 'h': 1147 case 'l': 1148 default: 1149 error(arg); 1150 break; 1151 } 1152 break; 1153 case 'Y': 1154 if (arglen == 1) { 1155 if ((arg = *++ctx->i_oldargv) == NULL || 1156 *arg == '\0') 1157 error("-Y"); 1158 ctx->i_oldargc--; 1159 arglen = strlen(arg + 1); 1160 } else { 1161 arg += 2; 1162 } 1163 /* Just ignore -YS,... for now */ 1164 if (strncmp(arg, "S,", 2) == 0) 1165 break; 1166 if (strncmp(arg, "l,", 2) == 0) { 1167 char *s = strdup(arg); 1168 s[0] = '-'; 1169 s[1] = 'B'; 1170 newae(ctx->i_ae, s); 1171 free(s); 1172 break; 1173 } 1174 if (strncmp(arg, "I,", 2) == 0) { 1175 char *s = strdup(arg); 1176 s[0] = '-'; 1177 s[1] = 'I'; 1178 newae(ctx->i_ae, "-nostdinc"); 1179 newae(ctx->i_ae, s); 1180 free(s); 1181 break; 1182 } 1183 error(arg); 1184 break; 1185 case 'Q': 1186 /* 1187 * We could map -Qy into -Wl,-Qy etc. 1188 */ 1189 default: 1190 error(arg); 1191 break; 1192 } 1193 } 1194 1195 free(nameflag); 1196 1197 if (c_files > 1 && (ctx->i_flags & CW_F_SHADOW) && 1198 op != CW_O_PREPROCESS) { 1199 errx(2, "multiple source files are " 1200 "allowed only with -E or -P"); 1201 } 1202 1203 /* 1204 * Make sure that we do not have any unintended interactions between 1205 * the xarch options passed in and the version of the Studio compiler 1206 * used. 1207 */ 1208 if ((mflag & (SS11|SS12)) == (SS11|SS12)) { 1209 errx(2, 1210 "Conflicting \"-xarch=\" flags (both Studio 11 and 12)\n"); 1211 } 1212 1213 switch (mflag) { 1214 case 0: 1215 /* FALLTHROUGH */ 1216 case M32: 1217 #if defined(__sparc) 1218 /* 1219 * Only -m32 is defined and so put in the missing xarch 1220 * translation. 1221 */ 1222 newae(ctx->i_ae, "-mcpu=v8"); 1223 newae(ctx->i_ae, "-mno-v8plus"); 1224 #endif 1225 break; 1226 case M64: 1227 #if defined(__sparc) 1228 /* 1229 * Only -m64 is defined and so put in the missing xarch 1230 * translation. 1231 */ 1232 newae(ctx->i_ae, "-mcpu=v9"); 1233 #endif 1234 break; 1235 case SS12: 1236 #if defined(__sparc) 1237 /* no -m32/-m64 flag used - this is an error for sparc builds */ 1238 (void) fprintf(stderr, "No -m32/-m64 flag defined\n"); 1239 exit(2); 1240 #endif 1241 break; 1242 case SS11: 1243 /* FALLTHROUGH */ 1244 case (SS11|M32): 1245 case (SS11|M64): 1246 break; 1247 case (SS12|M32): 1248 #if defined(__sparc) 1249 /* 1250 * Need to add in further 32 bit options because with SS12 1251 * the xarch=sparcvis option can be applied to 32 or 64 1252 * bit, and so the translatation table (xtbl) cannot handle 1253 * that. 1254 */ 1255 newae(ctx->i_ae, "-mv8plus"); 1256 #endif 1257 break; 1258 case (SS12|M64): 1259 break; 1260 default: 1261 (void) fprintf(stderr, 1262 "Incompatible -xarch= and/or -m32/-m64 options used.\n"); 1263 exit(2); 1264 } 1265 1266 if ((op == CW_O_LINK || op == CW_O_PREPROCESS) && 1267 (ctx->i_flags & CW_F_SHADOW)) 1268 exit(0); 1269 1270 if (model != NULL) 1271 newae(ctx->i_ae, model); 1272 if (!nolibc) 1273 newae(ctx->i_ae, "-lc"); 1274 if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) { 1275 newae(ctx->i_ae, "-o"); 1276 newae(ctx->i_ae, ctx->i_discard); 1277 } 1278 } 1279 1280 static void 1281 do_cc(cw_ictx_t *ctx) 1282 { 1283 int in_output = 0, seen_o = 0; 1284 cw_op_t op = CW_O_LINK; 1285 char *nameflag; 1286 1287 if (ctx->i_flags & CW_F_PROG) { 1288 newae(ctx->i_ae, "-V"); 1289 return; 1290 } 1291 1292 if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1) 1293 nomem(); 1294 1295 while (--ctx->i_oldargc > 0) { 1296 char *arg = *++ctx->i_oldargv; 1297 1298 if (strncmp(arg, "-_CC=", 5) == 0) { 1299 newae(ctx->i_ae, strchr(arg, '=') + 1); 1300 continue; 1301 } 1302 1303 if (*arg != '-') { 1304 if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) { 1305 newae(ctx->i_ae, arg); 1306 } else { 1307 in_output = 0; 1308 newae(ctx->i_ae, ctx->i_discard); 1309 } 1310 continue; 1311 } 1312 switch (*(arg + 1)) { 1313 case '_': 1314 if ((strncmp(arg, nameflag, strlen(nameflag)) == 0) || 1315 (strncmp(arg, "-_cc=", 5) == 0) || 1316 (strncmp(arg, "-_sun=", 6) == 0)) { 1317 newae(ctx->i_ae, strchr(arg, '=') + 1); 1318 } 1319 break; 1320 1321 case 'V': 1322 ctx->i_flags &= ~CW_F_ECHO; 1323 newae(ctx->i_ae, arg); 1324 break; 1325 case 'o': 1326 seen_o = 1; 1327 if (strlen(arg) == 2) { 1328 in_output = 1; 1329 newae(ctx->i_ae, arg); 1330 } else if (ctx->i_flags & CW_F_SHADOW) { 1331 newae(ctx->i_ae, "-o"); 1332 newae(ctx->i_ae, ctx->i_discard); 1333 } else { 1334 newae(ctx->i_ae, arg); 1335 } 1336 break; 1337 case 'c': 1338 case 'S': 1339 if (strlen(arg) == 2) 1340 op = CW_O_COMPILE; 1341 newae(ctx->i_ae, arg); 1342 break; 1343 case 'E': 1344 case 'P': 1345 if (strlen(arg) == 2) 1346 op = CW_O_PREPROCESS; 1347 /*FALLTHROUGH*/ 1348 default: 1349 newae(ctx->i_ae, arg); 1350 } 1351 } 1352 1353 free(nameflag); 1354 1355 if ((op == CW_O_LINK || op == CW_O_PREPROCESS) && 1356 (ctx->i_flags & CW_F_SHADOW)) 1357 exit(0); 1358 1359 if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) { 1360 newae(ctx->i_ae, "-o"); 1361 newae(ctx->i_ae, ctx->i_discard); 1362 } 1363 } 1364 1365 static void 1366 prepctx(cw_ictx_t *ctx) 1367 { 1368 newae(ctx->i_ae, ctx->i_compiler->c_path); 1369 1370 if (ctx->i_flags & CW_F_PROG) { 1371 (void) printf("%s: %s\n", (ctx->i_flags & CW_F_SHADOW) ? 1372 "shadow" : "primary", ctx->i_compiler->c_path); 1373 (void) fflush(stdout); 1374 } 1375 1376 if (!(ctx->i_flags & CW_F_XLATE)) 1377 return; 1378 1379 switch (ctx->i_compiler->c_style) { 1380 case SUN: 1381 do_cc(ctx); 1382 break; 1383 case GNU: 1384 do_gcc(ctx); 1385 break; 1386 } 1387 } 1388 1389 static int 1390 invoke(cw_ictx_t *ctx) 1391 { 1392 char **newargv; 1393 int ac; 1394 struct ae *a; 1395 1396 if ((newargv = calloc(sizeof (*newargv), ctx->i_ae->ael_argc + 1)) == 1397 NULL) 1398 nomem(); 1399 1400 if (ctx->i_flags & CW_F_ECHO) 1401 (void) fprintf(stderr, "+ "); 1402 1403 for (ac = 0, a = ctx->i_ae->ael_head; a; a = a->ae_next, ac++) { 1404 newargv[ac] = a->ae_arg; 1405 if (ctx->i_flags & CW_F_ECHO) 1406 (void) fprintf(stderr, "%s ", a->ae_arg); 1407 if (a == ctx->i_ae->ael_tail) 1408 break; 1409 } 1410 1411 if (ctx->i_flags & CW_F_ECHO) { 1412 (void) fprintf(stderr, "\n"); 1413 (void) fflush(stderr); 1414 } 1415 1416 if (!(ctx->i_flags & CW_F_EXEC)) 1417 return (0); 1418 1419 /* 1420 * We must fix up the environment here so that the dependency files are 1421 * not trampled by the shadow compiler. Also take care of GCC 1422 * environment variables that will throw off gcc. This assumes a primary 1423 * gcc. 1424 */ 1425 if ((ctx->i_flags & CW_F_SHADOW) && 1426 (unsetenv("SUNPRO_DEPENDENCIES") != 0 || 1427 unsetenv("DEPENDENCIES_OUTPUT") != 0 || 1428 unsetenv("GCC_ROOT") != 0)) { 1429 (void) fprintf(stderr, "error: environment setup failed: %s\n", 1430 strerror(errno)); 1431 return (-1); 1432 } 1433 1434 (void) execv(newargv[0], newargv); 1435 warn("couldn't run %s", newargv[0]); 1436 1437 return (-1); 1438 } 1439 1440 static int 1441 reap(cw_ictx_t *ctx) 1442 { 1443 int status, ret = 0; 1444 char buf[1024]; 1445 struct stat s; 1446 1447 /* 1448 * Only wait for one specific child. 1449 */ 1450 if (ctx->i_pid <= 0) 1451 return (-1); 1452 1453 do { 1454 if (waitpid(ctx->i_pid, &status, 0) < 0) { 1455 warn("cannot reap child"); 1456 return (-1); 1457 } 1458 if (status != 0) { 1459 if (WIFSIGNALED(status)) { 1460 ret = -WTERMSIG(status); 1461 break; 1462 } else if (WIFEXITED(status)) { 1463 ret = WEXITSTATUS(status); 1464 break; 1465 } 1466 } 1467 } while (!WIFEXITED(status) && !WIFSIGNALED(status)); 1468 1469 (void) unlink(ctx->i_discard); 1470 1471 if (stat(ctx->i_stderr, &s) < 0) { 1472 warn("stat failed on child cleanup"); 1473 return (-1); 1474 } 1475 if (s.st_size != 0) { 1476 FILE *f; 1477 1478 if ((f = fopen(ctx->i_stderr, "r")) != NULL) { 1479 while (fgets(buf, sizeof (buf), f)) 1480 (void) fprintf(stderr, "%s", buf); 1481 (void) fflush(stderr); 1482 (void) fclose(f); 1483 } 1484 } 1485 (void) unlink(ctx->i_stderr); 1486 free(ctx->i_stderr); 1487 1488 /* 1489 * cc returns an error code when given -V; we want that to succeed. 1490 */ 1491 if (ctx->i_flags & CW_F_PROG) 1492 return (0); 1493 1494 return (ret); 1495 } 1496 1497 static int 1498 exec_ctx(cw_ictx_t *ctx, int block) 1499 { 1500 char *file; 1501 1502 /* 1503 * To avoid offending cc's sensibilities, the name of its output 1504 * file must end in '.o'. 1505 */ 1506 if ((file = tempnam(NULL, ".cw")) == NULL) { 1507 nomem(); 1508 return (-1); 1509 } 1510 (void) strlcpy(ctx->i_discard, file, MAXPATHLEN); 1511 (void) strlcat(ctx->i_discard, ".o", MAXPATHLEN); 1512 free(file); 1513 1514 if ((ctx->i_stderr = tempnam(NULL, ".cw")) == NULL) { 1515 nomem(); 1516 return (-1); 1517 } 1518 1519 if ((ctx->i_pid = fork()) == 0) { 1520 int fd; 1521 1522 (void) fclose(stderr); 1523 if ((fd = open(ctx->i_stderr, O_WRONLY | O_CREAT | O_EXCL, 1524 0666)) < 0) { 1525 err(1, "open failed for standard error"); 1526 } 1527 if (dup2(fd, 2) < 0) { 1528 err(1, "dup2 failed for standard error"); 1529 } 1530 if (fd != 2) 1531 (void) close(fd); 1532 if (freopen("/dev/fd/2", "w", stderr) == NULL) { 1533 err(1, "freopen failed for /dev/fd/2"); 1534 } 1535 1536 prepctx(ctx); 1537 exit(invoke(ctx)); 1538 } 1539 1540 if (ctx->i_pid < 0) { 1541 err(1, "fork failed"); 1542 } 1543 1544 if (block) 1545 return (reap(ctx)); 1546 1547 return (0); 1548 } 1549 1550 static void 1551 parse_compiler(const char *spec, cw_compiler_t *compiler) 1552 { 1553 char *tspec, *token; 1554 1555 if ((tspec = strdup(spec)) == NULL) 1556 nomem(); 1557 1558 if ((token = strsep(&tspec, ",")) == NULL) 1559 errx(1, "Compiler is missing a name: %s", spec); 1560 compiler->c_name = token; 1561 1562 if ((token = strsep(&tspec, ",")) == NULL) 1563 errx(1, "Compiler is missing a path: %s", spec); 1564 compiler->c_path = token; 1565 1566 if ((token = strsep(&tspec, ",")) == NULL) 1567 errx(1, "Compiler is missing a style: %s", spec); 1568 1569 if ((strcasecmp(token, "gnu") == 0) || 1570 (strcasecmp(token, "gcc") == 0)) 1571 compiler->c_style = GNU; 1572 else if ((strcasecmp(token, "sun") == 0) || 1573 (strcasecmp(token, "cc") == 0)) 1574 compiler->c_style = SUN; 1575 else 1576 errx(1, "unknown compiler style: %s", token); 1577 1578 if (tspec != NULL) 1579 errx(1, "Excess tokens in compiler: %s", spec); 1580 } 1581 1582 int 1583 main(int argc, char **argv) 1584 { 1585 int ch; 1586 cw_compiler_t primary = { NULL, NULL, 0 }; 1587 cw_compiler_t shadows[10]; 1588 int nshadows = 0; 1589 int ret = 0; 1590 boolean_t do_serial = B_FALSE; 1591 boolean_t do_exec = B_FALSE; 1592 boolean_t vflg = B_FALSE; 1593 boolean_t Cflg = B_FALSE; 1594 boolean_t cflg = B_FALSE; 1595 boolean_t nflg = B_FALSE; 1596 1597 cw_ictx_t *main_ctx; 1598 1599 static struct option longopts[] = { 1600 { "compiler", no_argument, NULL, 'c' }, 1601 { "noecho", no_argument, NULL, 'n' }, 1602 { "primary", required_argument, NULL, 'p' }, 1603 { "shadow", required_argument, NULL, 's' }, 1604 { "versions", no_argument, NULL, 'v' }, 1605 { NULL, 0, NULL, 0 }, 1606 }; 1607 1608 1609 if ((main_ctx = newictx()) == NULL) 1610 nomem(); 1611 1612 while ((ch = getopt_long(argc, argv, "C", longopts, NULL)) != -1) { 1613 switch (ch) { 1614 case 'c': 1615 cflg = B_TRUE; 1616 break; 1617 case 'C': 1618 Cflg = B_TRUE; 1619 break; 1620 case 'n': 1621 nflg = B_TRUE; 1622 break; 1623 case 'p': 1624 if (primary.c_path != NULL) { 1625 warnx("Only one primary compiler may " 1626 "be specified"); 1627 usage(); 1628 } 1629 1630 parse_compiler(optarg, &primary); 1631 break; 1632 case 's': 1633 if (nshadows >= 10) 1634 errx(1, "May only use 10 shadows at " 1635 "the moment"); 1636 parse_compiler(optarg, &shadows[nshadows]); 1637 nshadows++; 1638 break; 1639 case 'v': 1640 vflg = B_TRUE; 1641 break; 1642 default: 1643 (void) fprintf(stderr, "Did you forget '--'?\n"); 1644 usage(); 1645 } 1646 } 1647 1648 if (primary.c_path == NULL) { 1649 warnx("A primary compiler must be specified"); 1650 usage(); 1651 } 1652 1653 do_serial = (getenv("CW_SHADOW_SERIAL") == NULL) ? B_FALSE : B_TRUE; 1654 do_exec = (getenv("CW_NO_EXEC") == NULL) ? B_TRUE : B_FALSE; 1655 1656 /* Leave room for argv[0] */ 1657 argc -= (optind - 1); 1658 argv += (optind - 1); 1659 1660 main_ctx->i_oldargc = argc; 1661 main_ctx->i_oldargv = argv; 1662 main_ctx->i_flags = CW_F_XLATE; 1663 if (nflg == 0) 1664 main_ctx->i_flags |= CW_F_ECHO; 1665 if (do_exec) 1666 main_ctx->i_flags |= CW_F_EXEC; 1667 if (Cflg) 1668 main_ctx->i_flags |= CW_F_CXX; 1669 main_ctx->i_compiler = &primary; 1670 1671 if (cflg) { 1672 (void) fputs(primary.c_path, stdout); 1673 } 1674 1675 if (vflg) { 1676 (void) printf("cw version %s\n", CW_VERSION); 1677 (void) fflush(stdout); 1678 main_ctx->i_flags &= ~CW_F_ECHO; 1679 main_ctx->i_flags |= CW_F_PROG | CW_F_EXEC; 1680 do_serial = 1; 1681 } 1682 1683 ret |= exec_ctx(main_ctx, do_serial); 1684 1685 for (int i = 0; i < nshadows; i++) { 1686 int r; 1687 cw_ictx_t *shadow_ctx; 1688 1689 if ((shadow_ctx = newictx()) == NULL) 1690 nomem(); 1691 1692 memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t)); 1693 1694 shadow_ctx->i_flags |= CW_F_SHADOW; 1695 shadow_ctx->i_compiler = &shadows[i]; 1696 1697 r = exec_ctx(shadow_ctx, do_serial); 1698 if (r == 0) { 1699 shadow_ctx->i_next = main_ctx->i_next; 1700 main_ctx->i_next = shadow_ctx; 1701 } 1702 ret |= r; 1703 } 1704 1705 if (!do_serial) { 1706 cw_ictx_t *next = main_ctx; 1707 while (next != NULL) { 1708 cw_ictx_t *toreap = next; 1709 next = next->i_next; 1710 ret |= reap(toreap); 1711 } 1712 } 1713 1714 return (ret); 1715 }