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;
-}