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