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