Mercurial > hg > aboriginal
changeset 1661:586b011cb706
Swap old wrapper for new.
author | Rob Landley <rob@landley.net> |
---|---|
date | Mon, 23 Jun 2014 06:02:15 -0500 |
parents | c1addb6ebb84 |
children | 970b405bd6e6 |
files | sources/toys/ccwrap.c sources/toys/ccwrap.old sources/toys/ccwrap2.c |
diffstat | 3 files changed, 866 insertions(+), 866 deletions(-) [+] |
line wrap: on
line diff
--- a/sources/toys/ccwrap.c Mon Jun 23 06:01:02 2014 -0500 +++ b/sources/toys/ccwrap.c Mon Jun 23 06:02:15 2014 -0500 @@ -1,480 +1,459 @@ -/* vi: set ts=4 :*/ -/* - * Copyright (C) 2000 Manuel Novoa III - * Copyright (C) 2002-2003 Erik Andersen - * Copyright (C) 2006-2010 Rob Landley <rob@landley.net> +/* Copyright 2013 Rob Landley <rob@landley.net> * - * Wrapper to use make a C compiler relocatable. - * - * Licensed under GPLv2. + * C compiler wrapper. Parses command line, supplies path information for + * headers and libraries. */ -// No, we don't need to check the return value from asprintf(). - #undef _FORTIFY_SOURCE -#define _GNU_SOURCE -#include <alloca.h> +#include <libgen.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> -#include <stdarg.h> #include <string.h> -#include <strings.h> -#include <unistd.h> -#include <errno.h> #include <sys/stat.h> -#include <sys/wait.h> +#include <sys/types.h> +#include <unistd.h> + +// Default to musl +#ifndef DYNAMIC_LINKER +#define DYNAMIC_LINKER "/lib/libc.so" +#endif + +// Some plumbing from toybox + +void *xmalloc(long len) +{ + void *ret = malloc(len); + + if (!ret) { + fprintf(stderr, "bad malloc\n"); + exit(1); + } +} -static char *topdir, *devprefix; -static char nostdinc[] = "-nostdinc"; -static char nostdlib[] = "-nostdlib"; +// Die unless we can allocate enough space to sprintf() into. +char *xmprintf(char *format, ...) +{ + va_list va, va2; + int len; + char *ret; + + va_start(va, format); + va_copy(va2, va); -// For C++ -static char nostdinc_plus[] = "-nostdinc++"; + // How long is it? + len = vsnprintf(0, 0, format, va); + len++; + va_end(va); + + // Allocate and do the sprintf() + ret = xmalloc(len); + vsnprintf(ret, len, format, va2); + va_end(va2); + + return ret; +} // Confirm that a regular file exists, and (optionally) has the executable bit. int is_file(char *filename, int has_exe) { - // Confirm it has the executable bit set, if necessary. - if (!has_exe || !access(filename, X_OK)) { - struct stat st; + // Confirm it has the executable bit set, if necessary. + if (!has_exe || !access(filename, X_OK)) { + struct stat st; - // Confirm it exists and is not a directory. - if (!stat(filename, &st) && S_ISREG(st.st_mode)) return 1; - } - return 0; + // Confirm it exists and is not a directory. + if (!stat(filename, &st) && S_ISREG(st.st_mode)) return 1; + } + return 0; } -// Find an executable in a colon-separated path - +// Find a file in a colon-separated path char *find_in_path(char *path, char *filename, int has_exe) { - char *cwd = getcwd(NULL, 0); + char *cwd = getcwd(0, 0); - if (index(filename, '/') && is_file(filename, has_exe)) - return realpath(filename, NULL); + if (index(filename, '/') && is_file(filename, has_exe)) + return realpath(filename, 0); + + while (path) { + char *str, *next = path ? index(path, ':') : 0; + int len = next ? next-path : strlen(path); - while (path) { - char *str, *next = path ? index(path, ':') : NULL; - int len = next ? next-path : strlen(path); + if (!len) str = xmprintf("%s/%s", cwd, filename); + else str = xmprintf("%*s/%s", len, path, filename); - // The +3 is a corner case: if strlen(filename) is 1, make sure we - // have enough space to append ".." to make topdir. - str = malloc(strlen(filename) + (len ? len : strlen(cwd)) + 3); - if (!len) sprintf(str, "%s/%s", cwd, filename); - else { - char *str2 = str; + // If it's not a directory, return it. + if (is_file(str, has_exe)) { + char *s = realpath(str, 0); + + free(str); + free(cwd); + + return s; + } else free(str); - strncpy(str, path, len); - str2 = str+len; - *(str2++) = '/'; - strcpy(str2, filename); - } + if (next) next++; + path = next; + } + free(cwd); + + return NULL; +} + +struct dlist { + struct dlist *next, *prev; + char *str; +}; - // If it's not a directory, return it. - if (is_file(str, has_exe)) { - char *s = realpath(str, NULL); - free(str); - free(cwd); - return s; - } else free(str); +// Append to end of doubly linked list (in-order insertion) +void dlist_add(struct dlist **list, char *str) +{ + struct dlist *new = xmalloc(sizeof(struct dlist)); - if (next) next++; - path = next; - } - free(cwd); + new->str = str; + if (*list) { + new->next = *list; + new->prev = (*list)->prev; + (*list)->prev->next = new; + (*list)->prev = new; + } else *list = new->next = new->prev = new; - return NULL; + *list = new; } // Some compiler versions don't provide separate T and S versions of begin/end, // so fall back to the base version if they're not there. -char *find_TSpath(char *base, int use_shared, int use_static_linking) +char *find_TSpath(char *base, char *top, int use_shared, int use_static_linking) { - int i; - char *temp; + int i; + char *temp; - asprintf(&temp, base, devprefix, - use_shared ? "S.o" : use_static_linking ? "T.o" : ".o"); + temp = xmprintf(base, top, + use_shared ? "S.o" : use_static_linking ? "T.o" : ".o"); - if (!is_file(temp, 0)) { - free(temp); - asprintf(&temp, base, devprefix, ".o"); - } + if (!is_file(temp, 0)) { + free(temp); + temp = xmprintf(base, top, ".o"); + } - return temp; + return temp; } -int main(int argc, char **argv) -{ - int linking = 1, use_static_linking = 0, use_shared_libgcc, used_x = 0; - int use_stdinc = 1, use_start = 1, use_stdlib = 1, use_shared = 0; - int source_count = 0, verbose = 0; - int i, argcnt, lplen; - char **cc_argv, **libpath; - char *dlstr; - char *cc, *toolprefix; - char *debug_wrapper=getenv("CCWRAP_DEBUG"); - // For C++ +enum { + Clibccso, Clink, Cprofile, Cshared, Cstart, Cstatic, Cstdinc, Cstdlib, + Cverbose, Cx, Cdashdash, - char *cpp = NULL; - int prefixlen, ctor_dtor = 1, use_nostdinc_plus = 0; - - // For profiling - int profile = 0; + CPctordtor, CP, CPstdinc +}; - if(debug_wrapper) { - fprintf(stderr,"incoming: "); - for(cc_argv=argv;*cc_argv;cc_argv++) - fprintf(stderr,"%s ",*cc_argv); - fprintf(stderr,"\n\n"); - } +#define MASK_BIT(X) (1<<X) +#define SET_FLAG(X) (flags |= MASK_BIT(X)) +#define CLEAR_FLAG(X) (flags &= ~MASK_BIT(X)) +#define GET_FLAG(X) (flags & MASK_BIT(X)) - // Allocate space for new command line - cc_argv = alloca(sizeof(char*) * (argc + 128)); +// Read the command line arguments and work out status +int main(int argc, char *argv[]) +{ + char *topdir, *ccprefix, *dynlink, *cc, *temp, **keepv, **hdr, **outv; + int i, keepc, srcfiles, flags, outc; + struct dlist *libs = 0; - // What directory is the wrapper script in? - if(!(topdir = find_in_path(getenv("PATH"), argv[0], 1))) { - fprintf(stderr, "can't find %s in $PATH (did you export it?)\n", argv[0]); - exit(1); - } else { - char *path = getenv("PATH"), *temp; - - if (!path) path = ""; + keepv = xmalloc(argc*sizeof(char *)); + flags = MASK_BIT(Clink)|MASK_BIT(Cstart)|MASK_BIT(Cstdinc)|MASK_BIT(Cstdlib) + |MASK_BIT(CPctordtor); + keepc = srcfiles = 0; - // Add that directory to the start of $PATH. (Better safe than sorry.) - *rindex(topdir,'/') = 0; - asprintf(&temp,"PATH=%s:%s/../tools/bin:%s",topdir,topdir,path); - putenv(temp); - - // The directory above the wrapper script should have include, cc, - // and lib directories. However, the script could have a symlink - // pointing to its directory (ala /bin -> /usr/bin), so append ".." - // instead of trucating the path. - strcat(topdir,"/.."); - } - - // What's the name of the C compiler we're wrapping? (It may have a - // cross-prefix.) - cc = getenv("CCWRAP_CC"); - if (!cc) cc = "rawcc"; + if (getenv("CCWRAP_DEBUG")) { + SET_FLAG(Cverbose); + fprintf(stderr, "incoming: "); + for (i=0; i<argc; i++) fprintf(stderr, "%s ", argv[i]); + fprintf(stderr, "\n\n"); + } - // Check end of name, since there could be a cross-prefix on the thing - toolprefix = strrchr(argv[0], '/'); - if (!toolprefix) toolprefix = argv[0]; - else toolprefix++; - - prefixlen = strlen(toolprefix); - if (prefixlen>=3 && !strcmp(toolprefix+prefixlen-3, "gcc")) prefixlen -= 3; - else if (!strcmp(toolprefix+prefixlen-2, "cc")) prefixlen -= 2; - else if (!strcmp(toolprefix+prefixlen-2, "ld")) { - prefixlen -= 2; + // Find the cannonical path to the directory containing our executable + topdir = find_in_path(getenv("PATH"), *argv, 1); + if (!topdir || !(temp = rindex(topdir, '/')) || strlen(*argv)<2) { + fprintf(stderr, "Can't find %s in $PATH (did you export it?)\n", *argv); + exit(1); + } + // We want to strip off the bin/ but the path we followed can end with + // a symlink, so append .. instead. + strcpy(++temp, ".."); - // TODO: put support for wrapping the linker here. - } else if (!strcmp(toolprefix+prefixlen-3, "cpp")) { - prefixlen -=3; - linking = 0; + // Add our binary's directory and the tools directory to $PATH so gcc's + // convulsive flailing probably blunders through here first. + // Note: do this before reading topdir from environment variable, because + // toolchain binaries go with wrapper even if headers/libraries don't. + temp = getenv("PATH"); + if (!temp) temp = ""; + temp = xmprintf("PATH=%s/bin:%s/tools/bin:%s", topdir, topdir, temp); + putenv(temp); - // Wrapping the c++ compiler? - } else if (!strcmp(toolprefix+prefixlen-2, "++")) { - int len = strlen(cc); - cpp = alloca(len+1); - strcpy(cpp, cc); - cpp[len-1]='+'; - cpp[len-2]='+'; - use_nostdinc_plus = 1; - } + // Override header/library search path with environment variable? + temp = getenv("CCWRAP_TOPDIR"); + if (!temp) { + cc = xmprintf("%sCCWRAP_TOPDIR", ccprefix); - devprefix = getenv("CCWRAP_TOPDIR"); - if (!devprefix) { - char *temp, *temp2; - asprintf(&temp, "%.*sCCWRAP_TOPDIR", prefixlen, toolprefix); - temp2 = temp; - while (*temp2) { - if (*temp2 == '-') *temp2='_'; - temp2++; - } - devprefix = getenv(temp); - } - if (!devprefix) devprefix = topdir; - - // Do we have libgcc_s.so? - - asprintf(&dlstr, "%s/lib/libgcc_s.so", devprefix); - use_shared_libgcc = is_file(dlstr, 0); - free(dlstr); + for (i=0; cc[i]; i++) if (cc[i] == '-') cc[i]='_'; + temp = getenv(cc); + free(cc); + } + if (temp) { + free(topdir); + topdir = temp; + } + + // Name of the C compiler we're wrapping. + cc = getenv("CCWRAP_CC"); + if (!cc) cc = "rawcc"; + + // figure out cross compiler prefix + i = strlen(ccprefix = basename(*argv)); + if (i<2) { + fprintf(stderr, "Bad name '%s'\n", ccprefix); + exit(1); + } + if (!strcmp("++", ccprefix+i-2)) { + cc = "raw++"; + SET_FLAG(CP); + SET_FLAG(CPstdinc); + if (i<3) exit(1); + i -= 3; + } else if (!strcmp("gcc", ccprefix+i-3)) i -= 3; // TODO: yank + else if (!strcmp("cc", ccprefix+i-2)) i-=2; + else if (!strcmp("cpp", ccprefix+i-3)) { + i -= 3; + CLEAR_FLAG(Clink); + } else return 1; // TODO: wrap ld + if (!(ccprefix = strndup(ccprefix, i))) exit(1); - // Figure out where the dynamic linker is. - dlstr = getenv("CCWRAP_DYNAMIC_LINKER"); - if (!dlstr) dlstr = "/lib/ld-uClibc.so.0"; - asprintf(&dlstr, "-Wl,--dynamic-linker,%s", dlstr); - - lplen = 0; - libpath = alloca(sizeof(char*) * (argc)); - libpath[lplen] = 0; - - // Parse the incoming compiler arguments. - - for (i=1; i<argc; i++) { - if (argv[i][0] == '-' && argv[i][1]) { /* option */ - switch (argv[i][1]) { - case 'M': /* generate dependencies */ - { - char *p = argv[i]; - - // -M and -MM imply -E and thus no linking - // Other -MX options _don't_, including -MMD. - if (p[2] && (p[2]!='M' || p[3])) break; - } - // fall through + // Does toolchain have a shared libcc? + temp = xmprintf("%s/lib/libgcc_s.so", topdir); + if (is_file(temp, 0)) SET_FLAG(Clibccso); + free(temp); - case 'c': /* compile or assemble */ - case 'S': /* generate assembler code */ - case 'E': /* preprocess only */ - linking = 0; - break; + // Where's the dynamic linker? + temp = getenv("CCWRAP_DYNAMIC_LINKER"); + if (!temp) temp = DYNAMIC_LINKER; + dynlink = xmprintf("-Wl,--dynamic-linker,%s", temp); - case 'L': /* library path */ - libpath[lplen++] = argv[i]; - libpath[lplen] = 0; - if (!argv[i][2]) { - argv[i] = 0; - libpath[lplen++] = argv[++i]; - libpath[lplen] = 0; - } - argv[i] = 0; - break; + // Fallback library search path, these will wind up at the end + dlist_add(&libs, xmprintf("%s/lib", topdir)); + dlist_add(&libs, xmprintf("%s/cc/lib", topdir)); - case 'v': /* verbose */ - if (argv[i][2] == 0) verbose = 1; - printf("Invoked as %s\n", argv[0]); - printf("Reference path: %s\n", topdir); - break; + // Parse command line arguments + for (i=1; i<argc; i++) { + char *c = keepv[keepc++] = argv[i]; + + if (!strcmp(c, "--")) SET_FLAG(Cdashdash); - case 'n': - if (!strcmp(nostdinc,argv[i])) use_stdinc = 0; - else if (!strcmp("-nostartfiles",argv[i])) { - ctor_dtor = 0; - use_start = 0; - } else if (!strcmp("-nodefaultlibs",argv[i])) { - use_stdlib = 0; - argv[i] = 0; - } else if (!strcmp(nostdlib,argv[i])) { - ctor_dtor = 0; - use_start = 0; - use_stdlib = 0; - } else if (!strcmp(nostdinc_plus,argv[i])) - use_nostdinc_plus = 0; - break; + // is this an option? + if (*c == '-' && c[1] && !GET_FLAG(Cdashdash)) c++; + else { + srcfiles++; + continue; + } - case 's': - if (!strcmp(argv[i],"-static")) { - use_static_linking = 1; - use_shared_libgcc=0; - } - if (!strcmp(argv[i],"-static-libgcc")) - use_shared_libgcc = 0; - if (!strcmp(argv[i],"-shared-libgcc")) - use_shared_libgcc = 1; - if (!strcmp("-shared",argv[i])) { - use_start = 0; - use_shared = 1; - } - break; + // Second dash? + if (*c == '-') { + // Passthrough double dash versions of single-dash options. + if (!strncmp(c, "-print-", 7) || !strncmp(c, "-static", 7) + || !strncmp(c, "-shared", 7)) c++; + else { + if (!strcmp(c, "-no-ctors")) { + CLEAR_FLAG(CPctordtor); + keepc--; + } + continue; + } + } + + // -M and -MM imply -E and thus no linking. + // Other -M? options don't, including -MMD + if (*c == 'M' && c[1] && (c[1] != 'M' || c[2])) continue; - case 'W': /* -static could be passed directly to ld */ - if (!strncmp("-Wl,",argv[i],4)) { - char *temp = strstr(argv[i], ",-static"); - if (temp && (!temp[7] || temp[7]==',')) { - use_static_linking = 1; - use_shared_libgcc=0; - } - if (strstr(argv[i],"--dynamic-linker")) dlstr = 0; - } - break; - - case 'p': - if (!strncmp("-print-",argv[i],7)) { - char *temp, *temp2; - int itemp, showall = 0; + // compile, preprocess, assemble... options that suppress linking. + if (strchr("cEMS", *c)) CLEAR_FLAG(Clink); + else if (*c == 'L') { + if (c[1]) dlist_add(&libs, c+1); + else if (!argv[++i]) { + fprintf(stderr, "-L at end of args\n"); + exit(1); + } else dlist_add(&libs, argv[i]); + keepc--; + } else if (*c == 'f') { + if (!strcmp(c, "fprofile-arcs")) SET_FLAG(Cprofile); + } else if (*c == 'n') { + keepc--; + if (!strcmp(c, "nodefaultlibs")) CLEAR_FLAG(Cstdlib); + else if (!strcmp(c, "nostartfiles")) { + CLEAR_FLAG(CPctordtor); + CLEAR_FLAG(Cstart); + } else if (!strcmp(c, "nostdinc")) CLEAR_FLAG(Cstdinc); + else if (!strcmp(c, "nostdinc++")) CLEAR_FLAG(CPstdinc); + else if (!strcmp(c, "nostdlib")) { + CLEAR_FLAG(Cstdlib); + CLEAR_FLAG(Cstart); + CLEAR_FLAG(CPctordtor); + } else keepc++; + } else if (*c == 'p') { + if (!strncmp(c, "print-", 6)) { + struct dlist *dl; + int show = 0; - temp = argv[i]+7; - if (!strncmp(temp, "prog-name=", 10)) { - printf("%.*s%s\n", prefixlen, toolprefix, temp+10); - exit(0); - } else if (!strcmp(temp, "search-dirs")) { - printf("install: %s/\n",devprefix); - printf("programs: %s\n",getenv("PATH")); - printf("libraries: "); - temp2 = ""; - showall = 1; - } else if (!strncmp(temp, "file-name=", 10)) - temp2 = temp+10; - else if (!strcmp(temp, "libgcc-file-name")) - temp2="libgcc.a"; - else break; - - // Find this entry in the library path. - for(itemp=0;;itemp++) { - if (itemp == lplen) - asprintf(&temp, "%s/cc/lib/%s", devprefix, - temp2); - else if (itemp == lplen+1) - asprintf(&temp, "%s/lib/%s", devprefix, temp2); + // Just add prefix to prog-name + if (!strncmp(c += 6, "prog-name=", 10)) { + printf("%s%s\n", ccprefix, c+10); + exit(0); + } - // This is so "include" finds the cc internal - // include dir. The uClibc build needs this. - else if (itemp == lplen+2) - asprintf(&temp, "%s/cc/%s", devprefix, temp2); - else if (itemp == lplen+3) { - temp = temp2; - break; - } else asprintf(&temp, "%s/%s", libpath[itemp], - temp2); - - if (debug_wrapper) - fprintf(stderr, "try=%s\n", temp); + if (!strncmp(c, "file-name=", 10)) { + c += 10; + if (!strcmp(c, "include")) { + printf("%s/cc/include\n", topdir); + exit(0); + } + } else if (!strcmp(c, "search-dirs")) { + c = ""; + show = 1; + printf("install: %s/\nprograms: %s\nlibraries:", + topdir, getenv("PATH")); + } else if (!strcmp(c, "libgcc-file-name")) { + printf("%s/cc/lib/libgcc.a\n", topdir); + exit(0); + } + else break; - if (showall) printf(":%s"+(itemp?0:1), temp); - else if (!access(temp, F_OK)) break; - } - - - - printf("%s\n"+(showall ? 2 : 0), temp); - exit(0); - - // Profiling. - } else if (!strcmp("-pg",argv[i])) profile = 1; - break; + // Adjust dlist before traversing (move fallback to end, break circle) + libs = libs->next->next; + libs->prev->next = 0; - case 'f': - // profiling - if (strcmp("-fprofile-arcs",argv[i]) == 0) profile = 1; - break; - - case 'x': - used_x++; - break; - - // --longopts + // Either display the list, or find first hit. + for (dl = libs; dl; dl = dl->next) { + if (show) printf(":%s" + (dl==libs), dl->str); + else if (!access(dl->str, F_OK)) break; + } + if (dl) printf("%s", dl->str); + printf("\n"); - case '-': - if (!strncmp(argv[i],"--print-",8) - || !strncmp(argv[i],"--static",8) - || !strncmp(argv[i],"--shared",8)) - { - argv[i]++; - i--; - continue; - } else if (!strcmp("--no-ctors", argv[i])) { - ctor_dtor = 0; - argv[i] = 0; - } - break; - } - // assume it is an existing source file - } else ++source_count; - } - - argcnt = 0; + return 0; + } else if (!strcmp(c, "pg")) SET_FLAG(Cprofile); + } else if (*c == 's') { + keepc--; + if (!strcmp(c, "shared")) { + CLEAR_FLAG(Cstart); + SET_FLAG(Cshared); + } else if (!strcmp(c, "static")) { + SET_FLAG(Cstatic); + CLEAR_FLAG(Clibccso); + } else if (!strcmp(c, "shared-libgcc")) SET_FLAG(Clibccso); + else if (!strcmp(c, "static-libgcc")) CLEAR_FLAG(Clibccso); + else keepc++; + } else if (*c == 'v' && !c[1]) { + SET_FLAG(Cverbose); + printf("ccwrap: %s\n", topdir); + } else if (!strncmp(c, "Wl,", 3)) { + temp = strstr(c, ",-static"); + if (temp && (!temp[8] || temp[8]==',')) { + SET_FLAG(Cstatic); + CLEAR_FLAG(Clibccso); + } + // This argument specifies dynamic linker, so we shouldn't. + if (strstr(c, "--dynamic-linker")) dynlink = 0; + } else if (*c == 'x') SET_FLAG(Cx); + } - cc_argv[argcnt++] = cpp ? cpp : cc; + // Initialize argument list for exec call - if (cpp) cc_argv[argcnt++] = "-fno-use-cxa-atexit"; +// what's a good outc size? - if (linking && source_count) { -//#if defined HAS_ELF && ! defined HAS_MMU -// cc_argv[argcnt++] = "-Wl,-elf2flt"; -//#endif - cc_argv[argcnt++] = nostdlib; - if (use_static_linking) cc_argv[argcnt++] = "-static"; - else if (dlstr) cc_argv[argcnt++] = dlstr; - for (i=0; i<lplen; i++) - if (libpath[i]) cc_argv[argcnt++] = libpath[i]; - - // just to be safe: - asprintf(cc_argv+(argcnt++), "-Wl,-rpath-link,%s/lib", devprefix); + outc = (argc+keepc+64)*sizeof(char *); + memset(outv = xmalloc(outc), 0, outc); + outc = 0; + outv[outc++] = cc; - asprintf(cc_argv+(argcnt++), "-L%s/lib", devprefix); - asprintf(cc_argv+(argcnt++), "-L%s/cc/lib", devprefix); - } - if (use_stdinc && source_count) { - cc_argv[argcnt++] = nostdinc; - - if (cpp) { - if (use_nostdinc_plus) cc_argv[argcnt++] = "-nostdinc++"; - cc_argv[argcnt++] = "-isystem"; - asprintf(cc_argv+(argcnt++), "%s/c++/include", devprefix); - } + // Are we linking? + if (srcfiles) { + outv[outc++] = "-nostdinc"; + if (GET_FLAG(CP)) { + outv[outc++] = "-nostdinc++"; + if (GET_FLAG(CPstdinc)) { + outv[outc++] = "-isystem"; + outv[outc++] = xmprintf("%s/c++/include", topdir); + } + } + if (GET_FLAG(Cstdinc)) { + outv[outc++] = "-isystem"; + outv[outc++] = xmprintf("%s/include", topdir); + outv[outc++] = "-isystem"; + outv[outc++] = xmprintf("%s/cc/include", topdir); + } + if (GET_FLAG(Clink)) { + // Zab defaults, add dynamic linker + outv[outc++] = "-nostdlib"; + outv[outc++] = GET_FLAG(Cstatic) ? "-static" : dynlink; + if (GET_FLAG(Cshared)) outv[outc++] = "-shared"; - cc_argv[argcnt++] = "-isystem"; - asprintf(cc_argv+(argcnt++), "%s/include", devprefix); - cc_argv[argcnt++] = "-isystem"; - asprintf(cc_argv+(argcnt++), "%s/cc/include", devprefix); - } - - cc_argv[argcnt++] = "-U__nptl__"; - - if (linking && source_count) { - - if (profile) - asprintf(cc_argv+(argcnt++), "%s/lib/gcrt1.o", devprefix); + // Copy libraries to output (first move fallback to end, break circle) + libs = libs->next->next; + libs->prev->next = 0; + for (; libs; libs = libs->next) + outv[outc++] = xmprintf("-L%s", libs->str); + outv[outc++] = xmprintf("-Wl,-rpath-link,%s/lib", topdir); // TODO: in? - if (ctor_dtor) { - asprintf(cc_argv+(argcnt++), "%s/lib/crti.o", devprefix); - cc_argv[argcnt++]=find_TSpath("%s/cc/lib/crtbegin%s", - use_shared, use_static_linking); - } - if (use_start && !profile) - asprintf(cc_argv+(argcnt++), "%s/lib/%scrt1.o", devprefix, use_shared ? "S" : ""); - - // Add remaining unclaimed arguments. - - for (i=1; i<argc; i++) if (argv[i]) cc_argv[argcnt++] = argv[i]; + // TODO: -fprofile-arcs + if (GET_FLAG(Cprofile)) xmprintf("%s/lib/gcrt1.o", topdir); + if (GET_FLAG(CPctordtor)) { + outv[outc++] = xmprintf("%s/lib/crti.o", topdir); + outv[outc++] = find_TSpath("%s/cc/lib/crtbegin%s", topdir, + GET_FLAG(Cshared), GET_FLAG(Cstatic)); + } + if (!GET_FLAG(Cprofile) && GET_FLAG(Cstart)) + outv[outc++] = xmprintf("%s/lib/%scrt1.o", topdir, + GET_FLAG(Cshared) ? "S" : ""); + } + } - if (used_x) cc_argv[argcnt++] = "-xnone"; - - // Add standard libraries + // Copy unclaimed arguments + memcpy(outv+outc, keepv, keepc*sizeof(char *)); + outc += keepc; - if (use_stdlib) { - if (cpp) { - cc_argv[argcnt++] = "-lstdc++"; - cc_argv[argcnt++] = "-lm"; - } - - // libgcc can call libc which can call libgcc + if (srcfiles && GET_FLAG(Clink)) { + if (GET_FLAG(Cx)) outv[outc++] = "-xnone"; + if (GET_FLAG(Cstdlib)) { + if (GET_FLAG(CP)) { + outv[outc++] = "-lstdc++"; + //outv[outc++] = "-lm"; + } - cc_argv[argcnt++] = "-Wl,--start-group,--as-needed"; - cc_argv[argcnt++] = "-lgcc"; - if (!use_static_linking && use_shared_libgcc) - cc_argv[argcnt++] = "-lgcc_s"; - else cc_argv[argcnt++] = "-lgcc_eh"; - cc_argv[argcnt++] = "-lc"; - cc_argv[argcnt++] = "-Wl,--no-as-needed,--end-group"; - } - if (ctor_dtor) { - cc_argv[argcnt++] = find_TSpath("%s/cc/lib/crtend%s", use_shared, 0); - asprintf(cc_argv+(argcnt++), "%s/lib/crtn.o", devprefix); - } - } else for (i=1; i<argc; i++) if (argv[i]) cc_argv[argcnt++] = argv[i]; - - cc_argv[argcnt++] = NULL; + // libgcc can call libc which can call libgcc + outv[outc++] = "-Wl,--start-group,--as-needed"; + outv[outc++] = "-lgcc"; + if (GET_FLAG(Clibccso)) outv[outc++] = "-lgcc_s"; + else outv[outc++] = "-lgcc_eh"; + outv[outc++] = "-lc"; + outv[outc++] = "-Wl,--no-as-needed,--end-group"; + } + if (GET_FLAG(CPctordtor)) { + outv[outc++] = find_TSpath("%s/cc/lib/crtend%s", topdir, + GET_FLAG(Cshared), GET_FLAG(Cstatic)); + outv[outc++] = xmprintf("%s/lib/crtn.o", topdir); + } + } + outv[outc] = 0; - if (verbose) { - for (i=0; cc_argv[i]; i++) printf("arg[%2i] = %s\n", i, cc_argv[i]); - fflush(stdout); - } + if (getenv("CCWRAP_DEBUG")) { + fprintf(stderr, "outgoing:"); + for(i=0; i<outc; i++) printf(stderr, " \"%s\"", outv[i]); + fprintf(stderr, "\n"); + } - if (debug_wrapper) { - fprintf(stderr, "outgoing: "); - for (i=0; cc_argv[i]; i++) fprintf(stderr, "%s ",cc_argv[i]); - fprintf(stderr, "\n\n"); - } + execvp(*outv, outv); + fprintf(stderr, "%s: %s\n", *outv, strerror(errno)); + exit(1); - execvp(cc_argv[0], cc_argv); - fprintf(stderr, "%s: %s\n", cpp ? cpp : cc, strerror(errno)); - exit(EXIT_FAILURE); + return 0; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sources/toys/ccwrap.old Mon Jun 23 06:02:15 2014 -0500 @@ -0,0 +1,480 @@ +/* vi: set ts=4 :*/ +/* + * Copyright (C) 2000 Manuel Novoa III + * Copyright (C) 2002-2003 Erik Andersen + * Copyright (C) 2006-2010 Rob Landley <rob@landley.net> + * + * Wrapper to use make a C compiler relocatable. + * + * Licensed under GPLv2. + */ + +// No, we don't need to check the return value from asprintf(). + +#undef _FORTIFY_SOURCE + +#define _GNU_SOURCE +#include <alloca.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/wait.h> + +static char *topdir, *devprefix; +static char nostdinc[] = "-nostdinc"; +static char nostdlib[] = "-nostdlib"; + +// For C++ +static char nostdinc_plus[] = "-nostdinc++"; + +// Confirm that a regular file exists, and (optionally) has the executable bit. +int is_file(char *filename, int has_exe) +{ + // Confirm it has the executable bit set, if necessary. + if (!has_exe || !access(filename, X_OK)) { + struct stat st; + + // Confirm it exists and is not a directory. + if (!stat(filename, &st) && S_ISREG(st.st_mode)) return 1; + } + return 0; +} + +// Find an executable in a colon-separated path + +char *find_in_path(char *path, char *filename, int has_exe) +{ + char *cwd = getcwd(NULL, 0); + + if (index(filename, '/') && is_file(filename, has_exe)) + return realpath(filename, NULL); + + while (path) { + char *str, *next = path ? index(path, ':') : NULL; + int len = next ? next-path : strlen(path); + + // The +3 is a corner case: if strlen(filename) is 1, make sure we + // have enough space to append ".." to make topdir. + str = malloc(strlen(filename) + (len ? len : strlen(cwd)) + 3); + if (!len) sprintf(str, "%s/%s", cwd, filename); + else { + char *str2 = str; + + strncpy(str, path, len); + str2 = str+len; + *(str2++) = '/'; + strcpy(str2, filename); + } + + // If it's not a directory, return it. + if (is_file(str, has_exe)) { + char *s = realpath(str, NULL); + free(str); + free(cwd); + return s; + } else free(str); + + if (next) next++; + path = next; + } + free(cwd); + + return NULL; +} + +// Some compiler versions don't provide separate T and S versions of begin/end, +// so fall back to the base version if they're not there. + +char *find_TSpath(char *base, int use_shared, int use_static_linking) +{ + int i; + char *temp; + + asprintf(&temp, base, devprefix, + use_shared ? "S.o" : use_static_linking ? "T.o" : ".o"); + + if (!is_file(temp, 0)) { + free(temp); + asprintf(&temp, base, devprefix, ".o"); + } + + return temp; +} + +int main(int argc, char **argv) +{ + int linking = 1, use_static_linking = 0, use_shared_libgcc, used_x = 0; + int use_stdinc = 1, use_start = 1, use_stdlib = 1, use_shared = 0; + int source_count = 0, verbose = 0; + int i, argcnt, lplen; + char **cc_argv, **libpath; + char *dlstr; + char *cc, *toolprefix; + char *debug_wrapper=getenv("CCWRAP_DEBUG"); + + // For C++ + + char *cpp = NULL; + int prefixlen, ctor_dtor = 1, use_nostdinc_plus = 0; + + // For profiling + int profile = 0; + + if(debug_wrapper) { + fprintf(stderr,"incoming: "); + for(cc_argv=argv;*cc_argv;cc_argv++) + fprintf(stderr,"%s ",*cc_argv); + fprintf(stderr,"\n\n"); + } + + // Allocate space for new command line + cc_argv = alloca(sizeof(char*) * (argc + 128)); + + // What directory is the wrapper script in? + if(!(topdir = find_in_path(getenv("PATH"), argv[0], 1))) { + fprintf(stderr, "can't find %s in $PATH (did you export it?)\n", argv[0]); + exit(1); + } else { + char *path = getenv("PATH"), *temp; + + if (!path) path = ""; + + // Add that directory to the start of $PATH. (Better safe than sorry.) + *rindex(topdir,'/') = 0; + asprintf(&temp,"PATH=%s:%s/../tools/bin:%s",topdir,topdir,path); + putenv(temp); + + // The directory above the wrapper script should have include, cc, + // and lib directories. However, the script could have a symlink + // pointing to its directory (ala /bin -> /usr/bin), so append ".." + // instead of trucating the path. + strcat(topdir,"/.."); + } + + // What's the name of the C compiler we're wrapping? (It may have a + // cross-prefix.) + cc = getenv("CCWRAP_CC"); + if (!cc) cc = "rawcc"; + + // Check end of name, since there could be a cross-prefix on the thing + toolprefix = strrchr(argv[0], '/'); + if (!toolprefix) toolprefix = argv[0]; + else toolprefix++; + + prefixlen = strlen(toolprefix); + if (prefixlen>=3 && !strcmp(toolprefix+prefixlen-3, "gcc")) prefixlen -= 3; + else if (!strcmp(toolprefix+prefixlen-2, "cc")) prefixlen -= 2; + else if (!strcmp(toolprefix+prefixlen-2, "ld")) { + prefixlen -= 2; + + // TODO: put support for wrapping the linker here. + } else if (!strcmp(toolprefix+prefixlen-3, "cpp")) { + prefixlen -=3; + linking = 0; + + // Wrapping the c++ compiler? + } else if (!strcmp(toolprefix+prefixlen-2, "++")) { + int len = strlen(cc); + cpp = alloca(len+1); + strcpy(cpp, cc); + cpp[len-1]='+'; + cpp[len-2]='+'; + use_nostdinc_plus = 1; + } + + devprefix = getenv("CCWRAP_TOPDIR"); + if (!devprefix) { + char *temp, *temp2; + asprintf(&temp, "%.*sCCWRAP_TOPDIR", prefixlen, toolprefix); + temp2 = temp; + while (*temp2) { + if (*temp2 == '-') *temp2='_'; + temp2++; + } + devprefix = getenv(temp); + } + if (!devprefix) devprefix = topdir; + + // Do we have libgcc_s.so? + + asprintf(&dlstr, "%s/lib/libgcc_s.so", devprefix); + use_shared_libgcc = is_file(dlstr, 0); + free(dlstr); + + // Figure out where the dynamic linker is. + dlstr = getenv("CCWRAP_DYNAMIC_LINKER"); + if (!dlstr) dlstr = "/lib/ld-uClibc.so.0"; + asprintf(&dlstr, "-Wl,--dynamic-linker,%s", dlstr); + + lplen = 0; + libpath = alloca(sizeof(char*) * (argc)); + libpath[lplen] = 0; + + // Parse the incoming compiler arguments. + + for (i=1; i<argc; i++) { + if (argv[i][0] == '-' && argv[i][1]) { /* option */ + switch (argv[i][1]) { + case 'M': /* generate dependencies */ + { + char *p = argv[i]; + + // -M and -MM imply -E and thus no linking + // Other -MX options _don't_, including -MMD. + if (p[2] && (p[2]!='M' || p[3])) break; + } + // fall through + + case 'c': /* compile or assemble */ + case 'S': /* generate assembler code */ + case 'E': /* preprocess only */ + linking = 0; + break; + + case 'L': /* library path */ + libpath[lplen++] = argv[i]; + libpath[lplen] = 0; + if (!argv[i][2]) { + argv[i] = 0; + libpath[lplen++] = argv[++i]; + libpath[lplen] = 0; + } + argv[i] = 0; + break; + + case 'v': /* verbose */ + if (argv[i][2] == 0) verbose = 1; + printf("Invoked as %s\n", argv[0]); + printf("Reference path: %s\n", topdir); + break; + + case 'n': + if (!strcmp(nostdinc,argv[i])) use_stdinc = 0; + else if (!strcmp("-nostartfiles",argv[i])) { + ctor_dtor = 0; + use_start = 0; + } else if (!strcmp("-nodefaultlibs",argv[i])) { + use_stdlib = 0; + argv[i] = 0; + } else if (!strcmp(nostdlib,argv[i])) { + ctor_dtor = 0; + use_start = 0; + use_stdlib = 0; + } else if (!strcmp(nostdinc_plus,argv[i])) + use_nostdinc_plus = 0; + break; + + case 's': + if (!strcmp(argv[i],"-static")) { + use_static_linking = 1; + use_shared_libgcc=0; + } + if (!strcmp(argv[i],"-static-libgcc")) + use_shared_libgcc = 0; + if (!strcmp(argv[i],"-shared-libgcc")) + use_shared_libgcc = 1; + if (!strcmp("-shared",argv[i])) { + use_start = 0; + use_shared = 1; + } + break; + + case 'W': /* -static could be passed directly to ld */ + if (!strncmp("-Wl,",argv[i],4)) { + char *temp = strstr(argv[i], ",-static"); + if (temp && (!temp[7] || temp[7]==',')) { + use_static_linking = 1; + use_shared_libgcc=0; + } + if (strstr(argv[i],"--dynamic-linker")) dlstr = 0; + } + break; + + case 'p': + if (!strncmp("-print-",argv[i],7)) { + char *temp, *temp2; + int itemp, showall = 0; + + temp = argv[i]+7; + if (!strncmp(temp, "prog-name=", 10)) { + printf("%.*s%s\n", prefixlen, toolprefix, temp+10); + exit(0); + } else if (!strcmp(temp, "search-dirs")) { + printf("install: %s/\n",devprefix); + printf("programs: %s\n",getenv("PATH")); + printf("libraries: "); + temp2 = ""; + showall = 1; + } else if (!strncmp(temp, "file-name=", 10)) + temp2 = temp+10; + else if (!strcmp(temp, "libgcc-file-name")) + temp2="libgcc.a"; + else break; + + // Find this entry in the library path. + for(itemp=0;;itemp++) { + if (itemp == lplen) + asprintf(&temp, "%s/cc/lib/%s", devprefix, + temp2); + else if (itemp == lplen+1) + asprintf(&temp, "%s/lib/%s", devprefix, temp2); + + // This is so "include" finds the cc internal + // include dir. The uClibc build needs this. + else if (itemp == lplen+2) + asprintf(&temp, "%s/cc/%s", devprefix, temp2); + else if (itemp == lplen+3) { + temp = temp2; + break; + } else asprintf(&temp, "%s/%s", libpath[itemp], + temp2); + + if (debug_wrapper) + fprintf(stderr, "try=%s\n", temp); + + if (showall) printf(":%s"+(itemp?0:1), temp); + else if (!access(temp, F_OK)) break; + } + + + + printf("%s\n"+(showall ? 2 : 0), temp); + exit(0); + + // Profiling. + } else if (!strcmp("-pg",argv[i])) profile = 1; + break; + + case 'f': + // profiling + if (strcmp("-fprofile-arcs",argv[i]) == 0) profile = 1; + break; + + case 'x': + used_x++; + break; + + // --longopts + + case '-': + if (!strncmp(argv[i],"--print-",8) + || !strncmp(argv[i],"--static",8) + || !strncmp(argv[i],"--shared",8)) + { + argv[i]++; + i--; + continue; + } else if (!strcmp("--no-ctors", argv[i])) { + ctor_dtor = 0; + argv[i] = 0; + } + break; + } + // assume it is an existing source file + } else ++source_count; + } + + argcnt = 0; + + cc_argv[argcnt++] = cpp ? cpp : cc; + + if (cpp) cc_argv[argcnt++] = "-fno-use-cxa-atexit"; + + if (linking && source_count) { +//#if defined HAS_ELF && ! defined HAS_MMU +// cc_argv[argcnt++] = "-Wl,-elf2flt"; +//#endif + cc_argv[argcnt++] = nostdlib; + if (use_static_linking) cc_argv[argcnt++] = "-static"; + else if (dlstr) cc_argv[argcnt++] = dlstr; + for (i=0; i<lplen; i++) + if (libpath[i]) cc_argv[argcnt++] = libpath[i]; + + // just to be safe: + asprintf(cc_argv+(argcnt++), "-Wl,-rpath-link,%s/lib", devprefix); + + asprintf(cc_argv+(argcnt++), "-L%s/lib", devprefix); + asprintf(cc_argv+(argcnt++), "-L%s/cc/lib", devprefix); + } + if (use_stdinc && source_count) { + cc_argv[argcnt++] = nostdinc; + + if (cpp) { + if (use_nostdinc_plus) cc_argv[argcnt++] = "-nostdinc++"; + cc_argv[argcnt++] = "-isystem"; + asprintf(cc_argv+(argcnt++), "%s/c++/include", devprefix); + } + + cc_argv[argcnt++] = "-isystem"; + asprintf(cc_argv+(argcnt++), "%s/include", devprefix); + cc_argv[argcnt++] = "-isystem"; + asprintf(cc_argv+(argcnt++), "%s/cc/include", devprefix); + } + + cc_argv[argcnt++] = "-U__nptl__"; + + if (linking && source_count) { + + if (profile) + asprintf(cc_argv+(argcnt++), "%s/lib/gcrt1.o", devprefix); + + if (ctor_dtor) { + asprintf(cc_argv+(argcnt++), "%s/lib/crti.o", devprefix); + cc_argv[argcnt++]=find_TSpath("%s/cc/lib/crtbegin%s", + use_shared, use_static_linking); + } + if (use_start && !profile) + asprintf(cc_argv+(argcnt++), "%s/lib/%scrt1.o", devprefix, use_shared ? "S" : ""); + + // Add remaining unclaimed arguments. + + for (i=1; i<argc; i++) if (argv[i]) cc_argv[argcnt++] = argv[i]; + + if (used_x) cc_argv[argcnt++] = "-xnone"; + + // Add standard libraries + + if (use_stdlib) { + if (cpp) { + cc_argv[argcnt++] = "-lstdc++"; + cc_argv[argcnt++] = "-lm"; + } + + // libgcc can call libc which can call libgcc + + cc_argv[argcnt++] = "-Wl,--start-group,--as-needed"; + cc_argv[argcnt++] = "-lgcc"; + if (!use_static_linking && use_shared_libgcc) + cc_argv[argcnt++] = "-lgcc_s"; + else cc_argv[argcnt++] = "-lgcc_eh"; + cc_argv[argcnt++] = "-lc"; + cc_argv[argcnt++] = "-Wl,--no-as-needed,--end-group"; + } + if (ctor_dtor) { + cc_argv[argcnt++] = find_TSpath("%s/cc/lib/crtend%s", use_shared, 0); + asprintf(cc_argv+(argcnt++), "%s/lib/crtn.o", devprefix); + } + } else for (i=1; i<argc; i++) if (argv[i]) cc_argv[argcnt++] = argv[i]; + + cc_argv[argcnt++] = NULL; + + if (verbose) { + for (i=0; cc_argv[i]; i++) printf("arg[%2i] = %s\n", i, cc_argv[i]); + fflush(stdout); + } + + if (debug_wrapper) { + fprintf(stderr, "outgoing: "); + for (i=0; cc_argv[i]; i++) fprintf(stderr, "%s ",cc_argv[i]); + fprintf(stderr, "\n\n"); + } + + execvp(cc_argv[0], cc_argv); + fprintf(stderr, "%s: %s\n", cpp ? cpp : cc, strerror(errno)); + exit(EXIT_FAILURE); +}
--- a/sources/toys/ccwrap2.c Mon Jun 23 06:01:02 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,459 +0,0 @@ -/* Copyright 2013 Rob Landley <rob@landley.net> - * - * C compiler wrapper. Parses command line, supplies path information for - * headers and libraries. - */ - -#undef _FORTIFY_SOURCE - -#include <libgen.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -// Default to musl -#ifndef DYNAMIC_LINKER -#define DYNAMIC_LINKER "/lib/libc.so" -#endif - -// Some plumbing from toybox - -void *xmalloc(long len) -{ - void *ret = malloc(len); - - if (!ret) { - fprintf(stderr, "bad malloc\n"); - exit(1); - } -} - -// Die unless we can allocate enough space to sprintf() into. -char *xmprintf(char *format, ...) -{ - va_list va, va2; - int len; - char *ret; - - va_start(va, format); - va_copy(va2, va); - - // How long is it? - len = vsnprintf(0, 0, format, va); - len++; - va_end(va); - - // Allocate and do the sprintf() - ret = xmalloc(len); - vsnprintf(ret, len, format, va2); - va_end(va2); - - return ret; -} - -// Confirm that a regular file exists, and (optionally) has the executable bit. -int is_file(char *filename, int has_exe) -{ - // Confirm it has the executable bit set, if necessary. - if (!has_exe || !access(filename, X_OK)) { - struct stat st; - - // Confirm it exists and is not a directory. - if (!stat(filename, &st) && S_ISREG(st.st_mode)) return 1; - } - return 0; -} - -// Find a file in a colon-separated path -char *find_in_path(char *path, char *filename, int has_exe) -{ - char *cwd = getcwd(0, 0); - - if (index(filename, '/') && is_file(filename, has_exe)) - return realpath(filename, 0); - - while (path) { - char *str, *next = path ? index(path, ':') : 0; - int len = next ? next-path : strlen(path); - - if (!len) str = xmprintf("%s/%s", cwd, filename); - else str = xmprintf("%*s/%s", len, path, filename); - - // If it's not a directory, return it. - if (is_file(str, has_exe)) { - char *s = realpath(str, 0); - - free(str); - free(cwd); - - return s; - } else free(str); - - if (next) next++; - path = next; - } - free(cwd); - - return NULL; -} - -struct dlist { - struct dlist *next, *prev; - char *str; -}; - -// Append to end of doubly linked list (in-order insertion) -void dlist_add(struct dlist **list, char *str) -{ - struct dlist *new = xmalloc(sizeof(struct dlist)); - - new->str = str; - if (*list) { - new->next = *list; - new->prev = (*list)->prev; - (*list)->prev->next = new; - (*list)->prev = new; - } else *list = new->next = new->prev = new; - - *list = new; -} - -// Some compiler versions don't provide separate T and S versions of begin/end, -// so fall back to the base version if they're not there. - -char *find_TSpath(char *base, char *top, int use_shared, int use_static_linking) -{ - int i; - char *temp; - - temp = xmprintf(base, top, - use_shared ? "S.o" : use_static_linking ? "T.o" : ".o"); - - if (!is_file(temp, 0)) { - free(temp); - temp = xmprintf(base, top, ".o"); - } - - return temp; -} - - -enum { - Clibccso, Clink, Cprofile, Cshared, Cstart, Cstatic, Cstdinc, Cstdlib, - Cverbose, Cx, Cdashdash, - - CPctordtor, CP, CPstdinc -}; - -#define MASK_BIT(X) (1<<X) -#define SET_FLAG(X) (flags |= MASK_BIT(X)) -#define CLEAR_FLAG(X) (flags &= ~MASK_BIT(X)) -#define GET_FLAG(X) (flags & MASK_BIT(X)) - -// Read the command line arguments and work out status -int main(int argc, char *argv[]) -{ - char *topdir, *ccprefix, *dynlink, *cc, *temp, **keepv, **hdr, **outv; - int i, keepc, srcfiles, flags, outc; - struct dlist *libs = 0; - - keepv = xmalloc(argc*sizeof(char *)); - flags = MASK_BIT(Clink)|MASK_BIT(Cstart)|MASK_BIT(Cstdinc)|MASK_BIT(Cstdlib) - |MASK_BIT(CPctordtor); - keepc = srcfiles = 0; - - if (getenv("CCWRAP_DEBUG")) { - SET_FLAG(Cverbose); - fprintf(stderr, "incoming: "); - for (i=0; i<argc; i++) fprintf(stderr, "%s ", argv[i]); - fprintf(stderr, "\n\n"); - } - - // Find the cannonical path to the directory containing our executable - topdir = find_in_path(getenv("PATH"), *argv, 1); - if (!topdir || !(temp = rindex(topdir, '/')) || strlen(*argv)<2) { - fprintf(stderr, "Can't find %s in $PATH (did you export it?)\n", *argv); - exit(1); - } - // We want to strip off the bin/ but the path we followed can end with - // a symlink, so append .. instead. - strcpy(++temp, ".."); - - // Add our binary's directory and the tools directory to $PATH so gcc's - // convulsive flailing probably blunders through here first. - // Note: do this before reading topdir from environment variable, because - // toolchain binaries go with wrapper even if headers/libraries don't. - temp = getenv("PATH"); - if (!temp) temp = ""; - temp = xmprintf("PATH=%s/bin:%s/tools/bin:%s", topdir, topdir, temp); - putenv(temp); - - // Override header/library search path with environment variable? - temp = getenv("CCWRAP_TOPDIR"); - if (!temp) { - cc = xmprintf("%sCCWRAP_TOPDIR", ccprefix); - - for (i=0; cc[i]; i++) if (cc[i] == '-') cc[i]='_'; - temp = getenv(cc); - free(cc); - } - if (temp) { - free(topdir); - topdir = temp; - } - - // Name of the C compiler we're wrapping. - cc = getenv("CCWRAP_CC"); - if (!cc) cc = "rawcc"; - - // figure out cross compiler prefix - i = strlen(ccprefix = basename(*argv)); - if (i<2) { - fprintf(stderr, "Bad name '%s'\n", ccprefix); - exit(1); - } - if (!strcmp("++", ccprefix+i-2)) { - cc = "raw++"; - SET_FLAG(CP); - SET_FLAG(CPstdinc); - if (i<3) exit(1); - i -= 3; - } else if (!strcmp("gcc", ccprefix+i-3)) i -= 3; // TODO: yank - else if (!strcmp("cc", ccprefix+i-2)) i-=2; - else if (!strcmp("cpp", ccprefix+i-3)) { - i -= 3; - CLEAR_FLAG(Clink); - } else return 1; // TODO: wrap ld - if (!(ccprefix = strndup(ccprefix, i))) exit(1); - - // Does toolchain have a shared libcc? - temp = xmprintf("%s/lib/libgcc_s.so", topdir); - if (is_file(temp, 0)) SET_FLAG(Clibccso); - free(temp); - - // Where's the dynamic linker? - temp = getenv("CCWRAP_DYNAMIC_LINKER"); - if (!temp) temp = DYNAMIC_LINKER; - dynlink = xmprintf("-Wl,--dynamic-linker,%s", temp); - - // Fallback library search path, these will wind up at the end - dlist_add(&libs, xmprintf("%s/lib", topdir)); - dlist_add(&libs, xmprintf("%s/cc/lib", topdir)); - - // Parse command line arguments - for (i=1; i<argc; i++) { - char *c = keepv[keepc++] = argv[i]; - - if (!strcmp(c, "--")) SET_FLAG(Cdashdash); - - // is this an option? - if (*c == '-' && c[1] && !GET_FLAG(Cdashdash)) c++; - else { - srcfiles++; - continue; - } - - // Second dash? - if (*c == '-') { - // Passthrough double dash versions of single-dash options. - if (!strncmp(c, "-print-", 7) || !strncmp(c, "-static", 7) - || !strncmp(c, "-shared", 7)) c++; - else { - if (!strcmp(c, "-no-ctors")) { - CLEAR_FLAG(CPctordtor); - keepc--; - } - continue; - } - } - - // -M and -MM imply -E and thus no linking. - // Other -M? options don't, including -MMD - if (*c == 'M' && c[1] && (c[1] != 'M' || c[2])) continue; - - // compile, preprocess, assemble... options that suppress linking. - if (strchr("cEMS", *c)) CLEAR_FLAG(Clink); - else if (*c == 'L') { - if (c[1]) dlist_add(&libs, c+1); - else if (!argv[++i]) { - fprintf(stderr, "-L at end of args\n"); - exit(1); - } else dlist_add(&libs, argv[i]); - keepc--; - } else if (*c == 'f') { - if (!strcmp(c, "fprofile-arcs")) SET_FLAG(Cprofile); - } else if (*c == 'n') { - keepc--; - if (!strcmp(c, "nodefaultlibs")) CLEAR_FLAG(Cstdlib); - else if (!strcmp(c, "nostartfiles")) { - CLEAR_FLAG(CPctordtor); - CLEAR_FLAG(Cstart); - } else if (!strcmp(c, "nostdinc")) CLEAR_FLAG(Cstdinc); - else if (!strcmp(c, "nostdinc++")) CLEAR_FLAG(CPstdinc); - else if (!strcmp(c, "nostdlib")) { - CLEAR_FLAG(Cstdlib); - CLEAR_FLAG(Cstart); - CLEAR_FLAG(CPctordtor); - } else keepc++; - } else if (*c == 'p') { - if (!strncmp(c, "print-", 6)) { - struct dlist *dl; - int show = 0; - - // Just add prefix to prog-name - if (!strncmp(c += 6, "prog-name=", 10)) { - printf("%s%s\n", ccprefix, c+10); - exit(0); - } - - if (!strncmp(c, "file-name=", 10)) { - c += 10; - if (!strcmp(c, "include")) { - printf("%s/cc/include\n", topdir); - exit(0); - } - } else if (!strcmp(c, "search-dirs")) { - c = ""; - show = 1; - printf("install: %s/\nprograms: %s\nlibraries:", - topdir, getenv("PATH")); - } else if (!strcmp(c, "libgcc-file-name")) { - printf("%s/cc/lib/libgcc.a\n", topdir); - exit(0); - } - else break; - - // Adjust dlist before traversing (move fallback to end, break circle) - libs = libs->next->next; - libs->prev->next = 0; - - // Either display the list, or find first hit. - for (dl = libs; dl; dl = dl->next) { - if (show) printf(":%s" + (dl==libs), dl->str); - else if (!access(dl->str, F_OK)) break; - } - if (dl) printf("%s", dl->str); - printf("\n"); - - return 0; - } else if (!strcmp(c, "pg")) SET_FLAG(Cprofile); - } else if (*c == 's') { - keepc--; - if (!strcmp(c, "shared")) { - CLEAR_FLAG(Cstart); - SET_FLAG(Cshared); - } else if (!strcmp(c, "static")) { - SET_FLAG(Cstatic); - CLEAR_FLAG(Clibccso); - } else if (!strcmp(c, "shared-libgcc")) SET_FLAG(Clibccso); - else if (!strcmp(c, "static-libgcc")) CLEAR_FLAG(Clibccso); - else keepc++; - } else if (*c == 'v' && !c[1]) { - SET_FLAG(Cverbose); - printf("ccwrap: %s\n", topdir); - } else if (!strncmp(c, "Wl,", 3)) { - temp = strstr(c, ",-static"); - if (temp && (!temp[8] || temp[8]==',')) { - SET_FLAG(Cstatic); - CLEAR_FLAG(Clibccso); - } - // This argument specifies dynamic linker, so we shouldn't. - if (strstr(c, "--dynamic-linker")) dynlink = 0; - } else if (*c == 'x') SET_FLAG(Cx); - } - - // Initialize argument list for exec call - -// what's a good outc size? - - outc = (argc+keepc+64)*sizeof(char *); - memset(outv = xmalloc(outc), 0, outc); - outc = 0; - outv[outc++] = cc; - - // Are we linking? - if (srcfiles) { - outv[outc++] = "-nostdinc"; - if (GET_FLAG(CP)) { - outv[outc++] = "-nostdinc++"; - if (GET_FLAG(CPstdinc)) { - outv[outc++] = "-isystem"; - outv[outc++] = xmprintf("%s/c++/include", topdir); - } - } - if (GET_FLAG(Cstdinc)) { - outv[outc++] = "-isystem"; - outv[outc++] = xmprintf("%s/include", topdir); - outv[outc++] = "-isystem"; - outv[outc++] = xmprintf("%s/cc/include", topdir); - } - if (GET_FLAG(Clink)) { - // Zab defaults, add dynamic linker - outv[outc++] = "-nostdlib"; - outv[outc++] = GET_FLAG(Cstatic) ? "-static" : dynlink; - if (GET_FLAG(Cshared)) outv[outc++] = "-shared"; - - // Copy libraries to output (first move fallback to end, break circle) - libs = libs->next->next; - libs->prev->next = 0; - for (; libs; libs = libs->next) - outv[outc++] = xmprintf("-L%s", libs->str); - outv[outc++] = xmprintf("-Wl,-rpath-link,%s/lib", topdir); // TODO: in? - - // TODO: -fprofile-arcs - if (GET_FLAG(Cprofile)) xmprintf("%s/lib/gcrt1.o", topdir); - if (GET_FLAG(CPctordtor)) { - outv[outc++] = xmprintf("%s/lib/crti.o", topdir); - outv[outc++] = find_TSpath("%s/cc/lib/crtbegin%s", topdir, - GET_FLAG(Cshared), GET_FLAG(Cstatic)); - } - if (!GET_FLAG(Cprofile) && GET_FLAG(Cstart)) - outv[outc++] = xmprintf("%s/lib/%scrt1.o", topdir, - GET_FLAG(Cshared) ? "S" : ""); - } - } - - // Copy unclaimed arguments - memcpy(outv+outc, keepv, keepc*sizeof(char *)); - outc += keepc; - - if (srcfiles && GET_FLAG(Clink)) { - if (GET_FLAG(Cx)) outv[outc++] = "-xnone"; - if (GET_FLAG(Cstdlib)) { - if (GET_FLAG(CP)) { - outv[outc++] = "-lstdc++"; - //outv[outc++] = "-lm"; - } - - // libgcc can call libc which can call libgcc - outv[outc++] = "-Wl,--start-group,--as-needed"; - outv[outc++] = "-lgcc"; - if (GET_FLAG(Clibccso)) outv[outc++] = "-lgcc_s"; - else outv[outc++] = "-lgcc_eh"; - outv[outc++] = "-lc"; - outv[outc++] = "-Wl,--no-as-needed,--end-group"; - } - if (GET_FLAG(CPctordtor)) { - outv[outc++] = find_TSpath("%s/cc/lib/crtend%s", topdir, - GET_FLAG(Cshared), GET_FLAG(Cstatic)); - outv[outc++] = xmprintf("%s/lib/crtn.o", topdir); - } - } - outv[outc] = 0; - - if (getenv("CCWRAP_DEBUG")) { - fprintf(stderr, "outgoing:"); - for(i=0; i<outc; i++) printf(stderr, " \"%s\"", outv[i]); - fprintf(stderr, "\n"); - } - - execvp(*outv, outv); - fprintf(stderr, "%s: %s\n", *outv, strerror(errno)); - exit(1); - - return 0; -}