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