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