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