diff options
| author | wesolows <none@none> | 2006-03-30 16:06:07 -0800 |
|---|---|---|
| committer | wesolows <none@none> | 2006-03-30 16:06:07 -0800 |
| commit | 80ab886d233f514d54c2a6bdeb9fdfd951bd6881 (patch) | |
| tree | 0a7ee03b9e4951aa9aa2baa1d5479ac4bc92f070 /usr/src/tools/cw/cw.c | |
| parent | 52aacb450723e8271d37836e1b5861c2072a3981 (diff) | |
| download | illumos-joyent-80ab886d233f514d54c2a6bdeb9fdfd951bd6881.tar.gz | |
6242262 ON should be buildable with gcc
6268345 fmd is insufficiently careful with alignment
6271070 gcc and cmd/fm don't get along
6272173 cpumem diag module writes to constant memory, crashing fmd
6273907 gcc and cmd/syseventd don't get along
6308057 gcc and sgs/dis don't get along on SPARC
6359863 the C preprocessor is still feeling abused by token pasting
6359868 gcc and cmd/stmsboot still don't get along
6359878 gcc and lib/smartcard don't get along on sparc
6361816 gcc and perl don't get along
6370832 kernel should agree on C99 mode for studio and gcc
6372728 gcc and sata don't get along
6390345 cw inserts garbage when used as a preprocessor
6397680 gcc and smbios are not getting along
6399113 meta_namespace.c uses worrisome construct and is not gcc friendly
6403999 cw is ugly and hairy and needs a man
Diffstat (limited to 'usr/src/tools/cw/cw.c')
| -rw-r--r-- | usr/src/tools/cw/cw.c | 747 |
1 files changed, 526 insertions, 221 deletions
diff --git a/usr/src/tools/cw/cw.c b/usr/src/tools/cw/cw.c index 218d2f9b9b..7cf7bcf15c 100644 --- a/usr/src/tools/cw/cw.c +++ b/usr/src/tools/cw/cw.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -288,19 +288,71 @@ #include <string.h> #include <stdlib.h> #include <ctype.h> +#include <fcntl.h> +#include <errno.h> +#include <stdarg.h> #include <sys/utsname.h> #include <sys/param.h> #include <sys/isa_defs.h> +#include <sys/wait.h> +#include <sys/stat.h> + +#define CW_F_CXX 0x01 +#define CW_F_SHADOW 0x02 +#define CW_F_EXEC 0x04 +#define CW_F_ECHO 0x08 +#define CW_F_XLATE 0x10 + +typedef enum cw_compiler { + CW_C_CC = 0, + CW_C_GCC +} cw_compiler_t; + +static const char *cmds[] = { + "cc", "CC", + "gcc", "g++" +}; -static int echo = 1; -static int newargc; -static const char *progname; +static const char *dirs[] = { + DEFAULT_CC_DIR, DEFAULT_CPLUSPLUS_DIR, + DEFAULT_GCC_DIR, DEFAULT_GPLUSPLUS_DIR +}; -static char *default_cc_dir; -static char *default_gcc_dir; +#define CC(ctx) \ + (((ctx)->i_flags & CW_F_SHADOW) ? \ + ((ctx)->i_compiler == CW_C_CC ? CW_C_GCC : CW_C_CC) : \ + (ctx)->i_compiler) -static char *default_cplusplus_dir; -static char *default_gplusplus_dir; +#define CIDX(compiler, flags) \ + ((int)(compiler) << 1) + ((flags) & CW_F_CXX ? 1 : 0) + +typedef enum cw_op { + CW_O_NONE = 0, + CW_O_PREPROCESS, + CW_O_COMPILE, + CW_O_LINK +} cw_op_t; + +struct aelist { + struct ae { + struct ae *ae_next; + char *ae_arg; + } *ael_head, *ael_tail; + int ael_argc; +}; + +typedef struct cw_ictx { + cw_compiler_t i_compiler; + struct aelist *i_ae; + uint32_t i_flags; + int i_oldargc; + char **i_oldargv; + pid_t i_pid; + int i_fd[2]; + char i_discard[MAXPATHLEN]; +} cw_ictx_t; + +static const char *progname; static const char *xarch_tbl[] = { #if defined(__x86) @@ -365,17 +417,26 @@ static const char *xregs_tbl[] = { NULL, NULL }; -struct aelist { - struct ae { - struct ae *ae_next; - char *ae_arg; - } *ael_head, *ael_tail; -}; +static void +nomem(void) +{ + (void) fprintf(stderr, "%s: error: out of memory\n", progname); + exit(1); +} -static struct aelist * -newael(void) +static void +cw_perror(const char *fmt, ...) { - return (calloc(sizeof (struct aelist), 1)); + va_list ap; + int saved_errno = errno; + + (void) fprintf(stderr, "%s: error: ", progname); + + va_start(ap, fmt); + (void) vfprintf(stderr, fmt, ap); + va_end(ap); + + (void) fprintf(stderr, " (%s)\n", strerror(saved_errno)); } static void @@ -383,21 +444,35 @@ newae(struct aelist *ael, const char *arg) { struct ae *ae; - ae = calloc(sizeof (*ae), 1); + if ((ae = calloc(sizeof (*ae), 1)) == NULL) + nomem(); ae->ae_arg = strdup(arg); if (ael->ael_tail == NULL) ael->ael_head = ae; else ael->ael_tail->ae_next = ae; ael->ael_tail = ae; - newargc++; + ael->ael_argc++; +} + +static cw_ictx_t * +newictx(void) +{ + cw_ictx_t *ctx = calloc(sizeof (cw_ictx_t), 1); + if (ctx) + if ((ctx->i_ae = calloc(sizeof (struct aelist), 1)) == NULL) { + free(ctx); + return (NULL); + } + + return (ctx); } static void error(const char *arg) { (void) fprintf(stderr, - "%s: mapping failed at or near arg '%s'\n", progname, arg); + "%s: error: mapping failed at or near arg '%s'\n", progname, arg); exit(2); } @@ -495,30 +570,20 @@ xlate(struct aelist *h, const char *xarg, const char **table) } static void -do_gcc(const char *dir, const char *cmd, int argc, char **argv, - struct aelist *h, int cplusplus) +do_gcc(cw_ictx_t *ctx) { int c; - int pic = 0; - int nolibc = 0; + int pic = 0, nolibc = 0; + int in_output = 0, seen_o = 0, c_files = 0; + cw_op_t op = CW_O_LINK; char *model = NULL; - char *program; - size_t len = strlen(dir) + strlen(cmd) + 2; - - program = malloc(len); - (void) snprintf(program, len, "%s/%s", dir, cmd); - - /* - * Basic defaults for ON compilation - */ - newae(h, program); - newae(h, "-fident"); - newae(h, "-finline"); - newae(h, "-fno-inline-functions"); - newae(h, "-fno-builtin"); - newae(h, "-fno-asm"); - newae(h, "-nodefaultlibs"); + newae(ctx->i_ae, "-fident"); + newae(ctx->i_ae, "-finline"); + newae(ctx->i_ae, "-fno-inline-functions"); + newae(ctx->i_ae, "-fno-builtin"); + newae(ctx->i_ae, "-fno-asm"); + newae(ctx->i_ae, "-nodefaultlibs"); #if defined(__sparc) /* @@ -528,7 +593,7 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, * pieces of buggy code that doesn't conform to the ABI. This * flag makes gcc work more like Studio with -xmemalign=4. */ - newae(h, "-mno-integer-ldd-std"); + newae(ctx->i_ae, "-mno-integer-ldd-std"); #endif /* @@ -539,66 +604,78 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, * * -Dunix is also missing in enhanced ANSI mode */ - newae(h, "-D__sun"); + newae(ctx->i_ae, "-D__sun"); /* * Walk the argument list, translating as we go .. */ - while (--argc > 0) { - char *arg = *++argv; + while (--ctx->i_oldargc > 0) { + char *arg = *++ctx->i_oldargv; size_t arglen = strlen(arg); - if (*arg == '-') + if (*arg == '-') { arglen--; - else { + } else { /* * Discard inline files that gcc doesn't grok */ - if (arglen > 3 && + if (!in_output && arglen > 3 && strcmp(arg + arglen - 3, ".il") == 0) continue; + if (!in_output && arglen > 2 && + arg[arglen - 2] == '.' && + (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' || + arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i')) + c_files++; + /* - * Otherwise, filenames, and partial arguments - * are simply passed through for gcc to chew on. + * Otherwise, filenames and partial arguments + * are passed through for gcc to chew on. However, + * output is always discarded for the secondary + * compiler. */ - newae(h, arg); + if ((ctx->i_flags & CW_F_SHADOW) && in_output) + newae(ctx->i_ae, ctx->i_discard); + else + newae(ctx->i_ae, arg); + in_output = 0; continue; } - if (cplusplus) { + if (ctx->i_flags & CW_F_CXX) { if (strncmp(arg, "-compat=", 8) == 0) { /* discard -compat=4 and -compat=5 */ continue; } if (strcmp(arg, "-Qoption") == 0) { /* discard -Qoption and its two arguments */ - if (argc < 3) + if (ctx->i_oldargc < 3) error(arg); - argc -= 2; - argv += 2; + ctx->i_oldargc -= 2; + ctx->i_oldargv += 2; continue; } if (strcmp(arg, "-xwe") == 0) { /* turn warnings into errors */ - /* newae(h, "-Werror"); */ + newae(ctx->i_ae, "-Werror"); continue; } if (strcmp(arg, "-noex") == 0) { /* no exceptions */ - newae(h, "-fno-exceptions"); + newae(ctx->i_ae, "-fno-exceptions"); /* no run time type descriptor information */ - newae(h, "-fno-rtti"); + newae(ctx->i_ae, "-fno-rtti"); continue; } if (strcmp(arg, "-pic") == 0) { - newae(h, "-fpic"); + newae(ctx->i_ae, "-fpic"); pic = 1; continue; } if (strcmp(arg, "-PIC") == 0) { - newae(h, "-fPIC"); + newae(ctx->i_ae, "-fPIC"); pic = 1; continue; } @@ -613,8 +690,8 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, } #if defined(__sparc) if (strcmp(arg, "-cg92") == 0) { - xlate(h, "v8", xarch_tbl); - xlate(h, "super", xchip_tbl); + xlate(ctx->i_ae, "v8", xarch_tbl); + xlate(ctx->i_ae, "super", xchip_tbl); continue; } #endif /* __sparc */ @@ -623,33 +700,31 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, switch ((c = arg[1])) { case '_': if (strcmp(arg, "-_noecho") == 0) - echo = 0; + ctx->i_flags &= ~CW_F_ECHO; else if (strncmp(arg, "-_cc=", 5) == 0 || strncmp(arg, "-_CC=", 5) == 0) /* EMPTY */; else if (strncmp(arg, "-_gcc=", 6) == 0 || strncmp(arg, "-_g++=", 6) == 0) - newae(h, arg + 6); - else if (strcmp(arg, "-_compiler") == 0) { - (void) printf("%s\n", program); - exit(0); - } else + newae(ctx->i_ae, arg + 6); + else error(arg); break; case '#': if (arglen == 1) { - newae(h, "-v"); + newae(ctx->i_ae, "-v"); break; } error(arg); break; case 'g': - newae(h, "-gdwarf-2"); + newae(ctx->i_ae, "-gdwarf-2"); break; case 'E': if (arglen == 1) { - newae(h, "-xc"); - newae(h, arg); + newae(ctx->i_ae, "-xc"); + newae(ctx->i_ae, arg); + op = CW_O_PREPROCESS; nolibc = 1; break; } @@ -657,14 +732,16 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, break; case 'c': case 'S': - if (arglen == 1) + if (arglen == 1) { + op = CW_O_COMPILE; nolibc = 1; + } /* FALLTHROUGH */ case 'C': case 'H': case 'p': if (arglen == 1) { - newae(h, arg); + newae(ctx->i_ae, arg); break; } error(arg); @@ -675,30 +752,41 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, case 'i': case 'L': case 'l': - case 'o': case 'R': case 'U': case 'u': case 'w': - newae(h, arg); + newae(ctx->i_ae, arg); + break; + case 'o': + seen_o = 1; + if (arglen == 1) { + in_output = 1; + newae(ctx->i_ae, arg); + } else if (ctx->i_flags & CW_F_SHADOW) { + newae(ctx->i_ae, "-o"); + newae(ctx->i_ae, ctx->i_discard); + } else { + newae(ctx->i_ae, arg); + } break; case 'D': - newae(h, arg); + newae(ctx->i_ae, arg); /* * XXX Clearly a hack ... do we need _KADB too? */ if (strcmp(arg, "-D_KERNEL") == 0 || strcmp(arg, "-D_BOOT") == 0) - newae(h, "-ffreestanding"); + newae(ctx->i_ae, "-ffreestanding"); break; case 'd': if (arglen == 2) { if (strcmp(arg, "-dy") == 0) { - newae(h, "-Wl,-dy"); + newae(ctx->i_ae, "-Wl,-dy"); break; } if (strcmp(arg, "-dn") == 0) { - newae(h, "-Wl,-dn"); + newae(ctx->i_ae, "-Wl,-dn"); break; } } @@ -725,48 +813,49 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, if (strncmp(arg, "-erroff=", 8) == 0) break; if (strcmp(arg, "-errtags=yes") == 0) { - warnings(h); + warnings(ctx->i_ae); break; } if (strcmp(arg, "-errwarn=%all") == 0) { - newae(h, "-Werror"); + newae(ctx->i_ae, "-Werror"); break; } error(arg); break; case 'f': if (strcmp(arg, "-flags") == 0) { - newae(h, "--help"); + newae(ctx->i_ae, "--help"); break; } error(arg); break; case 'G': - newae(h, "-shared"); + newae(ctx->i_ae, "-shared"); nolibc = 1; break; case 'k': if (strcmp(arg, "-keeptmp") == 0) { - newae(h, "-save-temps"); + newae(ctx->i_ae, "-save-temps"); break; } error(arg); break; case 'K': if (arglen == 1) { - if ((arg = *++argv) == NULL || *arg == '\0') + if ((arg = *++ctx->i_oldargv) == NULL || + *arg == '\0') error("-K"); - argc--; + ctx->i_oldargc--; } else { arg += 2; } if (strcmp(arg, "pic") == 0) { - newae(h, "-fpic"); + newae(ctx->i_ae, "-fpic"); pic = 1; break; } if (strcmp(arg, "PIC") == 0) { - newae(h, "-fPIC"); + newae(ctx->i_ae, "-fPIC"); pic = 1; break; } @@ -774,7 +863,7 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, break; case 'm': if (strcmp(arg, "-mt") == 0) { - newae(h, "-D_REENTRANT"); + newae(ctx->i_ae, "-D_REENTRANT"); break; } error(arg); @@ -788,17 +877,18 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, char *s; if (arglen == 1) { - opt = *++argv; + opt = *++ctx->i_oldargv; if (opt == NULL || *opt == '\0') error(arg); - argc--; + ctx->i_oldargc--; } else { opt = arg + 2; } len = strlen(opt) + 7; - s = malloc(len); + if ((s = malloc(len)) == NULL) + nomem(); (void) snprintf(s, len, "-Wl,-%c%s", c, opt); - newae(h, s); + newae(ctx->i_ae, s); free(s); } break; @@ -813,7 +903,7 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, break; case 'O': if (arglen == 1) { - newae(h, "-O"); + newae(ctx->i_ae, "-O"); break; } error(arg); @@ -826,41 +916,42 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, * -o in the Makefile. If they don't they'll find out * in a hurry. */ - newae(h, "-E"); + newae(ctx->i_ae, "-E"); + op = CW_O_PREPROCESS; nolibc = 1; break; case 'q': if (strcmp(arg, "-qp") == 0) { - newae(h, "-p"); + newae(ctx->i_ae, "-p"); break; } error(arg); break; case 's': if (arglen == 1) { - newae(h, "-Wl,-s"); + newae(ctx->i_ae, "-Wl,-s"); break; } error(arg); break; case 't': if (arglen == 1) { - newae(h, "-Wl,-t"); + newae(ctx->i_ae, "-Wl,-t"); break; } error(arg); break; case 'V': if (arglen == 1) { - echo = 0; - newae(h, "--version"); + ctx->i_flags &= ~CW_F_ECHO; + newae(ctx->i_ae, "--version"); break; } error(arg); break; case 'v': if (arglen == 1) { - warnings(h); + warnings(ctx->i_ae); break; } error(arg); @@ -876,7 +967,7 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, if (strncmp(arg, "-Wa,", 4) == 0 || strncmp(arg, "-Wp,", 4) == 0 || strncmp(arg, "-Wl,", 4) == 0) { - newae(h, arg); + newae(ctx->i_ae, arg); break; } if (strcmp(arg, "-W0,-xc99=pragma") == 0) { @@ -906,8 +997,10 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, break; } if (strcmp(arg, "-W0,-xdbggen=no%usedonly") == 0) { - newae(h, "-fno-eliminate-unused-debug-symbols"); - newae(h, "-fno-eliminate-unused-debug-types"); + newae(ctx->i_ae, + "-fno-eliminate-unused-debug-symbols"); + newae(ctx->i_ae, + "-fno-eliminate-unused-debug-types"); break; } if (strcmp(arg, "-W2,-Rcond_elim") == 0) { @@ -926,7 +1019,7 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, break; } if (strncmp(arg, "-Wc,-xcode=", 11) == 0) { - xlate(h, arg + 11, xcode_tbl); + xlate(ctx->i_ae, arg + 11, xcode_tbl); if (strncmp(arg + 11, "pic", 3) == 0) pic = 1; break; @@ -940,19 +1033,19 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, } #if defined(__x86) if (strcmp(arg, "-Wu,-no_got_reloc") == 0) { - newae(h, "-fno-jump-tables"); - newae(h, "-fno-constant-pools"); + newae(ctx->i_ae, "-fno-jump-tables"); + newae(ctx->i_ae, "-fno-constant-pools"); break; } if (strcmp(arg, "-Wu,-xmodel=kernel") == 0) { - newae(h, "-ffreestanding"); - newae(h, "-mno-red-zone"); + newae(ctx->i_ae, "-ffreestanding"); + newae(ctx->i_ae, "-mno-red-zone"); model = "-mcmodel=kernel"; nolibc = 1; break; } if (strcmp(arg, "-Wu,-save_args") == 0) { - newae(h, "-msave-args"); + newae(ctx->i_ae, "-msave-args"); break; } #endif /* __x86 */ @@ -961,15 +1054,15 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, case 'X': if (strcmp(arg, "-Xa") == 0 || strcmp(arg, "-Xt") == 0) { - Xamode(h); + Xamode(ctx->i_ae); break; } if (strcmp(arg, "-Xc") == 0) { - Xcmode(h); + Xcmode(ctx->i_ae); break; } if (strcmp(arg, "-Xs") == 0) { - Xsmode(h); + Xsmode(ctx->i_ae); break; } error(arg); @@ -981,14 +1074,14 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, #if defined(__x86) case '3': if (strcmp(arg, "-x386") == 0) { - newae(h, "-march=i386"); + newae(ctx->i_ae, "-march=i386"); break; } error(arg); break; case '4': if (strcmp(arg, "-x486") == 0) { - newae(h, "-march=i486"); + newae(ctx->i_ae, "-march=i486"); break; } error(arg); @@ -996,7 +1089,7 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, #endif /* __x86 */ case 'a': if (strncmp(arg, "-xarch=", 7) == 0) { - xlate(h, arg + 7, xarch_tbl); + xlate(ctx->i_ae, arg + 7, xarch_tbl); break; } error(arg); @@ -1004,7 +1097,7 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, case 'b': if (strncmp(arg, "-xbuiltin=", 10) == 0) { if (strcmp(arg + 10, "%all")) - newae(h, "-fbuiltin"); + newae(ctx->i_ae, "-fbuiltin"); break; } error(arg); @@ -1017,19 +1110,19 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, break; case 'c': if (strncmp(arg, "-xc99=%all", 10) == 0) { - newae(h, "-std=gnu99"); + newae(ctx->i_ae, "-std=gnu99"); break; } if (strncmp(arg, "-xc99=%none", 11) == 0) { - newae(h, "-std=gnu89"); + newae(ctx->i_ae, "-std=gnu89"); break; } if (strncmp(arg, "-xchip=", 7) == 0) { - xlate(h, arg + 7, xchip_tbl); + xlate(ctx->i_ae, arg + 7, xchip_tbl); break; } if (strncmp(arg, "-xcode=", 7) == 0) { - xlate(h, arg + 7, xcode_tbl); + xlate(ctx->i_ae, arg + 7, xcode_tbl); if (strncmp(arg + 7, "pic", 3) == 0) pic = 1; break; @@ -1065,11 +1158,11 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, break; case 'M': if (strcmp(arg, "-xM") == 0) { - newae(h, "-M"); + newae(ctx->i_ae, "-M"); break; } if (strcmp(arg, "-xM1") == 0) { - newae(h, "-MM"); + newae(ctx->i_ae, "-MM"); break; } error(arg); @@ -1084,13 +1177,16 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, case 'O': if (strncmp(arg, "-xO", 3) == 0) { size_t len = strlen(arg); - char *s = malloc(len); + char *s; int c = *(arg + 3); int level; if (len != 4 || !isdigit(c)) error(arg); + if ((s = malloc(len)) == NULL) + nomem(); + level = atoi(arg + 3); if (level > 5) error(arg); @@ -1100,14 +1196,14 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, * need to disable optimizations * that break ON. */ - optim_disable(h, level); + optim_disable(ctx->i_ae, level); /* * limit -xO3 to -O2 as well. */ level = 2; } (void) snprintf(s, len, "-O%d", level); - newae(h, s); + newae(ctx->i_ae, s); free(s); break; } @@ -1115,18 +1211,18 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, break; case 'p': if (strcmp(arg, "-xpentium") == 0) { - newae(h, "-march=pentium"); + newae(ctx->i_ae, "-march=pentium"); break; } if (strcmp(arg, "-xpg") == 0) { - newae(h, "-pg"); + newae(ctx->i_ae, "-pg"); break; } error(arg); break; case 'r': if (strncmp(arg, "-xregs=", 7) == 0) { - xlate(h, arg + 7, xregs_tbl); + xlate(ctx->i_ae, arg + 7, xregs_tbl); break; } error(arg); @@ -1140,19 +1236,19 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, break; case 't': if (strcmp(arg, "-xtransition") == 0) { - newae(h, "-Wtransition"); + newae(ctx->i_ae, "-Wtransition"); break; } if (strcmp(arg, "-xtrigraphs=yes") == 0) { - newae(h, "-trigraphs"); + newae(ctx->i_ae, "-trigraphs"); break; } if (strcmp(arg, "-xtrigraphs=no") == 0) { - newae(h, "-notrigraphs"); + newae(ctx->i_ae, "-notrigraphs"); break; } if (strncmp(arg, "-xtarget=", 9) == 0) { - xlate(h, arg + 9, xtarget_tbl); + xlate(ctx->i_ae, arg + 9, xtarget_tbl); break; } error(arg); @@ -1167,9 +1263,10 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, break; case 'Y': if (arglen == 1) { - if ((arg = *++argv) == NULL || *arg == '\0') + if ((arg = *++ctx->i_oldargv) == NULL || + *arg == '\0') error("-Y"); - argc--; + ctx->i_oldargc--; arglen = strlen(arg + 1); } else { arg += 2; @@ -1181,7 +1278,7 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, char *s = strdup(arg); s[0] = '-'; s[1] = 'B'; - newae(h, s); + newae(ctx->i_ae, s); free(s); break; } @@ -1189,8 +1286,8 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, char *s = strdup(arg); s[0] = '-'; s[1] = 'I'; - newae(h, "-nostdinc"); - newae(h, s); + newae(ctx->i_ae, "-nostdinc"); + newae(ctx->i_ae, s); free(s); break; } @@ -1206,74 +1303,283 @@ do_gcc(const char *dir, const char *cmd, int argc, char **argv, } } + if (c_files > 1 && (ctx->i_flags & CW_F_SHADOW) && + op != CW_O_PREPROCESS) { + (void) fprintf(stderr, "%s: error: multiple source files are " + "allowed only with -E or -P\n", progname); + exit(2); + } + if (op == CW_O_LINK && (ctx->i_flags & CW_F_SHADOW)) + exit(0); + if (model && !pic) - newae(h, model); + newae(ctx->i_ae, model); if (!nolibc) - newae(h, "-lc"); + newae(ctx->i_ae, "-lc"); + if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) { + newae(ctx->i_ae, "-o"); + newae(ctx->i_ae, ctx->i_discard); + } +} + +static void +do_cc(cw_ictx_t *ctx) +{ + int in_output = 0, seen_o = 0; + cw_op_t op = CW_O_LINK; + + while (--ctx->i_oldargc > 0) { + char *arg = *++ctx->i_oldargv; + + if (*arg != '-') { + if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) { + newae(ctx->i_ae, arg); + } else { + in_output = 0; + newae(ctx->i_ae, ctx->i_discard); + } + continue; + } + switch (*(arg + 1)) { + case '_': + if (strcmp(arg, "-_noecho") == 0) { + ctx->i_flags &= ~CW_F_ECHO; + } else if (strncmp(arg, "-_cc=", 5) == 0 || + strncmp(arg, "-_CC=", 5) == 0) { + newae(ctx->i_ae, arg + 5); + } else if (strncmp(arg, "-_gcc=", 6) != 0 && + strncmp(arg, "-_g++=", 6) != 0) { + (void) fprintf(stderr, + "%s: invalid argument '%s'\n", progname, + arg); + exit(2); + } + break; + case 'V': + ctx->i_flags &= ~CW_F_ECHO; + newae(ctx->i_ae, arg); + break; + case 'o': + seen_o = 1; + if (strlen(arg) == 2) { + in_output = 1; + newae(ctx->i_ae, arg); + } else if (ctx->i_flags & CW_F_SHADOW) { + newae(ctx->i_ae, "-o"); + newae(ctx->i_ae, ctx->i_discard); + } else { + newae(ctx->i_ae, arg); + } + break; + case 'c': + case 'S': + op = CW_O_COMPILE; + newae(ctx->i_ae, arg); + break; + case 'E': + case 'P': + op = CW_O_PREPROCESS; + /*FALLTHROUGH*/ + default: + newae(ctx->i_ae, arg); + } + } + + if ((op == CW_O_LINK || op == CW_O_PREPROCESS) && + (ctx->i_flags & CW_F_SHADOW)) + exit(0); + + if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) { + newae(ctx->i_ae, "-o"); + newae(ctx->i_ae, ctx->i_discard); + } } -/* ARGSUSED4 */ static void -do_cc(const char *dir, const char *cmd, int argc, char **argv, - struct aelist *h, int cplusplus) +prepctx(cw_ictx_t *ctx) { + const char *dir, *cmd; char *program; - size_t len = strlen(dir) + strlen(cmd) + 2; + size_t len; - program = malloc(len); + dir = dirs[CIDX(CC(ctx), ctx->i_flags)]; + cmd = cmds[CIDX(CC(ctx), ctx->i_flags)]; + len = strlen(dir) + strlen(cmd) + 2; + if ((program = malloc(len)) == NULL) + nomem(); (void) snprintf(program, len, "%s/%s", dir, cmd); + newae(ctx->i_ae, program); + + if (!(ctx->i_flags & CW_F_XLATE)) + return; + + switch (CC(ctx)) { + case CW_C_CC: + do_cc(ctx); + break; + case CW_C_GCC: + do_gcc(ctx); + break; + } +} + +static int +invoke(cw_ictx_t *ctx) +{ + char **newargv; + int ac; + struct ae *a; + + if ((newargv = calloc(sizeof (*newargv), ctx->i_ae->ael_argc + 1)) == + NULL) + nomem(); + + if (ctx->i_flags & CW_F_ECHO) + (void) fprintf(stderr, "+ "); + + for (ac = 0, a = ctx->i_ae->ael_head; a; a = a->ae_next, ac++) { + newargv[ac] = a->ae_arg; + if (ctx->i_flags & CW_F_ECHO) + (void) fprintf(stderr, "%s ", a->ae_arg); + if (a == ctx->i_ae->ael_tail) + break; + } + + if (ctx->i_flags & CW_F_ECHO) { + (void) fprintf(stderr, "\n"); + (void) fflush(stderr); + } + + if (!(ctx->i_flags & CW_F_EXEC)) + return (0); + /* - * This is pretty simple. - * We just have to recognize -V, -_noecho, -_compiler, -_cc= and -_gcc= + * We must fix up the environment here so that the + * dependency files are not trampled by the shadow compiler. */ - newae(h, program); + if ((ctx->i_flags & CW_F_SHADOW) && + (unsetenv("SUNPRO_DEPENDENCIES") != 0 || + unsetenv("DEPENDENCIES_OUTPUT") != 0)) { + (void) fprintf(stderr, "error: environment setup failed: %s\n", + strerror(errno)); + return (-1); + } - while (--argc > 0) { - char *arg = *++argv; + (void) execv(newargv[0], newargv); + cw_perror("couldn't run %s", newargv[0]); - if (*arg != '-') { - newae(h, arg); - } else if (*(arg + 1) != '_') { - if (strcmp(arg, "-V") == 0) - echo = 0; - newae(h, arg); - } else if (strcmp(arg, "-_noecho") == 0) { - echo = 0; - } else if (strcmp(arg, "-_compiler") == 0) { - (void) printf("%s\n", program); - exit(0); - } else if (strncmp(arg, "-_cc=", 5) == 0 || - strncmp(arg, "-_CC=", 5) == 0) { - newae(h, arg + 5); - } else if (strncmp(arg, "-_gcc=", 6) != 0 && - strncmp(arg, "-_g++=", 6) != 0) { - (void) fprintf(stderr, - "%s: invalid argument '%s'\n", progname, arg); - exit(2); + return (-1); +} + +static int +reap(cw_ictx_t *ctx) +{ + int stat, ret = 0; + char buf[1024]; + struct stat s; + + do { + (void) waitpid(ctx->i_pid, &stat, 0); + if (stat != 0) { + if (WIFSIGNALED(stat)) { + ret = -WTERMSIG(stat); + break; + } else if (WIFEXITED(stat)) { + ret = WEXITSTATUS(stat); + break; + } } + } while (!WIFEXITED(stat) && !WIFSIGNALED(stat)); + + (void) unlink(ctx->i_discard); + + if (fstat(ctx->i_fd[0], &s) < 0) { + cw_perror("stat failed on child cleanup"); + return (-1); } + if (s.st_size != 0) { + FILE *f = fdopen(ctx->i_fd[0], "r"); + + while (fgets(buf, sizeof (buf), f)) + (void) fprintf(stderr, "%s", buf); + (void) fflush(stderr); + (void) fclose(f); + } + (void) close(ctx->i_fd[0]); + + return (ret); +} + +static int +exec_ctx(cw_ictx_t *ctx, int block) +{ + char *file; + + /* + * To avoid offending cc's sensibilities, the name of its output + * file must end in '.o'. + */ + if ((file = tempnam(NULL, ".cw")) == NULL) { + nomem(); + return (-1); + } + (void) strlcpy(ctx->i_discard, file, MAXPATHLEN); + (void) strlcat(ctx->i_discard, ".o", MAXPATHLEN); + free(file); + + if (pipe(ctx->i_fd) < 0) { + cw_perror("pipe creation failed"); + return (-1); + } + + if ((ctx->i_pid = fork()) == 0) { + (void) close(ctx->i_fd[0]); + (void) fclose(stderr); + if (dup2(ctx->i_fd[1], 2) < 0) { + cw_perror("dup2 failed for standard error"); + exit(1); + } + (void) close(ctx->i_fd[1]); + if (freopen("/dev/fd/2", "w", stderr) == NULL) { + cw_perror("freopen failed for /dev/fd/2"); + exit(1); + } + prepctx(ctx); + exit(invoke(ctx)); + } + + if (ctx->i_pid < 0) { + cw_perror("fork failed"); + return (1); + } + (void) close(ctx->i_fd[1]); + + if (block) + return (reap(ctx)); + + return (0); } int main(int argc, char **argv) { - struct aelist *h = newael(); + cw_ictx_t *ctx = newictx(); + cw_ictx_t *ctx_shadow = newictx(); const char *dir; - int ac; - char **newargv; - struct ae *a; char cc_buf[MAXPATHLEN], gcc_buf[MAXPATHLEN]; + int do_serial, do_shadow; + int ret = 0; if ((progname = strrchr(argv[0], '/')) == NULL) progname = argv[0]; else progname++; - default_cc_dir = DEFAULT_CC_DIR; - default_gcc_dir = DEFAULT_GCC_DIR; - default_cplusplus_dir = DEFAULT_CPLUSPLUS_DIR; - default_gplusplus_dir = DEFAULT_GPLUSPLUS_DIR; + if (ctx == NULL || ctx_shadow == NULL) + nomem(); + + ctx->i_flags = CW_F_ECHO|CW_F_XLATE; /* * Figure out where to get our tools from. This depends on @@ -1287,16 +1593,31 @@ main(int argc, char **argv) (void) snprintf(cc_buf, MAXPATHLEN, "%s/SUNWspro/SOS10/bin", dir); } - if (dir != NULL) - default_cc_dir = (char *)cc_buf; + if (dir != NULL) { + dirs[CIDX(CW_C_CC, 0)] = (const char *)cc_buf; + dirs[CIDX(CW_C_CC, CW_F_CXX)] = (const char *)cc_buf; + } if ((dir = getenv("GNU_ROOT")) != NULL) { (void) snprintf(gcc_buf, MAXPATHLEN, "%s/bin", dir); - default_gcc_dir = (char *)gcc_buf; + dirs[CIDX(CW_C_GCC, 0)] = (const char *)gcc_buf; + dirs[CIDX(CW_C_GCC, CW_F_CXX)] = (const char *)gcc_buf; } - default_cplusplus_dir = default_cc_dir; - default_gplusplus_dir = default_gcc_dir; + if ((dir = getenv("CW_CC_DIR")) != NULL) + dirs[CIDX(CW_C_CC, 0)] = dir; + if ((dir = getenv("CW_CPLUSPLUS_DIR")) != NULL) + dirs[CIDX(CW_C_CC, CW_F_CXX)] = dir; + if ((dir = getenv("CW_GCC_DIR")) != NULL) + dirs[CIDX(CW_C_GCC, 0)] = dir; + if ((dir = getenv("CW_GPLUSPLUS_DIR")) != NULL) + dirs[CIDX(CW_C_GCC, CW_F_CXX)] = dir; + + do_shadow = (getenv("CW_NO_SHADOW") ? 0 : 1); + do_serial = (getenv("CW_SHADOW_SERIAL") ? 1 : 0); + + if (getenv("CW_NO_EXEC") == NULL) + ctx->i_flags |= CW_F_EXEC; /* * The first argument must be one of "-_cc", "-_gcc", "-_CC", or "-_g++" @@ -1306,58 +1627,42 @@ main(int argc, char **argv) argc--; argv++; if (strcmp(argv[0], "-_cc") == 0) { - if ((dir = getenv("CW_CC_DIR")) == NULL) - dir = default_cc_dir; - do_cc(dir, "cc", argc, argv, h, 0); + ctx->i_compiler = CW_C_CC; } else if (strcmp(argv[0], "-_gcc") == 0) { - if ((dir = getenv("CW_GCC_DIR")) == NULL) - dir = default_gcc_dir; - do_gcc(dir, "gcc", argc, argv, h, 0); + ctx->i_compiler = CW_C_GCC; } else if (strcmp(argv[0], "-_CC") == 0) { - if ((dir = getenv("CW_CPLUSPLUS_DIR")) == NULL) - dir = default_cplusplus_dir; - do_cc(dir, "CC", argc, argv, h, 1); + ctx->i_compiler = CW_C_CC; + ctx->i_flags |= CW_F_CXX; } else if (strcmp(argv[0], "-_g++") == 0) { - if ((dir = getenv("CW_GPLUSPLUS_DIR")) == NULL) - dir = default_gplusplus_dir; - do_gcc(dir, "g++", argc, argv, h, 1); + ctx->i_compiler = CW_C_GCC; + ctx->i_flags |= CW_F_CXX; } else { /* assume "-_gcc" by default */ argc++; argv--; - if ((dir = getenv("CW_GCC_DIR")) == NULL) - dir = default_gcc_dir; - do_gcc(dir, "gcc", argc, argv, h, 0); + ctx->i_compiler = CW_C_GCC; } - newargv = calloc(sizeof (*newargv), newargc + 1); - - if (echo) - (void) printf("+ "); + ctx->i_oldargc = argc; + ctx->i_oldargv = argv; - for (ac = 0, a = h->ael_head; a; a = a->ae_next, ac++) { - newargv[ac] = a->ae_arg; - if (echo) - (void) printf("%s ", a->ae_arg); - if (a == h->ael_tail) - break; + if (argc > 1 && strcmp(argv[1], "-_compiler") == 0) { + ctx->i_flags &= ~CW_F_XLATE; + prepctx(ctx); + (void) printf("%s\n", ctx->i_ae->ael_head->ae_arg); + return (0); } - if (echo) { - (void) printf("\n"); - (void) fflush(stdout); + ret |= exec_ctx(ctx, do_serial); + + if (do_shadow) { + (void) memcpy(ctx_shadow, ctx, sizeof (cw_ictx_t)); + ctx_shadow->i_flags |= CW_F_SHADOW; + ret |= exec_ctx(ctx_shadow, 1); } - /* - * Here goes .. - */ - (void) execvp(newargv[0], newargv); + if (!do_serial) + ret |= reap(ctx); - /* - * execvp() returns only on error. - */ - perror("execvp"); - (void) fprintf(stderr, "%s: couldn't run %s\n", - progname, newargv[0]); - return (4); + return (ret); } |
