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