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