1 /* vi: set sw=4 ts=4: */
3 * Copyright (C) 2000 Manuel Novoa III
4 * Copyright (C) 2002-2003 Erik Andersen
6 * This is a crude wrapper to use uClibc with gcc.
7 * It was originally written to work around ./configure for ext2fs-utils.
8 * It certainly can be improved, but it works for me in the normal cases.
12 * A bug was fixed in building the gcc command line when dynamic linking.
13 * The functions dlopen, etc. now work. At this time, you must make sure
14 * the correct libdl.so is included however. It is safest to, for example,
15 * add /lib/libdl.so.1 if using ld-linux.so.1 rather than adding -ldl to the
18 * Note: This is only a problem if devel and target archs are the same. To
19 * avoid the problem, you can use a customized dynamic linker.
24 * The wrapper now works with either installed and uninstalled uClibc versions.
25 * If you want to use the uninstalled header files and libs, either include
26 * the string "build" in the invocation name such as
27 * 'ln -s <ARCH>-uclibc-gcc <ARCH>-uclibc-gcc-build'
28 * or include it in the environment variable setting of UCLIBC_ENV.
29 * Note: This automatically enables the "rpath" behavior described below.
31 * The wrapper will now pass the location of the uClibc shared libs used to
32 * the linker with the "-rpath" option if the invocation name includes the
33 * string "rpath" or if the environment variable UCLIBC_ENV include it (as
34 * with "build" above). This is primarily intended to be used on devel
35 * platforms of the same arch as the target. A good place to use this feature
36 * would be in the uClibc/test directory.
38 * The wrapper now displays the command line passed to gcc when '-v' is used.
42 * "rpath" and "build" behavior are now decoupled. You can of course get
43 * the old "build" behavior by setting UCLIBC_ENV="rpath-build". Order
44 * isn't important here, as only the substrings are searched for.
46 * Added environment variable check for UCLIBC_GCC_DLOPT to let user specify
47 * an alternative dynamic linker at runtime without using command line args.
48 * Since this wouldn't commonly be used, I made it easy on myself. You have
49 * to match the option you would have passed to the gcc wrapper. As an
52 * export UCLIBC_GCC_DLOPT="-Wl,--dynamic-linker,/lib/ld-alt-linker.so.3"
54 * This is really only useful if target arch == devel arch and DEVEL_PREFIX
55 * isn't empty. It involves a recompile, but you can at least test apps
56 * on your devel system if combined with the "rpath" behavor if by using
57 * LD_LIBRARY_PATH, etc.
59 * Also added check for "-Wl,--dynamic-linker" on the command line. The
60 * use default dynamic linker or the envirnment-specified dynamic linker
61 * is disabled in that case.
63 * Added options --uclibc-use-build-dir and --uclibc-use-rpath so that those
64 * behaviors can be invoked from the command line.
71 * Check/modify gcc-specific environment variables?
83 #include "gcc-uClibc.h"
85 static char *our_usr_lib_path = "-L"UCLIBC_DEVEL_PREFIX"/lib";
87 static char static_linking[] = "-static";
88 static char nostdinc[] = "-nostdinc";
89 static char nostartfiles[] = "-nostartfiles";
90 static char nodefaultlibs[] = "-nodefaultlibs";
91 static char nostdlib[] = "-nostdlib";
92 #ifdef __UCLIBC_CTOR_DTOR__
93 static char nostdinc_plus[] = "-nostdinc++";
96 /* Include a local implementation of basename, since this
97 * uses the host system's C lib, and CYGWIN apparently
98 * doesn't provide an implementation of basename(). */
99 char *basename(const char *path)
101 register const char *s;
102 register const char *p;
112 char *dirname(char *path)
114 static const char null_or_empty_or_noslash[] = ".";
124 while (*s && (*s != '/')) ++s;
126 while (*s == '/') ++s;
136 if ((*++last == '/') && (last[1] == '\0')) {
144 return (char *) null_or_empty_or_noslash;
148 extern void *xmalloc(size_t size)
150 void *ptr = malloc(size);
153 fprintf(stderr, "memory exhausted");
159 void xstrcat(char **string, ...)
163 /* Don't bother to calculate how big exerything
164 * will be, just be careful to not overflow... */
166 *string = xmalloc(BUFSIZ);
168 while ((c = va_arg(p, const char *))) {
174 int main(int argc, char **argv)
176 int use_build_dir = 0, linking = 1, use_static_linking = 0;
177 int use_stdinc = 1, use_start = 1, use_stdlib = 1, use_pic = 0;
178 int source_count = 0, use_rpath = 0, verbose = 0;
180 int i, j, k, l, m, n;
182 char ** gcc_argument;
190 char *build_dlstr = NULL;
196 char *our_lib_path[2];
198 char *crtbegin_path[2];
199 char *crtend_path[2];
200 const char *application_name;
201 #ifdef __UCLIBC_CTOR_DTOR__
205 int ctor_dtor = 1, cplusplus = 0, use_nostdinc_plus = 0;
209 #ifdef __UCLIBC_PROFILING__
214 cc = getenv("UCLIBC_CC");
217 #ifdef __UCLIBC_CTOR_DTOR__
222 application_name = basename(argv[0]);
223 if (application_name[0] == '-')
226 #ifdef __UCLIBC_CTOR_DTOR__
227 /* We must use strstr since g++ might be named like a
228 * cross compiler (i.e. arm-linux-g++). We must also
229 * search carefully, in case we are searching something
230 * like /opt/c++/gcc-3.1/bin/arm-linux-g++ or some similar
232 len = strlen(application_name);
233 if ((strcmp(application_name+len-3, "g++") == 0) ||
234 (strcmp(application_name+len-3, "c++") == 0)) {
236 if (strcmp(cc+len-3, "gcc") == 0) {
242 use_nostdinc_plus = 1;
246 devprefix = getenv("UCLIBC_DEVEL_PREFIX");
248 devprefix = UCLIBC_DEVEL_PREFIX;
251 builddir = getenv("UCLIBC_BUILD_DIR");
253 builddir = UCLIBC_BUILD_DIR;
256 incstr = getenv("UCLIBC_GCC_INC");
257 libstr = getenv("UCLIBC_GCC_LIB");
259 ep = getenv("UCLIBC_ENV");
264 if (strstr(ep,"build") != NULL) {
268 if (strstr(ep,"rpath") != NULL) {
273 xstrcat(&(rpath_link[0]), "-Wl,-rpath-link,", devprefix, "/lib", NULL);
274 xstrcat(&(rpath_link[1]), "-Wl,-rpath-link,", builddir, "/lib", NULL);
276 xstrcat(&(rpath[0]), "-Wl,-rpath,", devprefix, "/lib", NULL);
277 xstrcat(&(rpath[1]), "-Wl,-rpath,", builddir, "/lib", NULL);
279 xstrcat(&(uClibc_inc[0]), devprefix, "/include/", NULL);
280 xstrcat(&(uClibc_inc[1]), builddir, "/include/", NULL);
282 #ifdef __UCLIBC_CTOR_DTOR__
283 xstrcat(&(crt0_path[0]), devprefix, "/lib/crt1.o", NULL);
284 xstrcat(&(crt0_path[1]), builddir, "/lib/crt1.o", NULL);
285 xstrcat(&(crti_path[0]), devprefix, "/lib/crti.o", NULL);
286 xstrcat(&(crti_path[1]), builddir, "/lib/crti.o", NULL);
287 xstrcat(&(crtn_path[0]), devprefix, "/lib/crtn.o", NULL);
288 xstrcat(&(crtn_path[1]), builddir, "/lib/crtn.o", NULL);
290 xstrcat(&(crt0_path[0]), devprefix, "/lib/crt0.o", NULL);
291 xstrcat(&(crt0_path[1]), builddir, "/lib/crt0.o", NULL);
293 #ifdef __UCLIBC_PROFILING__
294 xstrcat(&(gcrt1_path[0]), devprefix, "/lib/gcrt1.o", NULL);
295 xstrcat(&(gcrt1_path[1]), builddir, "/lib/gcrt1.o", NULL);
298 xstrcat(&(our_lib_path[0]), "-L", devprefix, "/lib", NULL);
299 xstrcat(&(our_lib_path[1]), "-L", builddir, "/lib", NULL);
301 #ifdef __UCLIBC_HAS_SHARED__
302 build_dlstr = "-Wl,--dynamic-linker," BUILD_DYNAMIC_LINKER;
303 dlstr = getenv("UCLIBC_GCC_DLOPT");
305 dlstr = "-Wl,--dynamic-linker," DYNAMIC_LINKER;
310 libraries = __builtin_alloca(sizeof(char*) * (argc));
314 libpath = __builtin_alloca(sizeof(char*) * (argc));
317 for ( i = 1 ; i < argc ; i++ ) {
318 if (argv[i][0] == '-' && argv[i][1] != '\0') { /* option */
319 switch (argv[i][1]) {
320 case 'c': /* compile or assemble */
321 case 'S': /* generate assembler code */
322 case 'E': /* preprocess only */
323 case 'M': /* generate dependencies */
326 case 'L': /* library */
327 libpath[n++] = argv[i];
329 if (argv[i][2] == '\0') {
331 libpath[n++] = argv[++i];
336 case 'l': /* library */
337 libraries[m++] = argv[i];
341 case 'x': /* Set target language */
345 case 'v': /* verbose */
346 if (argv[i][2] == '\0') verbose = 1;
347 printf("Invoked as %s\n", argv[0]);
350 if (strcmp(nostdinc, argv[i]) == 0) {
352 } else if (strcmp(nostartfiles, argv[i]) == 0) {
353 #ifdef __UCLIBC_CTOR_DTOR__
357 } else if (strcmp(nodefaultlibs, argv[i]) == 0) {
360 } else if (strcmp(nostdlib, argv[i]) == 0) {
361 #ifdef __UCLIBC_CTOR_DTOR__
367 #ifdef __UCLIBC_CTOR_DTOR__
368 else if (strcmp(nostdinc_plus, argv[i]) == 0) {
370 use_nostdinc_plus = 0;
376 if (strstr(argv[i], static_linking) != NULL) {
377 use_static_linking = 1;
379 if (strcmp("-shared", argv[i]) == 0) {
384 case 'W': /* -static could be passed directly to ld */
385 if (strncmp("-Wl,", argv[i], 4) == 0) {
386 if (strstr(argv[i], static_linking) != NULL) {
387 use_static_linking = 1;
389 if (strstr(argv[i], "--dynamic-linker") != NULL) {
394 #ifdef __UCLIBC_PROFILING__
396 if (strcmp("-pg", argv[i]) == 0) {
402 /* Check if we are doing PIC */
403 if (strcmp("-fPIC", argv[i]) == 0) {
405 } else if (strcmp("-fpic", argv[i]) == 0) {
408 #ifdef __UCLIBC_PROFILING__
409 else if (strcmp("-fprofile-arcs", argv[i]) == 0) {
416 if (strstr(argv[i]+1, static_linking) != NULL) {
417 use_static_linking = 1;
419 } else if (strcmp("--uclibc-use-build-dir", argv[i]) == 0) {
422 } else if (strcmp("--uclibc-use-rpath", argv[i]) == 0) {
425 } else if (strcmp ("--uclibc-cc", argv[i]) == 0 && argv[i + 1]) {
429 } else if (strncmp ("--uclibc-cc=", argv[i], 12) == 0) {
433 #ifdef __UCLIBC_CTOR_DTOR__
434 else if (strcmp("--uclibc-no-ctors",argv[i]) == 0) {
441 } else if (argv[i][0] == '-' && argv[i][1] == '\0') {
442 /* Reading code from stdin - crazy eh? */
444 } else { /* assume it is an existing source file */
449 gcc_argv = __builtin_alloca(sizeof(char*) * (argc + 64));
450 gcc_argument = __builtin_alloca(sizeof(char*) * (argc + 20));
453 #ifdef __UCLIBC_CTOR_DTOR__
456 if (findlibgcc || stat(LIBGCC_DIR, &statbuf) < 0 ||
457 !S_ISDIR(statbuf.st_mode))
459 /* Bummer, gcc is hiding from us. This is going
460 * to really slow things down... bummer. */
461 int status, gcc_pipe[2];
465 if (!(pid = fork())) {
470 dup2(gcc_pipe[1], 1);
471 dup2(gcc_pipe[1], 2);
473 argv[1] = "-print-libgcc-file-name";
480 while (wpid != pid) {
481 wpid = wait(&status);
484 if (WIFEXITED(status) && WEXITSTATUS(status)) {
486 fprintf(stderr, "Unable to locale crtbegin.o provided by gcc");
489 if (WIFSIGNALED(status)) {
490 fprintf(stderr, "%s exited because of uncaught signal %d", cc, WTERMSIG(status));
495 char buf[1024], *dir;
496 status = read(gcc_pipe[0], buf, sizeof(buf));
502 xstrcat(&(crtbegin_path[0]), dir, "/crtbegin.o", NULL);
503 xstrcat(&(crtbegin_path[1]), dir, "/crtbeginS.o", NULL);
504 xstrcat(&(crtend_path[0]), dir, "/crtend.o", NULL);
505 xstrcat(&(crtend_path[1]), dir, "/crtendS.o", NULL);
509 xstrcat(&(crtbegin_path[0]), LIBGCC_DIR, "crtbegin.o", NULL);
510 xstrcat(&(crtbegin_path[1]), LIBGCC_DIR, "crtbeginS.o", NULL);
511 xstrcat(&(crtend_path[0]), LIBGCC_DIR, "crtend.o", NULL);
512 xstrcat(&(crtend_path[1]), LIBGCC_DIR, "crtendS.o", NULL);
516 if (cplusplus && cpp)
522 for ( j = 1 ; j < argc ; j++ ) {
523 if (argv[j] != NULL) {
524 gcc_argument[k++] = argv[j];
527 gcc_argument[k] = NULL;
529 if (linking && source_count) {
530 #if defined __HAVE_ELF__ && ! defined __UCLIBC_HAS_MMU__
531 gcc_argv[i++] = "-Wl,-elf2flt";
533 gcc_argv[i++] = nostdlib;
534 if (use_static_linking) {
535 gcc_argv[i++] = static_linking;
537 if (!use_static_linking) {
538 if (dlstr && use_build_dir) {
539 gcc_argv[i++] = build_dlstr;
541 gcc_argv[i++] = dlstr;
544 gcc_argv[i++] = rpath[use_build_dir];
547 for ( l = 0 ; l < n ; l++ ) {
548 if (libpath[l]) gcc_argv[i++] = libpath[l];
550 gcc_argv[i++] = rpath_link[use_build_dir]; /* just to be safe */
552 gcc_argv[i++] = libstr;
553 gcc_argv[i++] = our_lib_path[use_build_dir];
554 if (!use_build_dir) {
555 gcc_argv[i++] = our_usr_lib_path;
558 if (use_stdinc && source_count) {
559 gcc_argv[i++] = nostdinc;
560 #ifdef __UCLIBC_CTOR_DTOR__
563 if (use_nostdinc_plus) {
564 gcc_argv[i++] = nostdinc_plus;
566 xstrcat(&cppinc, uClibc_inc[use_build_dir], "g++/", NULL);
567 gcc_argv[i++] = "-isystem";
568 gcc_argv[i++] = cppinc;
569 xstrcat(&cppinc, uClibc_inc[use_build_dir], "g++-v3/", NULL);
570 gcc_argv[i++] = "-isystem";
571 gcc_argv[i++] = cppinc;
574 gcc_argv[i++] = "-isystem";
575 gcc_argv[i++] = uClibc_inc[use_build_dir];
576 gcc_argv[i++] = "-iwithprefix";
577 gcc_argv[i++] = "include";
579 gcc_argv[i++] = incstr;
582 if (linking && source_count) {
584 #ifdef __UCLIBC_PROFILING__
586 gcc_argv[i++] = gcrt1_path[use_build_dir];
589 #ifdef __UCLIBC_CTOR_DTOR__
591 gcc_argv[i++] = crti_path[use_build_dir];
593 gcc_argv[i++] = crtbegin_path[1];
595 gcc_argv[i++] = crtbegin_path[0];
600 #ifdef __UCLIBC_PROFILING__
604 gcc_argv[i++] = crt0_path[use_build_dir];
607 for ( l = 0 ; l < k ; l++ ) {
608 if (gcc_argument[l]) gcc_argv[i++] = gcc_argument[l];
611 //gcc_argv[i++] = "-Wl,--start-group";
612 gcc_argv[i++] = "-lgcc";
614 for ( l = 0 ; l < m ; l++ ) {
615 if (libraries[l]) gcc_argv[i++] = libraries[l];
618 #ifdef __UCLIBC_CTOR_DTOR__
620 gcc_argv[i++] = "-lstdc++";
621 gcc_argv[i++] = "-lm";
624 gcc_argv[i++] = "-lc";
625 gcc_argv[i++] = "-lgcc";
626 //gcc_argv[i++] = "-Wl,--end-group";
628 #ifdef __UCLIBC_CTOR_DTOR__
631 gcc_argv[i++] = "-x";
632 gcc_argv[i++] = "none";
635 gcc_argv[i++] = crtend_path[1];
637 gcc_argv[i++] = crtend_path[0];
640 gcc_argv[i++] = crtn_path[use_build_dir];
644 for ( l = 0 ; l < k ; l++ ) {
645 if (gcc_argument[l]) gcc_argv[i++] = gcc_argument[l];
648 gcc_argv[i++] = NULL;
651 for ( j = 0 ; gcc_argv[j] ; j++ ) {
652 printf("arg[%2i] = %s\n", j, gcc_argv[j]);
656 //no need to free memory from xstrcat because we never return...
657 #ifdef __UCLIBC_CTOR_DTOR__
658 if (cplusplus && cpp) {
659 execvp(cpp, gcc_argv);
660 fprintf(stderr, "%s: %s\n", cpp, strerror(errno));
664 execvp(cc, gcc_argv);
665 fprintf(stderr, "%s: %s\n", cc, strerror(errno));