changeset 13:d34028ce8602

A version of the old uClibc wrapper script, which Chris Faylor maintained for timesys after uClibc dropped it, and then I gave it a quick cleanup (mostly #ifdef removal).
author Rob Landley <rob@landley.net>
date Sat, 02 Dec 2006 13:18:58 -0500
parents bed493dc4358
children 8b4600334a3d
files sources/toys/gcc-uClibc.c
diffstat 1 files changed, 573 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sources/toys/gcc-uClibc.c	Sat Dec 02 13:18:58 2006 -0500
@@ -0,0 +1,573 @@
+/* vi: set ts=4 :*/
+/*
+ * Copyright (C) 2000 Manuel Novoa III
+ * Copyright (C) 2002-2003 Erik Andersen
+ *
+ * Wrapper to use uClibc with gcc, and make gcc relocatable.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+static char *topdir;
+const char *mypath;
+const char *application_name;
+static char static_linking[] = "-static";
+static char nostdinc[] = "-nostdinc";
+static char nostartfiles[] = "-nostartfiles";
+static char nodefaultlibs[] = "-nodefaultlibs";
+static char nostdlib[] = "-nostdlib";
+
+// For C++
+static char nostdinc_plus[] = "-nostdinc++";
+
+
+char *dirname(char *path)
+{
+	static const char null_or_empty_or_noslash[] = ".";
+	register char *s;
+	register char *last;
+	char *first;
+
+	last = s = path;
+
+	if (s != NULL) {
+
+LOOP:
+		while (*s && (*s != '/')) ++s;
+		first = s;
+		while (*s == '/') ++s;
+		if (*s) {
+			last = first;
+			goto LOOP;
+		}
+
+		if (last == path) {
+			if (*last != '/') {
+				goto DOT;
+			}
+			if ((*++last == '/') && (last[1] == 0)) {
+				++last;
+			}
+		}
+		*last = 0;
+		return path;
+	}
+DOT:
+	return (char *) null_or_empty_or_noslash;
+}
+
+static int myexecvp(const char *path, char *argv[])
+{
+	int res;
+	const char *runpath;
+	if (strchr(path, '/'))
+		runpath = path;
+	else {
+		static char buf[8192];
+		strcpy(buf, mypath);
+		if (strchr(mypath, '\0')[-1] != '/')
+			  strcat(buf, "/");
+		strcat(buf, path);
+		runpath = buf;
+		argv[0] = buf;
+	}
+	res = execvp(runpath, argv);
+	if (runpath != path) {
+		argv[0] = (char *) runpath;
+		res = execvp(path, argv);
+	}
+	return res;
+}
+
+static void finddirs()
+{
+    char *here;
+    char **av;
+    static char *dirs[] = {
+	    "../" TARGET_DIR "/lib",
+	    "../lib", NULL
+    };
+    here = getcwd (NULL, 0);
+    for (av = dirs; *av; av++) {
+        chdir (mypath);
+	if (chdir (*av) == 0 && access ("ld-uClibc.so.0", F_OK) == 0) {
+		chdir ("..");
+		topdir = getcwd (NULL, 0);
+		break;
+	}
+    }
+    chdir (here);
+    free (here);
+    if (!topdir) {
+	    fprintf (stderr, "%s: unable to find uClibc headers and libraries relative to '%s'\n",
+		     application_name, mypath);
+	    exit (1);
+    }
+}
+
+extern void *xmalloc(size_t size)
+{
+	void *ptr = malloc(size);
+
+	if (!ptr) {
+		fprintf(stderr, "memory exhausted");
+		exit(EXIT_FAILURE);
+	}
+	return ptr;
+}
+
+void xstrcat(char **string, ...)
+{
+	const char *c;
+	va_list p; 
+	/* Don't bother to calculate how big exerything 
+	 * will be, just be careful to not overflow...  */
+	va_start(p, string);
+	*string = xmalloc(BUFSIZ);
+	**string = '\0';
+	while(1) {
+		if (!(c = va_arg(p, const char *)))
+			break;
+		strcat(*string, c); 
+	}
+	va_end(p);
+}
+
+int main(int argc, char **argv)
+{
+	int use_build_dir = 0, linking = 1, use_static_linking = 0;
+	int use_stdinc = 1, use_start = 1, use_stdlib = 1, use_pic = 0;
+	int source_count = 0, use_rpath = 0, verbose = 0;
+	int i, j, k, l, m, n;
+	int sawM = 0;
+	int sawdotoa = 0;
+	int sawcES = 0;
+	char ** gcc_argv;
+	char ** gcc_argument;
+	char ** libraries;
+	char ** libpath;
+	char *dlstr;
+	char *incstr;
+	char *devprefix;
+	char *libstr;
+	char *build_dlstr = 0;
+	char *cc;
+	char *ep;
+	char *rpath_link[2];
+	char *rpath[2];
+	char *uClibc_inc[2];
+	char *our_lib_path[2];
+	char *crt0_path[2];
+	char *crtbegin_path[2];
+	char *crtend_path[2];
+
+	// For C++
+
+	char *crti_path[2];
+	char *crtn_path[2];
+	int len;
+	int ctor_dtor = 1, cplusplus = 0, use_nostdinc_plus = 0;
+	char *cpp = NULL;
+
+	// For profiling
+	int profile = 0;
+	char *gcrt1_path[2];
+
+	cc = getenv("UCLIBC_CC");
+	if (!cc) cc = GCC_BIN;
+
+	char *argvwork = strdup(argv[0]);
+	application_name = strdup(argvwork);
+	mypath = dirname(argvwork);
+	if (strcmp (mypath, ".") == 0) {
+		int n = 4096;
+		char *buf;
+		while (1) {
+			buf = calloc (1, n);
+			if (readlink ("/proc/self/exe", buf, n) < 0)
+				break;
+			if (buf[n - 1] == '\0') {
+				mypath = strdup(dirname(buf));
+				char *p = strstr (mypath, "/" TARGET_DIR);
+				if (p)
+					strcpy (p, "/bin");
+				break;
+			}
+			free(buf);
+			n *= 2;
+		}
+	}
+	finddirs();
+
+	if (application_name[0] == '-')
+		application_name++;
+
+	/* We must use strstr since g++ might be named like a
+	 * cross compiler (i.e. arm-linux-g++).   We must also
+	 * search carefully, in case we are searching something 
+	 * like /opt/c++/gcc-3.1/bin/arm-linux-g++ or some similar 
+	 * perversion...  */
+	len = strlen(application_name);
+	if ((strcmp(application_name+len-3, "g++")==0) ||
+			(strcmp(application_name+len-3, "c++")==0)) {
+		len = strlen(cc);
+		if (strcmp(cc+len-3, "gcc")==0) {
+			cpp = strdup(cc);
+			cpp[len-1]='+';
+			cpp[len-2]='+';
+		}
+		cplusplus = 1;
+		use_nostdinc_plus = 1;
+	}
+
+	devprefix = getenv("UCLIBC_DEVEL_PREFIX");
+	if (!devprefix) {
+		devprefix = topdir;
+	}
+
+	incstr = getenv("UCLIBC_GCC_INC");
+	libstr = getenv("UCLIBC_GCC_LIB");
+
+	ep     = getenv("UCLIBC_ENV");
+	if (!ep) {
+		ep = "";
+	}
+
+	if (strstr(ep,"build") != 0) {
+		use_build_dir = 1;
+	}
+
+	if (strstr(ep,"rpath") != 0) {
+		use_rpath = 1;
+	}
+
+
+	xstrcat(&(rpath_link[0]), "-Wl,-rpath-link,", devprefix, "/lib", NULL);
+
+	xstrcat(&(rpath[0]), "-Wl,-rpath,", devprefix, "/lib", NULL);
+
+	xstrcat(&(uClibc_inc[0]), devprefix, "/include/", NULL);
+
+//#ifdef CTOR_DTOR
+	xstrcat(&(crt0_path[0]), devprefix, "/lib/crt1.o", NULL);
+	xstrcat(&(crti_path[0]), devprefix, "/lib/crti.o", NULL);
+	xstrcat(&(crtn_path[0]), devprefix, "/lib/crtn.o", NULL);
+//#else
+//	xstrcat(&(crt0_path[0]), devprefix, "/lib/crt0.o", NULL);
+//#endif
+
+	// profiling
+	xstrcat(&(gcrt1_path[0]), devprefix, "/lib/gcrt1.o", NULL);
+
+	xstrcat(&(our_lib_path[0]), "-L", devprefix, "/lib", NULL);
+
+	// Figure out where the dynamic linker is.
+	dlstr = getenv("UCLIBC_GCC_DLOPT");
+	if (!dlstr) {
+		dlstr = "-Wl,--dynamic-linker," DYNAMIC_LINKER;
+	}
+
+	m = 0;
+	libraries = __builtin_alloca(sizeof(char*) * (argc));
+	libraries[m] = '\0';
+
+	n = 0;
+	libpath = __builtin_alloca(sizeof(char*) * (argc));
+	libpath[n] = '\0';
+
+	for ( i = 1 ; i < argc ; i++ ) {
+		if (argv[i][0] == '-' && argv[i][1]) { /* option */
+			switch (argv[i][1]) {
+				case 'c':		/* compile or assemble */
+				case 'S':		/* generate assembler code */
+				case 'E':		/* preprocess only */
+				case 'M':	    /* generate dependencies */
+					linking = 0;
+					if (argv[i][1] == 'M')
+						  sawM = 1;
+					else
+						  sawcES = 1;
+					break;
+				case 'L': 		/* library */
+					libpath[n++] = argv[i];
+					libpath[n] = '\0';
+					if (argv[i][2] == 0) {
+						argv[i] = '\0';
+						libpath[n++] = argv[++i];
+						libpath[n] = '\0';
+					}
+					argv[i] = '\0';
+					break;
+				case 'l': 		/* library */
+					libraries[m++] = argv[i];
+					libraries[m] = '\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", mypath);
+					break;
+				case 'n':
+					if (strcmp(nostdinc,argv[i]) == 0) {
+						use_stdinc = 0;
+					} else if (strcmp(nostartfiles,argv[i]) == 0) {
+						ctor_dtor = 0;
+						use_start = 0;
+					} else if (strcmp(nodefaultlibs,argv[i]) == 0) {
+						use_stdlib = 0;
+						argv[i] = '\0';
+					} else if (strcmp(nostdlib,argv[i]) == 0) {
+						ctor_dtor = 0;
+						use_start = 0;
+						use_stdlib = 0;
+					} else if (strcmp(nostdinc_plus,argv[i]) == 0) {
+						if (cplusplus==1) {
+							use_nostdinc_plus = 0;
+						}
+					}
+					break;
+				case 's':
+					if (strstr(argv[i],static_linking) != NULL) {
+						use_static_linking = 1;
+					}
+					if (strcmp("-shared",argv[i]) == 0) {
+						use_start = 0;
+						use_pic = 1;
+					}
+					break;
+				case 'W':		/* -static could be passed directly to ld */
+					if (strncmp("-Wl,",argv[i],4) == 0) {
+						if (strstr(argv[i],static_linking) != 0) {
+							use_static_linking = 1;
+						}
+						if (strstr(argv[i],"--dynamic-linker") != 0) {
+							dlstr = 0;
+						}
+					}
+					break;
+
+				// Profiling.
+
+				case 'p':
+					if (strcmp("-pg",argv[i]) == 0) {
+						profile = 1;
+					}
+					break;
+				case 'f':
+					/* Check if we are doing PIC */
+					if (strcmp("-fPIC",argv[i]) == 0) {
+						use_pic = 1;
+					} else if (strcmp("-fpic",argv[i]) == 0) {
+						use_pic = 1;
+ 
+					// profiling
+					} else if (strcmp("-fprofile-arcs",argv[i]) == 0) {
+						profile = 1;
+					}
+					break;
+
+				case '-':
+					if (strstr(argv[i]+1,static_linking) != NULL) {
+						use_static_linking = 1;
+						argv[i]='\0';
+					} else if (strcmp("--version",argv[i]) == 0) {
+						printf("uClibc ");
+						fflush(stdout);
+						break;
+					} else if (strcmp("--uclibc-use-build-dir",argv[i]) == 0) {
+						use_build_dir = 1;
+						argv[i]='\0';
+					} else if (strcmp("--uclibc-use-rpath",argv[i]) == 0) {
+						use_rpath = 1;
+						argv[i]='\0';
+					} else if (strcmp ("--uclibc-cc", argv[i]) == 0 && argv[i + 1]) {
+						cc = argv[i + 1];
+						argv[i] = 0;
+						argv[i + 1] = 0;
+					} else if (strncmp ("--uclibc-cc=", argv[i], 12) == 0) {
+						cc = argv[i] + 12;
+						argv[i] = 0;
+					} else if (strcmp("--uclibc-no-ctors",argv[i]) == 0) {
+						ctor_dtor = 0;
+						argv[i]='\0';
+					}
+					break;
+			}
+		} else {				/* assume it is an existing source file */
+			char *p = strchr (argv[i], '\0') - 2;
+			if (p > argv[i] && sawM && (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0))
+				  sawdotoa = 1;
+			++source_count;
+		}
+	}
+
+	if (sawdotoa && sawM && !sawcES)
+		  linking = 1;
+
+	gcc_argv = __builtin_alloca(sizeof(char*) * (argc + 128));
+	gcc_argument = __builtin_alloca(sizeof(char*) * (argc + 20));
+
+	i = 0; k = 0;
+	if (ctor_dtor) {
+		xstrcat(&(crtbegin_path[0]), devprefix, "/lib/crtbegin.o", NULL);
+		xstrcat(&(crtbegin_path[1]), devprefix, "/lib/crtbeginS.o", NULL);
+		xstrcat(&(crtend_path[0]), devprefix, "/lib/crtend.o", NULL);
+		xstrcat(&(crtend_path[1]), devprefix, "/lib/crtendS.o", NULL);
+	}
+
+	if (cplusplus && cpp)
+		gcc_argv[i++] = cpp;
+	else
+		gcc_argv[i++] = cc;
+
+	if (EXTRAGCCFLAGS) gcc_argv[i++] = EXTRAGCCFLAGS;
+
+	for ( j = 1 ; j < argc ; j++ ) {
+		if (argv[j]=='\0') {
+			continue;
+		} else {
+			gcc_argument[k++] = argv[j];
+			gcc_argument[k] = '\0';
+		}
+	}
+
+	if (cplusplus)
+		gcc_argv[i++] = "-fno-use-cxa-atexit";
+
+	if (linking && source_count) {
+//#if defined HAS_ELF && ! defined HAS_MMU
+//		gcc_argv[i++] = "-Wl,-elf2flt";
+//#endif
+		gcc_argv[i++] = nostdlib;
+		if (use_static_linking) {
+			gcc_argv[i++] = static_linking;
+		}
+		if (!use_static_linking) {
+			if (dlstr && use_build_dir) {
+				gcc_argv[i++] = build_dlstr;
+			} else if (dlstr) {
+				gcc_argv[i++] = dlstr;
+			}
+			if (use_rpath) {
+				gcc_argv[i++] = rpath[use_build_dir];
+			}
+		}
+		for ( l = 0 ; l < n ; l++ ) {
+			if (libpath[l]) gcc_argv[i++] = libpath[l];
+		}
+		gcc_argv[i++] = rpath_link[use_build_dir]; /* just to be safe */
+		if( libstr )
+			gcc_argv[i++] = libstr;
+		gcc_argv[i++] = our_lib_path[use_build_dir];
+		if (!use_build_dir) {
+			xstrcat(&(gcc_argv[i++]), "-L", devprefix, "/lib", NULL);
+		}
+	}
+	if (use_stdinc && source_count) {
+		gcc_argv[i++] = nostdinc;
+
+		if (cplusplus) {
+			char *cppinc;
+			if (use_nostdinc_plus) {
+				gcc_argv[i++] = nostdinc_plus;
+			}
+			xstrcat(&cppinc, uClibc_inc[use_build_dir], "c++/4.1.1", NULL);
+			gcc_argv[i++] = "-isystem";
+			gcc_argv[i++] = cppinc;
+			xstrcat(&cppinc, uClibc_inc[use_build_dir], "c++/4.1.1/" TARGET_DIR, NULL);
+			gcc_argv[i++] = "-isystem";
+			gcc_argv[i++] = cppinc;
+			xstrcat(&cppinc, uClibc_inc[use_build_dir], "c++/4.1.1", NULL);
+			gcc_argv[i++] = "-isystem";
+			gcc_argv[i++] = cppinc;
+		}
+
+		gcc_argv[i++] = "-isystem";
+		gcc_argv[i++] = uClibc_inc[use_build_dir];
+		gcc_argv[i++] = "-iwithprefix";
+		gcc_argv[i++] = "include";
+		if( incstr )
+			gcc_argv[i++] = incstr;
+	}
+
+    gcc_argv[i++] = "-U__nptl__";
+
+	if (linking && source_count) {
+
+		if (profile) {
+			gcc_argv[i++] = gcrt1_path[use_build_dir];
+		}
+		if (ctor_dtor) {
+			gcc_argv[i++] = crti_path[use_build_dir];
+			if (use_pic) {
+				gcc_argv[i++] = crtbegin_path[1];
+			} else {
+				gcc_argv[i++] = crtbegin_path[0];
+			}
+		}
+		if (use_start) {
+			if (!profile) {
+				gcc_argv[i++] = crt0_path[use_build_dir];
+			}
+		}
+		for ( l = 0 ; l < k ; l++ ) {
+			if (gcc_argument[l]) gcc_argv[i++] = gcc_argument[l];
+		}
+		if (use_stdlib) {
+			//gcc_argv[i++] = "-Wl,--start-group";
+			gcc_argv[i++] = "-lgcc";
+			gcc_argv[i++] = "-lgcc_eh";
+		}
+		for ( l = 0 ; l < m ; l++ ) {
+			if (libraries[l]) gcc_argv[i++] = libraries[l];
+		}
+		if (use_stdlib) {
+			if (cplusplus) {
+				gcc_argv[ i++ ] = "-lstdc++";
+				gcc_argv[ i++ ] = "-lm";
+			}
+			gcc_argv[i++] = "-lc";
+			gcc_argv[i++] = "-lgcc";
+			gcc_argv[i++] = "-lgcc_eh";
+			//gcc_argv[i++] = "-Wl,--end-group";
+		}
+		if (ctor_dtor) {
+			if (use_pic) {
+				gcc_argv[i++] = crtend_path[1];
+			} else {
+				gcc_argv[i++] = crtend_path[0];
+			}
+
+			gcc_argv[i++] = crtn_path[use_build_dir];
+		}
+	} else {
+		for ( l = 0 ; l < k ; l++ ) {
+			if (gcc_argument[l]) gcc_argv[i++] = gcc_argument[l];
+		}
+	}
+	gcc_argv[i++] = NULL;
+
+	if (verbose) {
+		for ( j = 0 ; gcc_argv[j] ; j++ ) {
+			printf("arg[%2i] = %s\n", j, gcc_argv[j]);
+		}
+		fflush(stdout);
+	}
+	//no need to free memory from xstrcat because we never return... 
+	if (cplusplus && cpp) {
+		myexecvp(cpp, gcc_argv);
+		fprintf(stderr, "%s: %s\n", cpp, strerror(errno));
+	} else {
+		myexecvp(cc, gcc_argv);
+		fprintf(stderr, "%s: %s\n", cc, strerror(errno));
+	}
+	exit(EXIT_FAILURE);
+}