Print this page
Review from Robert, and nits
Review from Yuri


 318 typedef enum cw_op {
 319         CW_O_NONE = 0,
 320         CW_O_PREPROCESS,
 321         CW_O_COMPILE,
 322         CW_O_LINK
 323 } cw_op_t;
 324 
 325 struct aelist {
 326         struct ae {
 327                 struct ae *ae_next;
 328                 char *ae_arg;
 329         } *ael_head, *ael_tail;
 330         int ael_argc;
 331 };
 332 
 333 typedef enum {
 334         GNU,
 335         SUN
 336 } compiler_style_t;
 337 
 338 #define COMPILER_STYLE(comp) (comp->style == SUN ? "cc" : "gcc")
 339 
 340 typedef struct {
 341         char *name;
 342         char *path;
 343         compiler_style_t style;
 344 } cw_compiler_t;
 345 
 346 typedef struct cw_ictx {
 347         cw_compiler_t   *i_compiler;
 348         struct aelist   *i_ae;
 349         uint32_t        i_flags;
 350         int             i_oldargc;
 351         char            **i_oldargv;
 352         pid_t           i_pid;
 353         char            i_discard[MAXPATHLEN];
 354         char            *i_stderr;
 355 } cw_ictx_t;
 356 
 357 /*
 358  * Status values to indicate which Studio compiler and associated
 359  * flags are being used.
 360  */
 361 #define M32             0x01    /* -m32 - only on Studio 12 */
 362 #define M64             0x02    /* -m64 - only on Studio 12 */
 363 #define SS11            0x100   /* Studio 11 */


 437 static const char *xtarget_tbl[] = {
 438 #if defined(__x86)
 439         "pentium_pro",  "-march=pentiumpro", NULL,
 440 #endif  /* __x86 */
 441         NULL,           NULL
 442 };
 443 
 444 static const char *xregs_tbl[] = {
 445 #if defined(__sparc)
 446         "appl",         "-mapp-regs", NULL,
 447         "no%appl",      "-mno-app-regs", NULL,
 448         "float",        "-mfpu", NULL,
 449         "no%float",     "-mno-fpu", NULL,
 450 #endif  /* __sparc */
 451         NULL,           NULL
 452 };
 453 
 454 static void
 455 nomem(void)
 456 {
 457         (void) errx(1, "out of memory");
 458 }
 459 
 460 static void
 461 newae(struct aelist *ael, const char *arg)
 462 {
 463         struct ae *ae;
 464 
 465         if ((ae = calloc(sizeof (*ae), 1)) == NULL)
 466                 nomem();
 467         ae->ae_arg = strdup(arg);
 468         if (ael->ael_tail == NULL)
 469                 ael->ael_head = ae;
 470         else
 471                 ael->ael_tail->ae_next = ae;
 472         ael->ael_tail = ae;
 473         ael->ael_argc++;
 474 }
 475 
 476 static cw_ictx_t *
 477 newictx(void)


 506         /*
 507          * Enable as many warnings as exist, then disable those that we never
 508          * ever want.
 509          */
 510         newae(h, "-Wall");
 511         newae(h, "-Wextra");
 512 }
 513 
 514 static void
 515 optim_disable(struct aelist *h, int level)
 516 {
 517         if (level >= 2) {
 518                 newae(h, "-fno-strict-aliasing");
 519                 newae(h, "-fno-unit-at-a-time");
 520                 newae(h, "-fno-optimize-sibling-calls");
 521         }
 522 }
 523 
 524 /* ARGSUSED */
 525 static void
 526 Xamode(struct aelist *h __attribute__((__unused__)))
 527 {
 528 }
 529 
 530 static void
 531 Xcmode(struct aelist *h)
 532 {
 533         static int xconce;
 534 
 535         if (xconce++)
 536                 return;
 537 
 538         newae(h, "-ansi");
 539         newae(h, "-pedantic-errors");
 540 }
 541 
 542 static void
 543 Xsmode(struct aelist *h)
 544 {
 545         static int xsonce;
 546 


 641         /*
 642          * The SPARC ldd and std instructions require 8-byte alignment of
 643          * their address operand.  gcc correctly uses them only when the
 644          * ABI requires 8-byte alignment; unfortunately we have a number of
 645          * pieces of buggy code that doesn't conform to the ABI.  This
 646          * flag makes gcc work more like Studio with -xmemalign=4.
 647          */
 648         newae(ctx->i_ae, "-mno-integer-ldd-std");
 649 #endif
 650 
 651         /*
 652          * This is needed because 'u' is defined
 653          * under a conditional on 'sun'.  Should
 654          * probably just remove the conditional,
 655          * or make it be dependent on '__sun'.
 656          *
 657          * -Dunix is also missing in enhanced ANSI mode
 658          */
 659         newae(ctx->i_ae, "-D__sun");
 660 
 661         if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->name) == -1)
 662                 nomem();
 663 
 664         /*
 665          * Walk the argument list, translating as we go ..
 666          */
 667         while (--ctx->i_oldargc > 0) {
 668                 char *arg = *++ctx->i_oldargv;
 669                 size_t arglen = strlen(arg);
 670 
 671                 if (*arg == '-') {
 672                         arglen--;
 673                 } else {
 674                         /*
 675                          * Discard inline files that gcc doesn't grok
 676                          */
 677                         if (!in_output && arglen > 3 &&
 678                             strcmp(arg + arglen - 3, ".il") == 0)
 679                                 continue;
 680 
 681                         if (!in_output && arglen > 2 &&


1390                                 newae(ctx->i_ae, s);
1391                                 free(s);
1392                                 break;
1393                         }
1394                         error(arg);
1395                         break;
1396                 case 'Q':
1397                         /*
1398                          * We could map -Qy into -Wl,-Qy etc.
1399                          */
1400                 default:
1401                         error(arg);
1402                         break;
1403                 }
1404         }
1405 
1406         free(nameflag);
1407 
1408         if (c_files > 1 && (ctx->i_flags & CW_F_SHADOW) &&
1409             op != CW_O_PREPROCESS) {
1410                 (void) errx(2, "multiple source files are "
1411                     "allowed only with -E or -P");
1412         }
1413 
1414         /*
1415          * Make sure that we do not have any unintended interactions between
1416          * the xarch options passed in and the version of the Studio compiler
1417          * used.
1418          */
1419         if ((mflag & (SS11|SS12)) == (SS11|SS12)) {
1420                 (void) errx(2,
1421                     "Conflicting \"-xarch=\" flags (both Studio 11 and 12)\n");
1422         }
1423 
1424         switch (mflag) {
1425         case 0:
1426                 /* FALLTHROUGH */
1427         case M32:
1428 #if defined(__sparc)
1429                 /*
1430                  * Only -m32 is defined and so put in the missing xarch
1431                  * translation.
1432                  */
1433                 newae(ctx->i_ae, "-mcpu=v8");
1434                 newae(ctx->i_ae, "-mno-v8plus");
1435 #endif
1436                 break;
1437         case M64:
1438 #if defined(__sparc)
1439                 /*
1440                  * Only -m64 is defined and so put in the missing xarch


1481         if (!nolibc)
1482                 newae(ctx->i_ae, "-lc");
1483         if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
1484                 newae(ctx->i_ae, "-o");
1485                 newae(ctx->i_ae, ctx->i_discard);
1486         }
1487 }
1488 
1489 static void
1490 do_cc(cw_ictx_t *ctx)
1491 {
1492         int in_output = 0, seen_o = 0;
1493         cw_op_t op = CW_O_LINK;
1494         char *nameflag;
1495 
1496         if (ctx->i_flags & CW_F_PROG) {
1497                 newae(ctx->i_ae, "-V");
1498                 return;
1499         }
1500 
1501         if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->name) == -1)
1502                 nomem();
1503 
1504         while (--ctx->i_oldargc > 0) {
1505                 char *arg = *++ctx->i_oldargv;
1506 
1507                 if (strncmp(arg, "-_CC=", 5) == 0) {
1508                         newae(ctx->i_ae, strchr(arg, '=') + 1);
1509                         continue;
1510                 }
1511 
1512                 if (*arg != '-') {
1513                         if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) {
1514                                 newae(ctx->i_ae, arg);
1515                         } else {
1516                                 in_output = 0;
1517                                 newae(ctx->i_ae, ctx->i_discard);
1518                         }
1519                         continue;
1520                 }
1521                 switch (*(arg + 1)) {


1557                 default:
1558                         newae(ctx->i_ae, arg);
1559                 }
1560         }
1561 
1562         free(nameflag);
1563 
1564         if ((op == CW_O_LINK || op == CW_O_PREPROCESS) &&
1565             (ctx->i_flags & CW_F_SHADOW))
1566                 exit(0);
1567 
1568         if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
1569                 newae(ctx->i_ae, "-o");
1570                 newae(ctx->i_ae, ctx->i_discard);
1571         }
1572 }
1573 
1574 static void
1575 prepctx(cw_ictx_t *ctx)
1576 {
1577         newae(ctx->i_ae, ctx->i_compiler->path);
1578 
1579         if (ctx->i_flags & CW_F_PROG) {
1580                 (void) printf("%s: %s\n", (ctx->i_flags & CW_F_SHADOW) ?
1581                     "shadow" : "primary", ctx->i_compiler->path);
1582                 (void) fflush(stdout);
1583         }
1584 
1585         if (!(ctx->i_flags & CW_F_XLATE))
1586                 return;
1587 
1588         switch (ctx->i_compiler->style) {
1589         case SUN:
1590                 do_cc(ctx);
1591                 break;
1592         case GNU:
1593                 do_gcc(ctx);
1594                 break;
1595         }
1596 }
1597 
1598 static int
1599 invoke(cw_ictx_t *ctx)
1600 {
1601         char **newargv;
1602         int ac;
1603         struct ae *a;
1604 
1605         if ((newargv = calloc(sizeof (*newargv), ctx->i_ae->ael_argc + 1)) ==
1606             NULL)
1607                 nomem();
1608 


1741                 prepctx(ctx);
1742                 exit(invoke(ctx));
1743         }
1744 
1745         if (ctx->i_pid < 0) {
1746                 err(1, "fork failed");
1747         }
1748 
1749         if (block)
1750                 return (reap(ctx));
1751 
1752         return (0);
1753 }
1754 
1755 static int
1756 parse_compiler(const char *spec, cw_compiler_t *compiler)
1757 {
1758         char *tspec, *token;
1759 
1760         if ((tspec = strdup(spec)) == NULL)
1761                 err(1, "out of memory");
1762 
1763         if ((token = strsep(&tspec, ",")) == NULL)
1764                 errx(1, "Compiler is missing a name: %s", spec);
1765         compiler->name = token;
1766 
1767         if ((token = strsep(&tspec, ",")) == NULL)
1768                 errx(1, "Compiler is missing a path: %s", spec);
1769         compiler->path = token;
1770 
1771         if ((token = strsep(&tspec, ",")) == NULL)
1772                 errx(1, "Compiler is missing a style: %s", spec);
1773 
1774         if ((strcasecmp(token, "gnu") == 0) ||
1775             (strcasecmp(token, "gcc") == 0))
1776                 compiler->style = GNU;
1777         else if ((strcasecmp(token, "sun") == 0) ||
1778             (strcasecmp(token, "cc") == 0))
1779                 compiler->style = SUN;
1780         else
1781                 errx(1, "unknown compiler style: %s", token);
1782 
1783         if (tspec != NULL)
1784                 errx(1, "Excess tokens in compiler: %s", spec);
1785 
1786         return (0);
1787 }
1788 
1789 int
1790 main(int argc, char **argv)
1791 {
1792         int ch;
1793         cw_compiler_t primary = { NULL, NULL, 0 };
1794         cw_compiler_t shadows[10];
1795         int nshadows = 0;
1796         int ret = 0;
1797         boolean_t do_serial = B_FALSE;
1798         boolean_t do_exec = B_FALSE;
1799         boolean_t vflg = B_FALSE;
1800         boolean_t Cflg = B_FALSE;
1801         boolean_t cflg = B_FALSE;
1802         boolean_t nflg = B_FALSE;
1803 
1804         cw_ictx_t *main_ctx = newictx();
1805 
1806         static struct option longopts[] = {
1807                 { "compiler", no_argument, NULL, 'c' },
1808                 { "noecho", no_argument, NULL ,'n' },
1809                 { "primary", required_argument, NULL, 'p' },
1810                 { "shadow", required_argument, NULL, 's' },
1811                 { "versions", no_argument, NULL, 'v' },
1812                 { NULL, 0, NULL, 0 },
1813         };
1814 





1815         while ((ch = getopt_long(argc, argv, "C", longopts, NULL)) != -1) {
1816                 switch (ch) {
1817                 case 'c':
1818                         cflg = B_TRUE;
1819                         break;
1820                 case 'C':
1821                         Cflg = B_TRUE;
1822                         break;
1823                 case 'n':
1824                         nflg = B_TRUE;
1825                         break;
1826                 case 'p':
1827                         if (primary.path != NULL) {
1828                                 warnx("Only one primary compiler may be specified");

1829                                 usage();
1830                         }
1831 
1832                         if (parse_compiler(optarg, &primary) != 0)
1833                                 errx(1, "Couldn't parse %s as a compiler spec", optarg);

1834                         break;
1835                 case 's':
1836                         if (nshadows >= 10)
1837                                 errx(1, "May only use 10 shadows at the moment");

1838                         if (parse_compiler(optarg, &shadows[nshadows]) != 0)
1839                                 errx(1, "Couldn't parse %s as a compiler spec", optarg);

1840                         nshadows++;
1841                         break;
1842                 case 'v':
1843                         vflg = B_TRUE;
1844                         break;
1845                 default:
1846                         fprintf(stderr, "Did you forget '--'?\n");
1847                         usage();
1848                 }
1849         }
1850 
1851         if (primary.path == NULL) {
1852                 warnx("A primary compiler must be specified");
1853                 usage();
1854         }
1855 
1856         do_serial = (getenv("CW_SHADOW_SERIAL") == NULL) ? B_FALSE : B_TRUE;
1857         do_exec = (getenv("CW_NO_EXEC") == NULL) ? B_TRUE : B_FALSE;
1858 
1859         /* Leave room for argv[0] */
1860         argc -= (optind - 1);
1861         argv += (optind - 1);
1862 
1863         if (main_ctx == NULL)
1864                 nomem();
1865 
1866         main_ctx->i_oldargc = argc;
1867         main_ctx->i_oldargv = argv;
1868         main_ctx->i_flags = CW_F_XLATE;
1869         if (nflg == 0)
1870                 main_ctx->i_flags |= CW_F_ECHO;
1871         if (do_exec)
1872                 main_ctx->i_flags |= CW_F_EXEC;
1873         if (Cflg)
1874                 main_ctx->i_flags |= CW_F_CXX;
1875         main_ctx->i_compiler = &primary;
1876 
1877         if (cflg) {
1878                 fputs(primary.path, stdout);
1879         }
1880 
1881         if (vflg) {
1882                 (void) printf("cw version %s\n", CW_VERSION);
1883                 (void) fflush(stdout);
1884                 main_ctx->i_flags &= ~CW_F_ECHO;
1885                 main_ctx->i_flags |= CW_F_PROG|CW_F_EXEC;
1886                 do_serial = 1;
1887         }
1888 
1889         ret |= exec_ctx(main_ctx, do_serial);
1890 
1891         for (int i = 0; i < nshadows; i++) {
1892                 cw_ictx_t *shadow_ctx = newictx();
1893 
1894                 if (shadow_ctx == NULL)
1895                         nomem();
1896 
1897                 memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t));
1898 
1899                 shadow_ctx->i_flags |= CW_F_SHADOW;
1900                 shadow_ctx->i_compiler = &shadows[i];
1901 
1902                 /* XXX: Would be nice to run these parallel, too */
1903                 ret |= exec_ctx(shadow_ctx, 1);
1904         }
1905 
1906         if (!do_serial)
1907                 ret |= reap(main_ctx);
1908 
1909         return (ret);
1910 }


 318 typedef enum cw_op {
 319         CW_O_NONE = 0,
 320         CW_O_PREPROCESS,
 321         CW_O_COMPILE,
 322         CW_O_LINK
 323 } cw_op_t;
 324 
 325 struct aelist {
 326         struct ae {
 327                 struct ae *ae_next;
 328                 char *ae_arg;
 329         } *ael_head, *ael_tail;
 330         int ael_argc;
 331 };
 332 
 333 typedef enum {
 334         GNU,
 335         SUN
 336 } compiler_style_t;
 337 


 338 typedef struct {
 339         char *c_name;
 340         char *c_path;
 341         compiler_style_t c_style;
 342 } cw_compiler_t;
 343 
 344 typedef struct cw_ictx {
 345         cw_compiler_t   *i_compiler;
 346         struct aelist   *i_ae;
 347         uint32_t        i_flags;
 348         int             i_oldargc;
 349         char            **i_oldargv;
 350         pid_t           i_pid;
 351         char            i_discard[MAXPATHLEN];
 352         char            *i_stderr;
 353 } cw_ictx_t;
 354 
 355 /*
 356  * Status values to indicate which Studio compiler and associated
 357  * flags are being used.
 358  */
 359 #define M32             0x01    /* -m32 - only on Studio 12 */
 360 #define M64             0x02    /* -m64 - only on Studio 12 */
 361 #define SS11            0x100   /* Studio 11 */


 435 static const char *xtarget_tbl[] = {
 436 #if defined(__x86)
 437         "pentium_pro",  "-march=pentiumpro", NULL,
 438 #endif  /* __x86 */
 439         NULL,           NULL
 440 };
 441 
 442 static const char *xregs_tbl[] = {
 443 #if defined(__sparc)
 444         "appl",         "-mapp-regs", NULL,
 445         "no%appl",      "-mno-app-regs", NULL,
 446         "float",        "-mfpu", NULL,
 447         "no%float",     "-mno-fpu", NULL,
 448 #endif  /* __sparc */
 449         NULL,           NULL
 450 };
 451 
 452 static void
 453 nomem(void)
 454 {
 455         errx(1, "out of memory");
 456 }
 457 
 458 static void
 459 newae(struct aelist *ael, const char *arg)
 460 {
 461         struct ae *ae;
 462 
 463         if ((ae = calloc(sizeof (*ae), 1)) == NULL)
 464                 nomem();
 465         ae->ae_arg = strdup(arg);
 466         if (ael->ael_tail == NULL)
 467                 ael->ael_head = ae;
 468         else
 469                 ael->ael_tail->ae_next = ae;
 470         ael->ael_tail = ae;
 471         ael->ael_argc++;
 472 }
 473 
 474 static cw_ictx_t *
 475 newictx(void)


 504         /*
 505          * Enable as many warnings as exist, then disable those that we never
 506          * ever want.
 507          */
 508         newae(h, "-Wall");
 509         newae(h, "-Wextra");
 510 }
 511 
 512 static void
 513 optim_disable(struct aelist *h, int level)
 514 {
 515         if (level >= 2) {
 516                 newae(h, "-fno-strict-aliasing");
 517                 newae(h, "-fno-unit-at-a-time");
 518                 newae(h, "-fno-optimize-sibling-calls");
 519         }
 520 }
 521 
 522 /* ARGSUSED */
 523 static void
 524 Xamode(struct aelist __unused *h)
 525 {
 526 }
 527 
 528 static void
 529 Xcmode(struct aelist *h)
 530 {
 531         static int xconce;
 532 
 533         if (xconce++)
 534                 return;
 535 
 536         newae(h, "-ansi");
 537         newae(h, "-pedantic-errors");
 538 }
 539 
 540 static void
 541 Xsmode(struct aelist *h)
 542 {
 543         static int xsonce;
 544 


 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 && arglen > 2 &&


1388                                 newae(ctx->i_ae, s);
1389                                 free(s);
1390                                 break;
1391                         }
1392                         error(arg);
1393                         break;
1394                 case 'Q':
1395                         /*
1396                          * We could map -Qy into -Wl,-Qy etc.
1397                          */
1398                 default:
1399                         error(arg);
1400                         break;
1401                 }
1402         }
1403 
1404         free(nameflag);
1405 
1406         if (c_files > 1 && (ctx->i_flags & CW_F_SHADOW) &&
1407             op != CW_O_PREPROCESS) {
1408                 errx(2, "multiple source files are "
1409                     "allowed only with -E or -P");
1410         }
1411 
1412         /*
1413          * Make sure that we do not have any unintended interactions between
1414          * the xarch options passed in and the version of the Studio compiler
1415          * used.
1416          */
1417         if ((mflag & (SS11|SS12)) == (SS11|SS12)) {
1418                 errx(2,
1419                     "Conflicting \"-xarch=\" flags (both Studio 11 and 12)\n");
1420         }
1421 
1422         switch (mflag) {
1423         case 0:
1424                 /* FALLTHROUGH */
1425         case M32:
1426 #if defined(__sparc)
1427                 /*
1428                  * Only -m32 is defined and so put in the missing xarch
1429                  * translation.
1430                  */
1431                 newae(ctx->i_ae, "-mcpu=v8");
1432                 newae(ctx->i_ae, "-mno-v8plus");
1433 #endif
1434                 break;
1435         case M64:
1436 #if defined(__sparc)
1437                 /*
1438                  * Only -m64 is defined and so put in the missing xarch


1479         if (!nolibc)
1480                 newae(ctx->i_ae, "-lc");
1481         if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
1482                 newae(ctx->i_ae, "-o");
1483                 newae(ctx->i_ae, ctx->i_discard);
1484         }
1485 }
1486 
1487 static void
1488 do_cc(cw_ictx_t *ctx)
1489 {
1490         int in_output = 0, seen_o = 0;
1491         cw_op_t op = CW_O_LINK;
1492         char *nameflag;
1493 
1494         if (ctx->i_flags & CW_F_PROG) {
1495                 newae(ctx->i_ae, "-V");
1496                 return;
1497         }
1498 
1499         if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1)
1500                 nomem();
1501 
1502         while (--ctx->i_oldargc > 0) {
1503                 char *arg = *++ctx->i_oldargv;
1504 
1505                 if (strncmp(arg, "-_CC=", 5) == 0) {
1506                         newae(ctx->i_ae, strchr(arg, '=') + 1);
1507                         continue;
1508                 }
1509 
1510                 if (*arg != '-') {
1511                         if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) {
1512                                 newae(ctx->i_ae, arg);
1513                         } else {
1514                                 in_output = 0;
1515                                 newae(ctx->i_ae, ctx->i_discard);
1516                         }
1517                         continue;
1518                 }
1519                 switch (*(arg + 1)) {


1555                 default:
1556                         newae(ctx->i_ae, arg);
1557                 }
1558         }
1559 
1560         free(nameflag);
1561 
1562         if ((op == CW_O_LINK || op == CW_O_PREPROCESS) &&
1563             (ctx->i_flags & CW_F_SHADOW))
1564                 exit(0);
1565 
1566         if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
1567                 newae(ctx->i_ae, "-o");
1568                 newae(ctx->i_ae, ctx->i_discard);
1569         }
1570 }
1571 
1572 static void
1573 prepctx(cw_ictx_t *ctx)
1574 {
1575         newae(ctx->i_ae, ctx->i_compiler->c_path);
1576 
1577         if (ctx->i_flags & CW_F_PROG) {
1578                 (void) printf("%s: %s\n", (ctx->i_flags & CW_F_SHADOW) ?
1579                     "shadow" : "primary", ctx->i_compiler->c_path);
1580                 (void) fflush(stdout);
1581         }
1582 
1583         if (!(ctx->i_flags & CW_F_XLATE))
1584                 return;
1585 
1586         switch (ctx->i_compiler->c_style) {
1587         case SUN:
1588                 do_cc(ctx);
1589                 break;
1590         case GNU:
1591                 do_gcc(ctx);
1592                 break;
1593         }
1594 }
1595 
1596 static int
1597 invoke(cw_ictx_t *ctx)
1598 {
1599         char **newargv;
1600         int ac;
1601         struct ae *a;
1602 
1603         if ((newargv = calloc(sizeof (*newargv), ctx->i_ae->ael_argc + 1)) ==
1604             NULL)
1605                 nomem();
1606 


1739                 prepctx(ctx);
1740                 exit(invoke(ctx));
1741         }
1742 
1743         if (ctx->i_pid < 0) {
1744                 err(1, "fork failed");
1745         }
1746 
1747         if (block)
1748                 return (reap(ctx));
1749 
1750         return (0);
1751 }
1752 
1753 static int
1754 parse_compiler(const char *spec, cw_compiler_t *compiler)
1755 {
1756         char *tspec, *token;
1757 
1758         if ((tspec = strdup(spec)) == NULL)
1759                 nomem();
1760 
1761         if ((token = strsep(&tspec, ",")) == NULL)
1762                 errx(1, "Compiler is missing a name: %s", spec);
1763         compiler->c_name = token;
1764 
1765         if ((token = strsep(&tspec, ",")) == NULL)
1766                 errx(1, "Compiler is missing a path: %s", spec);
1767         compiler->c_path = token;
1768 
1769         if ((token = strsep(&tspec, ",")) == NULL)
1770                 errx(1, "Compiler is missing a style: %s", spec);
1771 
1772         if ((strcasecmp(token, "gnu") == 0) ||
1773             (strcasecmp(token, "gcc") == 0))
1774                 compiler->c_style = GNU;
1775         else if ((strcasecmp(token, "sun") == 0) ||
1776             (strcasecmp(token, "cc") == 0))
1777                 compiler->c_style = SUN;
1778         else
1779                 errx(1, "unknown compiler style: %s", token);
1780 
1781         if (tspec != NULL)
1782                 errx(1, "Excess tokens in compiler: %s", spec);
1783 
1784         return (0);
1785 }
1786 
1787 int
1788 main(int argc, char **argv)
1789 {
1790         int ch;
1791         cw_compiler_t primary = { NULL, NULL, 0 };
1792         cw_compiler_t shadows[10];
1793         int nshadows = 0;
1794         int ret = 0;
1795         boolean_t do_serial = B_FALSE;
1796         boolean_t do_exec = B_FALSE;
1797         boolean_t vflg = B_FALSE;
1798         boolean_t Cflg = B_FALSE;
1799         boolean_t cflg = B_FALSE;
1800         boolean_t nflg = B_FALSE;
1801 
1802         cw_ictx_t *main_ctx;
1803 
1804         static struct option longopts[] = {
1805                 { "compiler", no_argument, NULL, 'c' },
1806                 { "noecho", no_argument, NULL, 'n' },
1807                 { "primary", required_argument, NULL, 'p' },
1808                 { "shadow", required_argument, NULL, 's' },
1809                 { "versions", no_argument, NULL, 'v' },
1810                 { NULL, 0, NULL, 0 },
1811         };
1812 
1813 
1814         if ((main_ctx = newictx()) == NULL)
1815                 nomem();
1816 
1817 
1818         while ((ch = getopt_long(argc, argv, "C", longopts, NULL)) != -1) {
1819                 switch (ch) {
1820                 case 'c':
1821                         cflg = B_TRUE;
1822                         break;
1823                 case 'C':
1824                         Cflg = B_TRUE;
1825                         break;
1826                 case 'n':
1827                         nflg = B_TRUE;
1828                         break;
1829                 case 'p':
1830                         if (primary.c_path != NULL) {
1831                                 warnx("Only one primary compiler may "
1832                                     "be specified");
1833                                 usage();
1834                         }
1835 
1836                         if (parse_compiler(optarg, &primary) != 0)
1837                                 errx(1, "Couldn't parse %s as a compiler spec",
1838                                     optarg);
1839                         break;
1840                 case 's':
1841                         if (nshadows >= 10)
1842                                 errx(1, "May only use 10 shadows at "
1843                                     "the moment");
1844                         if (parse_compiler(optarg, &shadows[nshadows]) != 0)
1845                                 errx(1, "Couldn't parse %s as a compiler spec",
1846                                     optarg);
1847                         nshadows++;
1848                         break;
1849                 case 'v':
1850                         vflg = B_TRUE;
1851                         break;
1852                 default:
1853                         (void) fprintf(stderr, "Did you forget '--'?\n");
1854                         usage();
1855                 }
1856         }
1857 
1858         if (primary.c_path == NULL) {
1859                 warnx("A primary compiler must be specified");
1860                 usage();
1861         }
1862 
1863         do_serial = (getenv("CW_SHADOW_SERIAL") == NULL) ? B_FALSE : B_TRUE;
1864         do_exec = (getenv("CW_NO_EXEC") == NULL) ? B_TRUE : B_FALSE;
1865 
1866         /* Leave room for argv[0] */
1867         argc -= (optind - 1);
1868         argv += (optind - 1);
1869 



1870         main_ctx->i_oldargc = argc;
1871         main_ctx->i_oldargv = argv;
1872         main_ctx->i_flags = CW_F_XLATE;
1873         if (nflg == 0)
1874                 main_ctx->i_flags |= CW_F_ECHO;
1875         if (do_exec)
1876                 main_ctx->i_flags |= CW_F_EXEC;
1877         if (Cflg)
1878                 main_ctx->i_flags |= CW_F_CXX;
1879         main_ctx->i_compiler = &primary;
1880 
1881         if (cflg) {
1882                 (void) fputs(primary.c_path, stdout);
1883         }
1884 
1885         if (vflg) {
1886                 (void) printf("cw version %s\n", CW_VERSION);
1887                 (void) fflush(stdout);
1888                 main_ctx->i_flags &= ~CW_F_ECHO;
1889                 main_ctx->i_flags |= CW_F_PROG|CW_F_EXEC;
1890                 do_serial = 1;
1891         }
1892 
1893         ret |= exec_ctx(main_ctx, do_serial);
1894 
1895         for (int i = 0; i < nshadows; i++) {
1896                 cw_ictx_t *shadow_ctx;
1897 
1898                 if ((shadow_ctx = newictx()) == NULL)
1899                         nomem();
1900 
1901                 memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t));
1902 
1903                 shadow_ctx->i_flags |= CW_F_SHADOW;
1904                 shadow_ctx->i_compiler = &shadows[i];
1905 
1906                 /* XXX: Would be nice to run these parallel, too */
1907                 ret |= exec_ctx(shadow_ctx, 1);
1908         }
1909 
1910         if (!do_serial)
1911                 ret |= reap(main_ctx);
1912 
1913         return (ret);
1914 }