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