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 void 598 do_gcc(cw_ictx_t *ctx) 599 { 600 int c; 601 int nolibc = 0; 602 int in_output = 0, seen_o = 0, c_files = 0; 603 cw_op_t op = CW_O_LINK; 604 char *model = NULL; 605 char *nameflag; 606 int mflag = 0; 607 608 if (ctx->i_flags & CW_F_PROG) { 609 newae(ctx->i_ae, "--version"); 610 return; 611 } 612 613 newae(ctx->i_ae, "-fident"); 614 newae(ctx->i_ae, "-finline"); 615 newae(ctx->i_ae, "-fno-inline-functions"); 616 newae(ctx->i_ae, "-fno-builtin"); 617 newae(ctx->i_ae, "-fno-asm"); 618 newae(ctx->i_ae, "-fdiagnostics-show-option"); 619 newae(ctx->i_ae, "-nodefaultlibs"); 620 621 #if defined(__sparc) 622 /* 623 * The SPARC ldd and std instructions require 8-byte alignment of 624 * their address operand. gcc correctly uses them only when the 625 * ABI requires 8-byte alignment; unfortunately we have a number of 626 * pieces of buggy code that doesn't conform to the ABI. This 627 * flag makes gcc work more like Studio with -xmemalign=4. 628 */ 629 newae(ctx->i_ae, "-mno-integer-ldd-std"); 630 #endif 631 632 /* 633 * This is needed because 'u' is defined 634 * under a conditional on 'sun'. Should 635 * probably just remove the conditional, 636 * or make it be dependent on '__sun'. 637 * 638 * -Dunix is also missing in enhanced ANSI mode 639 */ 640 newae(ctx->i_ae, "-D__sun"); 641 642 if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1) 643 nomem(); 644 645 /* 646 * Walk the argument list, translating as we go .. 647 */ 648 while (--ctx->i_oldargc > 0) { 649 char *arg = *++ctx->i_oldargv; 650 size_t arglen = strlen(arg); 651 652 if (*arg == '-') { 653 arglen--; 654 } else { 655 /* 656 * Discard inline files that gcc doesn't grok 657 */ 658 if (!in_output && arglen > 3 && 659 strcmp(arg + arglen - 3, ".il") == 0) 660 continue; 661 662 if (!in_output && arglen > 2 && 663 arg[arglen - 2] == '.' && 664 (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' || 665 arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i')) 666 c_files++; 667 668 /* 669 * Otherwise, filenames and partial arguments 670 * are passed through for gcc to chew on. However, 671 * output is always discarded for the secondary 672 * compiler. 673 */ 674 if ((ctx->i_flags & CW_F_SHADOW) && in_output) { 675 newae(ctx->i_ae, discard_file_name(ctx, arg)); 676 } else { 677 newae(ctx->i_ae, arg); 678 } 679 in_output = 0; 680 continue; 681 } 682 683 if (ctx->i_flags & CW_F_CXX) { 684 if (strncmp(arg, "-_g++=", 6) == 0) { 685 newae(ctx->i_ae, strchr(arg, '=') + 1); 686 continue; 687 } 688 if (strncmp(arg, "-compat=", 8) == 0) { 689 /* discard -compat=4 and -compat=5 */ 690 continue; 691 } 692 if (strcmp(arg, "-Qoption") == 0) { 693 /* discard -Qoption and its two arguments */ 694 if (ctx->i_oldargc < 3) 695 error(arg); 696 ctx->i_oldargc -= 2; 697 ctx->i_oldargv += 2; 698 continue; 699 } 700 if (strcmp(arg, "-xwe") == 0) { 701 /* turn warnings into errors */ 702 newae(ctx->i_ae, "-Werror"); 703 continue; 704 } 705 if (strcmp(arg, "-norunpath") == 0) { 706 /* gcc has no corresponding option */ 707 continue; 708 } 709 if (strcmp(arg, "-nolib") == 0) { 710 /* -nodefaultlibs is on by default */ 711 nolibc = 1; 712 continue; 713 } 714 #if defined(__sparc) 715 if (strcmp(arg, "-cg92") == 0) { 716 mflag |= xlate_xtb(ctx->i_ae, "v8"); 717 xlate(ctx->i_ae, "super", xchip_tbl); 718 continue; 719 } 720 #endif /* __sparc */ 721 } 722 723 switch ((c = arg[1])) { 724 case '_': 725 if ((strncmp(arg, nameflag, strlen(nameflag)) == 0) || 726 (strncmp(arg, "-_gcc=", 6) == 0) || 727 (strncmp(arg, "-_gnu=", 6) == 0)) { 728 newae(ctx->i_ae, strchr(arg, '=') + 1); 729 } 730 break; 731 case '#': 732 if (arglen == 1) { 733 newae(ctx->i_ae, "-v"); 734 break; 735 } 736 error(arg); 737 break; 738 case 'f': 739 if ((strcmp(arg, "-fpic") == 0) || 740 (strcmp(arg, "-fPIC") == 0)) { 741 newae(ctx->i_ae, arg); 742 break; 743 } 744 error(arg); 745 break; 746 case 'g': 747 newae(ctx->i_ae, "-gdwarf-2"); 748 break; 749 case 'E': 750 if (arglen == 1) { 751 newae(ctx->i_ae, "-xc"); 752 newae(ctx->i_ae, arg); 753 op = CW_O_PREPROCESS; 754 nolibc = 1; 755 break; 756 } 757 error(arg); 758 break; 759 case 'c': 760 case 'S': 761 if (arglen == 1) { 762 op = CW_O_COMPILE; 763 nolibc = 1; 764 } 765 /* FALLTHROUGH */ 766 case 'C': 767 case 'H': 768 case 'p': 769 if (arglen == 1) { 770 newae(ctx->i_ae, arg); 771 break; 772 } 773 error(arg); 774 break; 775 case 'A': 776 case 'h': 777 case 'I': 778 case 'i': 779 case 'L': 780 case 'l': 781 case 'R': 782 case 'U': 783 case 'u': 784 case 'w': 785 newae(ctx->i_ae, arg); 786 break; 787 case 'o': 788 seen_o = 1; 789 if (arglen == 1) { 790 in_output = 1; 791 newae(ctx->i_ae, arg); 792 } else if (ctx->i_flags & CW_F_SHADOW) { 793 newae(ctx->i_ae, "-o"); 794 newae(ctx->i_ae, discard_file_name(ctx, arg)); 795 } else { 796 newae(ctx->i_ae, arg); 797 } 798 break; 799 case 'D': 800 newae(ctx->i_ae, arg); 801 /* 802 * XXX Clearly a hack ... do we need _KADB too? 803 */ 804 if (strcmp(arg, "-D_KERNEL") == 0 || 805 strcmp(arg, "-D_BOOT") == 0) 806 newae(ctx->i_ae, "-ffreestanding"); 807 break; 808 case 'd': 809 if (arglen == 2) { 810 if (strcmp(arg, "-dy") == 0) { 811 newae(ctx->i_ae, "-Wl,-dy"); 812 break; 813 } 814 if (strcmp(arg, "-dn") == 0) { 815 newae(ctx->i_ae, "-Wl,-dn"); 816 break; 817 } 818 } 819 if (strcmp(arg, "-dalign") == 0) { 820 /* 821 * -dalign forces alignment in some cases; 822 * gcc does not need any flag to do this. 823 */ 824 break; 825 } 826 error(arg); 827 break; 828 case 'e': 829 if (strcmp(arg, 830 "-erroff=E_EMPTY_TRANSLATION_UNIT") == 0) { 831 /* 832 * Accept but ignore this -- gcc doesn't 833 * seem to complain about empty translation 834 * units 835 */ 836 break; 837 } 838 /* XX64 -- ignore all -erroff= options, for now */ 839 if (strncmp(arg, "-erroff=", 8) == 0) 840 break; 841 if (strcmp(arg, "-errtags=yes") == 0) { 842 warnings(ctx->i_ae); 843 break; 844 } 845 if (strcmp(arg, "-errwarn=%all") == 0) { 846 newae(ctx->i_ae, "-Werror"); 847 break; 848 } 849 error(arg); 850 break; 851 case 'G': 852 newae(ctx->i_ae, "-shared"); 853 nolibc = 1; 854 break; 855 case 'k': 856 if (strcmp(arg, "-keeptmp") == 0) { 857 newae(ctx->i_ae, "-save-temps"); 858 break; 859 } 860 error(arg); 861 break; 862 case 'm': 863 if (strcmp(arg, "-mt") == 0) { 864 newae(ctx->i_ae, "-D_REENTRANT"); 865 break; 866 } 867 if (strcmp(arg, "-m64") == 0) { 868 newae(ctx->i_ae, "-m64"); 869 #if defined(__x86) 870 newae(ctx->i_ae, "-mtune=opteron"); 871 #endif 872 mflag |= M64; 873 break; 874 } 875 if (strcmp(arg, "-m32") == 0) { 876 newae(ctx->i_ae, "-m32"); 877 mflag |= M32; 878 break; 879 } 880 error(arg); 881 break; 882 case 'B': /* linker options */ 883 case 'M': 884 case 'z': 885 { 886 char *opt; 887 size_t len; 888 char *s; 889 890 if (arglen == 1) { 891 opt = *++ctx->i_oldargv; 892 if (opt == NULL || *opt == '\0') 893 error(arg); 894 ctx->i_oldargc--; 895 } else { 896 opt = arg + 2; 897 } 898 len = strlen(opt) + 7; 899 if ((s = malloc(len)) == NULL) 900 nomem(); 901 (void) snprintf(s, len, "-Wl,-%c%s", c, opt); 902 newae(ctx->i_ae, s); 903 free(s); 904 } 905 break; 906 case 'O': 907 if (arglen == 1) { 908 newae(ctx->i_ae, "-O"); 909 break; 910 } 911 error(arg); 912 break; 913 case 'P': 914 /* 915 * We could do '-E -o filename.i', but that's hard, 916 * and we don't need it for the case that's triggering 917 * this addition. We'll require the user to specify 918 * -o in the Makefile. If they don't they'll find out 919 * in a hurry. 920 */ 921 newae(ctx->i_ae, "-E"); 922 op = CW_O_PREPROCESS; 923 nolibc = 1; 924 break; 925 case 's': 926 if (arglen == 1) { 927 newae(ctx->i_ae, "-Wl,-s"); 928 break; 929 } 930 error(arg); 931 break; 932 case 't': 933 if (arglen == 1) { 934 newae(ctx->i_ae, "-Wl,-t"); 935 break; 936 } 937 error(arg); 938 break; 939 case 'V': 940 if (arglen == 1) { 941 ctx->i_flags &= ~CW_F_ECHO; 942 newae(ctx->i_ae, "--version"); 943 break; 944 } 945 error(arg); 946 break; 947 case 'v': 948 if (arglen == 1) { 949 warnings(ctx->i_ae); 950 break; 951 } 952 error(arg); 953 break; 954 case 'W': 955 if (strncmp(arg, "-Wp,-xc99", 9) == 0) { 956 /* 957 * gcc's preprocessor will accept c99 958 * regardless, so accept and ignore. 959 */ 960 break; 961 } 962 if (strncmp(arg, "-Wa,", 4) == 0 || 963 strncmp(arg, "-Wp,", 4) == 0 || 964 strncmp(arg, "-Wl,", 4) == 0) { 965 newae(ctx->i_ae, arg); 966 break; 967 } 968 if (strcmp(arg, "-W0,-noglobal") == 0 || 969 strcmp(arg, "-W0,-xglobalstatic") == 0) { 970 /* 971 * gcc doesn't prefix local symbols 972 * in debug mode, so this is not needed. 973 */ 974 break; 975 } 976 if (strcmp(arg, "-W0,-Lt") == 0) { 977 /* 978 * Generate tests at the top of loops. 979 * There is no direct gcc equivalent, ignore. 980 */ 981 break; 982 } 983 if (strcmp(arg, "-W0,-xdbggen=no%usedonly") == 0) { 984 newae(ctx->i_ae, 985 "-fno-eliminate-unused-debug-symbols"); 986 newae(ctx->i_ae, 987 "-fno-eliminate-unused-debug-types"); 988 break; 989 } 990 if (strcmp(arg, "-W2,-xwrap_int") == 0) { 991 /* 992 * Use the legacy behaviour (pre-SS11) 993 * for integer wrapping. 994 * gcc does not need this. 995 */ 996 break; 997 } 998 if (strcmp(arg, "-Wd,-xsafe=unboundsym") == 0) { 999 /* 1000 * Prevents optimizing away checks for 1001 * unbound weak symbol addresses. gcc does 1002 * not do this, so it's not needed. 1003 */ 1004 break; 1005 } 1006 if (strncmp(arg, "-Wc,-xcode=", 11) == 0) { 1007 xlate(ctx->i_ae, arg + 11, xcode_tbl); 1008 break; 1009 } 1010 if (strncmp(arg, "-Wc,-Qiselect", 13) == 0) { 1011 /* 1012 * Prevents insertion of register symbols. 1013 * gcc doesn't do this, so ignore it. 1014 */ 1015 break; 1016 } 1017 if (strcmp(arg, "-Wc,-Qassembler-ounrefsym=0") == 0) { 1018 /* 1019 * Prevents optimizing away of static variables. 1020 * gcc does not do this, so it's not needed. 1021 */ 1022 break; 1023 } 1024 #if defined(__x86) 1025 if (strcmp(arg, "-Wu,-save_args") == 0) { 1026 newae(ctx->i_ae, "-msave-args"); 1027 break; 1028 } 1029 #endif /* __x86 */ 1030 error(arg); 1031 break; 1032 case 'X': 1033 if (strcmp(arg, "-Xa") == 0 || 1034 strcmp(arg, "-Xt") == 0) { 1035 break; 1036 } 1037 if (strcmp(arg, "-Xs") == 0) { 1038 Xsmode(ctx->i_ae); 1039 break; 1040 } 1041 error(arg); 1042 break; 1043 case 'x': 1044 if (arglen == 1) 1045 error(arg); 1046 switch (arg[2]) { 1047 case 'a': 1048 if (strncmp(arg, "-xarch=", 7) == 0) { 1049 mflag |= xlate_xtb(ctx->i_ae, arg + 7); 1050 break; 1051 } 1052 error(arg); 1053 break; 1054 case 'b': 1055 if (strncmp(arg, "-xbuiltin=", 10) == 0) { 1056 if (strcmp(arg + 10, "%all")) 1057 newae(ctx->i_ae, "-fbuiltin"); 1058 break; 1059 } 1060 error(arg); 1061 break; 1062 case 'C': 1063 /* Accept C++ style comments -- ignore */ 1064 if (strcmp(arg, "-xCC") == 0) 1065 break; 1066 error(arg); 1067 break; 1068 case 'c': 1069 if (strncmp(arg, "-xc99=%all", 10) == 0) { 1070 newae(ctx->i_ae, "-std=gnu99"); 1071 break; 1072 } 1073 if (strncmp(arg, "-xc99=%none", 11) == 0) { 1074 newae(ctx->i_ae, "-std=gnu89"); 1075 break; 1076 } 1077 if (strncmp(arg, "-xchip=", 7) == 0) { 1078 xlate(ctx->i_ae, arg + 7, xchip_tbl); 1079 break; 1080 } 1081 if (strncmp(arg, "-xcode=", 7) == 0) { 1082 xlate(ctx->i_ae, arg + 7, xcode_tbl); 1083 break; 1084 } 1085 if (strncmp(arg, "-xcrossfile", 11) == 0) 1086 break; 1087 error(arg); 1088 break; 1089 case 'd': 1090 if (strncmp(arg, "-xdebugformat=", 14) == 0) 1091 break; 1092 error(arg); 1093 break; 1094 case 'F': 1095 /* 1096 * Compile for mapfile reordering, or unused 1097 * section elimination, syntax can be -xF or 1098 * more complex, like -xF=%all -- ignore. 1099 */ 1100 if (strncmp(arg, "-xF", 3) == 0) 1101 break; 1102 error(arg); 1103 break; 1104 case 'i': 1105 if (strncmp(arg, "-xinline", 8) == 0) 1106 /* No inlining; ignore */ 1107 break; 1108 if (strcmp(arg, "-xildon") == 0 || 1109 strcmp(arg, "-xildoff") == 0) 1110 /* No incremental linking; ignore */ 1111 break; 1112 error(arg); 1113 break; 1114 #if defined(__x86) 1115 case 'm': 1116 if (strcmp(arg, "-xmodel=kernel") == 0) { 1117 newae(ctx->i_ae, "-ffreestanding"); 1118 newae(ctx->i_ae, "-mno-red-zone"); 1119 model = "-mcmodel=kernel"; 1120 nolibc = 1; 1121 break; 1122 } 1123 error(arg); 1124 break; 1125 #endif /* __x86 */ 1126 case 'O': 1127 if (strncmp(arg, "-xO", 3) == 0) { 1128 size_t len = strlen(arg); 1129 char *s = NULL; 1130 int c = *(arg + 3); 1131 int level; 1132 1133 if (len != 4 || !isdigit(c)) 1134 error(arg); 1135 1136 level = atoi(arg + 3); 1137 if (level > 5) 1138 error(arg); 1139 if (level >= 2) { 1140 /* 1141 * For gcc-3.4.x at -O2 we 1142 * need to disable optimizations 1143 * that break ON. 1144 */ 1145 optim_disable(ctx->i_ae, level); 1146 /* 1147 * limit -xO3 to -O2 as well. 1148 */ 1149 level = 2; 1150 } 1151 if (asprintf(&s, "-O%d", level) == -1) 1152 nomem(); 1153 newae(ctx->i_ae, s); 1154 free(s); 1155 break; 1156 } 1157 error(arg); 1158 break; 1159 case 'r': 1160 if (strncmp(arg, "-xregs=", 7) == 0) { 1161 xlate(ctx->i_ae, arg + 7, xregs_tbl); 1162 break; 1163 } 1164 error(arg); 1165 break; 1166 case 's': 1167 if (strcmp(arg, "-xs") == 0 || 1168 strcmp(arg, "-xspace") == 0 || 1169 strcmp(arg, "-xstrconst") == 0) 1170 break; 1171 error(arg); 1172 break; 1173 case 't': 1174 if (strncmp(arg, "-xtarget=", 9) == 0) { 1175 xlate(ctx->i_ae, arg + 9, xtarget_tbl); 1176 break; 1177 } 1178 error(arg); 1179 break; 1180 case 'e': 1181 case 'h': 1182 case 'l': 1183 default: 1184 error(arg); 1185 break; 1186 } 1187 break; 1188 case 'Y': 1189 if (arglen == 1) { 1190 if ((arg = *++ctx->i_oldargv) == NULL || 1191 *arg == '\0') 1192 error("-Y"); 1193 ctx->i_oldargc--; 1194 arglen = strlen(arg + 1); 1195 } else { 1196 arg += 2; 1197 } 1198 /* Just ignore -YS,... for now */ 1199 if (strncmp(arg, "S,", 2) == 0) 1200 break; 1201 if (strncmp(arg, "l,", 2) == 0) { 1202 char *s = strdup(arg); 1203 s[0] = '-'; 1204 s[1] = 'B'; 1205 newae(ctx->i_ae, s); 1206 free(s); 1207 break; 1208 } 1209 if (strncmp(arg, "I,", 2) == 0) { 1210 char *s = strdup(arg); 1211 s[0] = '-'; 1212 s[1] = 'I'; 1213 newae(ctx->i_ae, "-nostdinc"); 1214 newae(ctx->i_ae, s); 1215 free(s); 1216 break; 1217 } 1218 error(arg); 1219 break; 1220 case 'Q': 1221 /* 1222 * We could map -Qy into -Wl,-Qy etc. 1223 */ 1224 default: 1225 error(arg); 1226 break; 1227 } 1228 } 1229 1230 free(nameflag); 1231 1232 /* 1233 * When compiling multiple source files in a single invocation some 1234 * compilers output objects into the current directory with 1235 * predictable and conventional names. 1236 * 1237 * We prevent any attempt to compile multiple files at once so that 1238 * any such objects created by a shadow can't escape into a later 1239 * link-edit. 1240 */ 1241 if (c_files > 1 && op != CW_O_PREPROCESS) { 1242 errx(2, "multiple source files are " 1243 "allowed only with -E or -P"); 1244 } 1245 1246 /* 1247 * Make sure that we do not have any unintended interactions between 1248 * the xarch options passed in and the version of the Studio compiler 1249 * used. 1250 */ 1251 if ((mflag & (SS11|SS12)) == (SS11|SS12)) { 1252 errx(2, 1253 "Conflicting \"-xarch=\" flags (both Studio 11 and 12)\n"); 1254 } 1255 1256 switch (mflag) { 1257 case 0: 1258 /* FALLTHROUGH */ 1259 case M32: 1260 #if defined(__sparc) 1261 /* 1262 * Only -m32 is defined and so put in the missing xarch 1263 * translation. 1264 */ 1265 newae(ctx->i_ae, "-mcpu=v8"); 1266 newae(ctx->i_ae, "-mno-v8plus"); 1267 #endif 1268 break; 1269 case M64: 1270 #if defined(__sparc) 1271 /* 1272 * Only -m64 is defined and so put in the missing xarch 1273 * translation. 1274 */ 1275 newae(ctx->i_ae, "-mcpu=v9"); 1276 #endif 1277 break; 1278 case SS12: 1279 #if defined(__sparc) 1280 /* no -m32/-m64 flag used - this is an error for sparc builds */ 1281 (void) fprintf(stderr, "No -m32/-m64 flag defined\n"); 1282 exit(2); 1283 #endif 1284 break; 1285 case SS11: 1286 /* FALLTHROUGH */ 1287 case (SS11|M32): 1288 case (SS11|M64): 1289 break; 1290 case (SS12|M32): 1291 #if defined(__sparc) 1292 /* 1293 * Need to add in further 32 bit options because with SS12 1294 * the xarch=sparcvis option can be applied to 32 or 64 1295 * bit, and so the translatation table (xtbl) cannot handle 1296 * that. 1297 */ 1298 newae(ctx->i_ae, "-mv8plus"); 1299 #endif 1300 break; 1301 case (SS12|M64): 1302 break; 1303 default: 1304 (void) fprintf(stderr, 1305 "Incompatible -xarch= and/or -m32/-m64 options used.\n"); 1306 exit(2); 1307 } 1308 1309 if (ctx->i_flags & CW_F_SHADOW) { 1310 if (op == CW_O_PREPROCESS) 1311 exit(0); 1312 else if (op == CW_O_LINK && c_files == 0) 1313 exit(0); 1314 } 1315 1316 if (model != NULL) 1317 newae(ctx->i_ae, model); 1318 if (!nolibc) 1319 newae(ctx->i_ae, "-lc"); 1320 if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) { 1321 newae(ctx->i_ae, "-o"); 1322 newae(ctx->i_ae, discard_file_name(ctx, NULL)); 1323 } 1324 } 1325 1326 static void 1327 do_smatch(cw_ictx_t *ctx) 1328 { 1329 if (ctx->i_flags & CW_F_PROG) { 1330 newae(ctx->i_ae, "--version"); 1331 return; 1332 } 1333 1334 /* 1335 * Some sources shouldn't run smatch at all. 1336 */ 1337 for (int i = 0; i < ctx->i_oldargc; i++) { 1338 char *arg = ctx->i_oldargv[i]; 1339 1340 if (strcmp(arg, "-_smatch=off") == 0) { 1341 ctx->i_flags &= ~ (CW_F_EXEC | CW_F_ECHO); 1342 return; 1343 } 1344 } 1345 1346 /* 1347 * smatch can handle gcc's options. 1348 */ 1349 do_gcc(ctx); 1350 } 1351 1352 static void 1353 do_cc(cw_ictx_t *ctx) 1354 { 1355 int in_output = 0, seen_o = 0, c_files = 0; 1356 cw_op_t op = CW_O_LINK; 1357 char *nameflag; 1358 1359 if (ctx->i_flags & CW_F_PROG) { 1360 newae(ctx->i_ae, "-V"); 1361 return; 1362 } 1363 1364 if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1) 1365 nomem(); 1366 1367 while (--ctx->i_oldargc > 0) { 1368 char *arg = *++ctx->i_oldargv; 1369 size_t arglen = strlen(arg); 1370 1371 if (strncmp(arg, "-_CC=", 5) == 0) { 1372 newae(ctx->i_ae, strchr(arg, '=') + 1); 1373 continue; 1374 } 1375 1376 if (*arg != '-') { 1377 if (!in_output && arglen > 2 && 1378 arg[arglen - 2] == '.' && 1379 (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' || 1380 arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i')) 1381 c_files++; 1382 1383 if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) { 1384 newae(ctx->i_ae, arg); 1385 } else { 1386 in_output = 0; 1387 newae(ctx->i_ae, discard_file_name(ctx, arg)); 1388 } 1389 continue; 1390 } 1391 switch (*(arg + 1)) { 1392 case '_': 1393 if ((strncmp(arg, nameflag, strlen(nameflag)) == 0) || 1394 (strncmp(arg, "-_cc=", 5) == 0) || 1395 (strncmp(arg, "-_sun=", 6) == 0)) { 1396 newae(ctx->i_ae, strchr(arg, '=') + 1); 1397 } 1398 break; 1399 1400 case 'V': 1401 ctx->i_flags &= ~CW_F_ECHO; 1402 newae(ctx->i_ae, arg); 1403 break; 1404 case 'o': 1405 seen_o = 1; 1406 if (strlen(arg) == 2) { 1407 in_output = 1; 1408 newae(ctx->i_ae, arg); 1409 } else if (ctx->i_flags & CW_F_SHADOW) { 1410 newae(ctx->i_ae, "-o"); 1411 newae(ctx->i_ae, discard_file_name(ctx, arg)); 1412 } else { 1413 newae(ctx->i_ae, arg); 1414 } 1415 break; 1416 case 'c': 1417 case 'S': 1418 if (strlen(arg) == 2) 1419 op = CW_O_COMPILE; 1420 newae(ctx->i_ae, arg); 1421 break; 1422 case 'E': 1423 case 'P': 1424 if (strlen(arg) == 2) 1425 op = CW_O_PREPROCESS; 1426 /*FALLTHROUGH*/ 1427 default: 1428 newae(ctx->i_ae, arg); 1429 } 1430 } 1431 1432 free(nameflag); 1433 1434 /* See the comment on this same code in do_gcc() */ 1435 if (c_files > 1 && op != CW_O_PREPROCESS) { 1436 errx(2, "multiple source files are " 1437 "allowed only with -E or -P"); 1438 } 1439 1440 if (ctx->i_flags & CW_F_SHADOW) { 1441 if (op == CW_O_PREPROCESS) 1442 exit(0); 1443 else if (op == CW_O_LINK && c_files == 0) 1444 exit(0); 1445 } 1446 1447 if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) { 1448 newae(ctx->i_ae, "-o"); 1449 newae(ctx->i_ae, discard_file_name(ctx, NULL)); 1450 } 1451 } 1452 1453 static void 1454 prepctx(cw_ictx_t *ctx) 1455 { 1456 newae(ctx->i_ae, ctx->i_compiler->c_path); 1457 1458 if (ctx->i_flags & CW_F_PROG) { 1459 (void) printf("%s: %s\n", (ctx->i_flags & CW_F_SHADOW) ? 1460 "shadow" : "primary", ctx->i_compiler->c_path); 1461 (void) fflush(stdout); 1462 } 1463 1464 if (!(ctx->i_flags & CW_F_XLATE)) 1465 return; 1466 1467 switch (ctx->i_compiler->c_style) { 1468 case SUN: 1469 do_cc(ctx); 1470 break; 1471 case GNU: 1472 do_gcc(ctx); 1473 break; 1474 case SMATCH: 1475 do_smatch(ctx); 1476 break; 1477 } 1478 } 1479 1480 static int 1481 invoke(cw_ictx_t *ctx) 1482 { 1483 char **newargv; 1484 int ac; 1485 struct ae *a; 1486 1487 if ((newargv = calloc(sizeof (*newargv), ctx->i_ae->ael_argc + 1)) == 1488 NULL) 1489 nomem(); 1490 1491 if (ctx->i_flags & CW_F_ECHO) 1492 (void) fprintf(stderr, "+ "); 1493 1494 for (ac = 0, a = ctx->i_ae->ael_head; a; a = a->ae_next, ac++) { 1495 newargv[ac] = a->ae_arg; 1496 if (ctx->i_flags & CW_F_ECHO) 1497 (void) fprintf(stderr, "%s ", a->ae_arg); 1498 if (a == ctx->i_ae->ael_tail) 1499 break; 1500 } 1501 1502 if (ctx->i_flags & CW_F_ECHO) { 1503 (void) fprintf(stderr, "\n"); 1504 (void) fflush(stderr); 1505 } 1506 1507 if (!(ctx->i_flags & CW_F_EXEC)) 1508 return (0); 1509 1510 /* 1511 * We must fix up the environment here so that the dependency files are 1512 * not trampled by the shadow compiler. Also take care of GCC 1513 * environment variables that will throw off gcc. This assumes a primary 1514 * gcc. 1515 */ 1516 if ((ctx->i_flags & CW_F_SHADOW) && 1517 (unsetenv("SUNPRO_DEPENDENCIES") != 0 || 1518 unsetenv("DEPENDENCIES_OUTPUT") != 0 || 1519 unsetenv("GCC_ROOT") != 0)) { 1520 (void) fprintf(stderr, "error: environment setup failed: %s\n", 1521 strerror(errno)); 1522 return (-1); 1523 } 1524 1525 (void) execv(newargv[0], newargv); 1526 warn("couldn't run %s", newargv[0]); 1527 1528 return (-1); 1529 } 1530 1531 static int 1532 reap(cw_ictx_t *ctx) 1533 { 1534 int status, ret = 0; 1535 char buf[1024]; 1536 struct stat s; 1537 1538 /* 1539 * Only wait for one specific child. 1540 */ 1541 if (ctx->i_pid <= 0) 1542 return (-1); 1543 1544 do { 1545 if (waitpid(ctx->i_pid, &status, 0) < 0) { 1546 warn("cannot reap child"); 1547 return (-1); 1548 } 1549 if (status != 0) { 1550 if (WIFSIGNALED(status)) { 1551 ret = -WTERMSIG(status); 1552 break; 1553 } else if (WIFEXITED(status)) { 1554 ret = WEXITSTATUS(status); 1555 break; 1556 } 1557 } 1558 } while (!WIFEXITED(status) && !WIFSIGNALED(status)); 1559 1560 if (stat(ctx->i_stderr, &s) < 0) { 1561 warn("stat failed on child cleanup"); 1562 return (-1); 1563 } 1564 if (s.st_size != 0) { 1565 FILE *f; 1566 1567 if ((f = fopen(ctx->i_stderr, "r")) != NULL) { 1568 while (fgets(buf, sizeof (buf), f)) 1569 (void) fprintf(stderr, "%s", buf); 1570 (void) fflush(stderr); 1571 (void) fclose(f); 1572 } 1573 } 1574 (void) unlink(ctx->i_stderr); 1575 free(ctx->i_stderr); 1576 1577 /* 1578 * cc returns an error code when given -V; we want that to succeed. 1579 */ 1580 if (ctx->i_flags & CW_F_PROG) 1581 return (0); 1582 1583 return (ret); 1584 } 1585 1586 static int 1587 exec_ctx(cw_ictx_t *ctx, int block) 1588 { 1589 if ((ctx->i_stderr = tempnam(ctx->i_tmpdir, "cw")) == NULL) { 1590 nomem(); 1591 return (-1); 1592 } 1593 1594 if ((ctx->i_pid = fork()) == 0) { 1595 int fd; 1596 1597 (void) fclose(stderr); 1598 if ((fd = open(ctx->i_stderr, O_WRONLY | O_CREAT | O_EXCL, 1599 0666)) < 0) { 1600 err(1, "open failed for standard error"); 1601 } 1602 if (dup2(fd, 2) < 0) { 1603 err(1, "dup2 failed for standard error"); 1604 } 1605 if (fd != 2) 1606 (void) close(fd); 1607 if (freopen("/dev/fd/2", "w", stderr) == NULL) { 1608 err(1, "freopen failed for /dev/fd/2"); 1609 } 1610 1611 prepctx(ctx); 1612 exit(invoke(ctx)); 1613 } 1614 1615 if (ctx->i_pid < 0) { 1616 err(1, "fork failed"); 1617 } 1618 1619 if (block) 1620 return (reap(ctx)); 1621 1622 return (0); 1623 } 1624 1625 static void 1626 parse_compiler(const char *spec, cw_compiler_t *compiler) 1627 { 1628 char *tspec, *token; 1629 1630 if ((tspec = strdup(spec)) == NULL) 1631 nomem(); 1632 1633 if ((token = strsep(&tspec, ",")) == NULL) 1634 errx(1, "Compiler is missing a name: %s", spec); 1635 compiler->c_name = token; 1636 1637 if ((token = strsep(&tspec, ",")) == NULL) 1638 errx(1, "Compiler is missing a path: %s", spec); 1639 compiler->c_path = token; 1640 1641 if ((token = strsep(&tspec, ",")) == NULL) 1642 errx(1, "Compiler is missing a style: %s", spec); 1643 1644 if ((strcasecmp(token, "gnu") == 0) || 1645 (strcasecmp(token, "gcc") == 0)) { 1646 compiler->c_style = GNU; 1647 } else if ((strcasecmp(token, "sun") == 0) || 1648 (strcasecmp(token, "cc") == 0)) { 1649 compiler->c_style = SUN; 1650 } else if ((strcasecmp(token, "smatch") == 0)) { 1651 compiler->c_style = SMATCH; 1652 } else { 1653 errx(1, "unknown compiler style: %s", token); 1654 } 1655 1656 if (tspec != NULL) 1657 errx(1, "Excess tokens in compiler: %s", spec); 1658 } 1659 1660 static void 1661 cleanup(cw_ictx_t *ctx) 1662 { 1663 DIR *dirp; 1664 struct dirent *dp; 1665 char buf[MAXPATHLEN]; 1666 1667 if ((dirp = opendir(ctx->i_tmpdir)) == NULL) { 1668 if (errno != ENOENT) { 1669 err(1, "couldn't open temp directory: %s", 1670 ctx->i_tmpdir); 1671 } else { 1672 return; 1673 } 1674 } 1675 1676 errno = 0; 1677 while ((dp = readdir(dirp)) != NULL) { 1678 (void) snprintf(buf, MAXPATHLEN, "%s/%s", ctx->i_tmpdir, 1679 dp->d_name); 1680 1681 if (strncmp(dp->d_name, ".", strlen(dp->d_name)) == 0 || 1682 strncmp(dp->d_name, "..", strlen(dp->d_name)) == 0) 1683 continue; 1684 1685 if (unlink(buf) == -1) 1686 err(1, "failed to unlink temp file: %s", dp->d_name); 1687 errno = 0; 1688 } 1689 1690 if (errno != 0) { 1691 err(1, "failed to read temporary directory: %s", 1692 ctx->i_tmpdir); 1693 } 1694 1695 (void) closedir(dirp); 1696 if (rmdir(ctx->i_tmpdir) != 0) { 1697 err(1, "failed to unlink temporary directory: %s", 1698 ctx->i_tmpdir); 1699 } 1700 } 1701 1702 int 1703 main(int argc, char **argv) 1704 { 1705 int ch; 1706 cw_compiler_t primary = { NULL, NULL, 0 }; 1707 cw_compiler_t shadows[10]; 1708 int nshadows = 0; 1709 int ret = 0; 1710 boolean_t do_serial = B_FALSE; 1711 boolean_t do_exec = B_FALSE; 1712 boolean_t vflg = B_FALSE; 1713 boolean_t Cflg = B_FALSE; 1714 boolean_t cflg = B_FALSE; 1715 boolean_t nflg = B_FALSE; 1716 char *tmpdir; 1717 1718 cw_ictx_t *main_ctx; 1719 1720 static struct option longopts[] = { 1721 { "compiler", no_argument, NULL, 'c' }, 1722 { "noecho", no_argument, NULL, 'n' }, 1723 { "primary", required_argument, NULL, 'p' }, 1724 { "shadow", required_argument, NULL, 's' }, 1725 { "versions", no_argument, NULL, 'v' }, 1726 { NULL, 0, NULL, 0 }, 1727 }; 1728 1729 1730 if ((main_ctx = newictx()) == NULL) 1731 nomem(); 1732 1733 while ((ch = getopt_long(argc, argv, "C", longopts, NULL)) != -1) { 1734 switch (ch) { 1735 case 'c': 1736 cflg = B_TRUE; 1737 break; 1738 case 'C': 1739 Cflg = B_TRUE; 1740 break; 1741 case 'n': 1742 nflg = B_TRUE; 1743 break; 1744 case 'p': 1745 if (primary.c_path != NULL) { 1746 warnx("Only one primary compiler may " 1747 "be specified"); 1748 usage(); 1749 } 1750 1751 parse_compiler(optarg, &primary); 1752 break; 1753 case 's': 1754 if (nshadows >= 10) 1755 errx(1, "May only use 10 shadows at " 1756 "the moment"); 1757 parse_compiler(optarg, &shadows[nshadows]); 1758 nshadows++; 1759 break; 1760 case 'v': 1761 vflg = B_TRUE; 1762 break; 1763 default: 1764 (void) fprintf(stderr, "Did you forget '--'?\n"); 1765 usage(); 1766 } 1767 } 1768 1769 if (primary.c_path == NULL) { 1770 warnx("A primary compiler must be specified"); 1771 usage(); 1772 } 1773 1774 do_serial = (getenv("CW_SHADOW_SERIAL") == NULL) ? B_FALSE : B_TRUE; 1775 do_exec = (getenv("CW_NO_EXEC") == NULL) ? B_TRUE : B_FALSE; 1776 1777 /* Leave room for argv[0] */ 1778 argc -= (optind - 1); 1779 argv += (optind - 1); 1780 1781 main_ctx->i_oldargc = argc; 1782 main_ctx->i_oldargv = argv; 1783 main_ctx->i_flags = CW_F_XLATE; 1784 if (nflg == 0) 1785 main_ctx->i_flags |= CW_F_ECHO; 1786 if (do_exec) 1787 main_ctx->i_flags |= CW_F_EXEC; 1788 if (Cflg) 1789 main_ctx->i_flags |= CW_F_CXX; 1790 main_ctx->i_compiler = &primary; 1791 1792 if (cflg) { 1793 (void) fputs(primary.c_path, stdout); 1794 } 1795 1796 if (vflg) { 1797 (void) printf("cw version %s\n", CW_VERSION); 1798 (void) fflush(stdout); 1799 main_ctx->i_flags &= ~CW_F_ECHO; 1800 main_ctx->i_flags |= CW_F_PROG | CW_F_EXEC; 1801 do_serial = 1; 1802 } 1803 1804 tmpdir = getenv("TMPDIR"); 1805 if (tmpdir == NULL) 1806 tmpdir = "/tmp"; 1807 1808 if (asprintf(&main_ctx->i_tmpdir, "%s/cw.XXXXXX", tmpdir) == -1) 1809 nomem(); 1810 1811 if ((main_ctx->i_tmpdir = mkdtemp(main_ctx->i_tmpdir)) == NULL) 1812 errx(1, "failed to create temporary directory"); 1813 1814 ret |= exec_ctx(main_ctx, do_serial); 1815 1816 for (int i = 0; i < nshadows; i++) { 1817 int r; 1818 cw_ictx_t *shadow_ctx; 1819 1820 if ((shadow_ctx = newictx()) == NULL) 1821 nomem(); 1822 1823 (void) memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t)); 1824 1825 shadow_ctx->i_flags |= CW_F_SHADOW; 1826 shadow_ctx->i_compiler = &shadows[i]; 1827 1828 r = exec_ctx(shadow_ctx, do_serial); 1829 if (r == 0) { 1830 shadow_ctx->i_next = main_ctx->i_next; 1831 main_ctx->i_next = shadow_ctx; 1832 } 1833 ret |= r; 1834 } 1835 1836 if (!do_serial) { 1837 cw_ictx_t *next = main_ctx; 1838 while (next != NULL) { 1839 cw_ictx_t *toreap = next; 1840 next = next->i_next; 1841 ret |= reap(toreap); 1842 } 1843 } 1844 1845 cleanup(main_ctx); 1846 return (ret); 1847 }