2 * Copyright (C) 2000 Manuel Novoa III
3 * Copyright (C) 2002 Erik Andersen
5 * This is a crude wrapper to use uClibc with gcc.
6 * It was originally written to work around ./configure for ext2fs-utils.
7 * It certainly can be improved, but it works for me in the normal cases.
11 * A bug was fixed in building the gcc command line when dynamic linking.
12 * The functions dlopen, etc. now work. At this time, you must make sure
13 * the correct libdl.so is included however. It is safest to, for example,
14 * add /lib/libdl.so.1 if using ld-linux.so.1 rather than adding -ldl to the
17 * Note: This is only a problem if devel and target archs are the same. To
18 * avoid the problem, you can use a customized dynamic linker.
23 * The wrapper now works with either installed and uninstalled uClibc versions.
24 * If you want to use the uninstalled header files and libs, either include
25 * the string "build" in the invocation name such as
26 * 'ln -s <ARCH>-uclibc-gcc <ARCH>-uclibc-gcc-build'
27 * or include it in the environment variable setting of UCLIBC_ENV.
28 * Note: This automatically enables the "rpath" behavior described below.
30 * The wrapper will now pass the location of the uClibc shared libs used to
31 * the linker with the "-rpath" option if the invocation name includes the
32 * string "rpath" or if the environment variable UCLIBC_ENV include it (as
33 * with "build" above). This is primarily intended to be used on devel
34 * platforms of the same arch as the target. A good place to use this feature
35 * would be in the uClibc/test directory.
37 * The wrapper now displays the command line passed to gcc when '-v' is used.
41 * "rpath" and "build" behavior are now decoupled. You can of course get
42 * the old "build" behavior by setting UCLIBC_ENV="rpath-build". Order
43 * isn't important here, as only the substrings are searched for.
45 * Added environment variable check for UCLIBC_GCC_DLOPT to let user specify
46 * an alternative dynamic linker at runtime without using command line args.
47 * Since this wouldn't commonly be used, I made it easy on myself. You have
48 * to match the option you would have passed to the gcc wrapper. As an
51 * export UCLIBC_GCC_DLOPT="-Wl,--dynamic-linker,/lib/ld-alt-linker.so.3"
53 * This is really only useful if target arch == devel arch and DEVEL_PREFIX
54 * isn't empty. It involves a recompile, but you can at least test apps
55 * on your devel system if combined with the "rpath" behavor if by using
56 * LD_LIBRARY_PATH, etc.
58 * Also added check for "-Wl,--dynamic-linker" on the command line. The
59 * use default dynamic linker or the envirnment-specified dynamic linker
60 * is disabled in that case.
62 * Added options --uclibc-use-build-dir and --uclibc-use-rpath so that those
63 * behaviors can be invoked from the command line.
70 * Check/modify gcc-specific environment variables?
81 #include "gcc-uClibc.h"
83 static char *our_usr_lib_path = "-L"UCLIBC_DEVEL_PREFIX"/lib";
85 static char static_linking[] = "-static";
86 static char nostdinc[] = "-nostdinc";
87 static char nostartfiles[] = "-nostartfiles";
88 static char nodefaultlibs[] = "-nodefaultlibs";
89 static char nostdlib[] = "-nostdlib";
90 #ifdef __UCLIBC_CTOR_DTOR__
91 static char nostdinc_plus[] = "-nostdinc++";
94 /* Include a local implementation of basename, since this
95 * uses the host system's C lib, and CYGWIN apparently
96 * doesn't provide an implementation of basename(). */
97 char *basename(const char *path)
99 register const char *s;
100 register const char *p;
110 char *dirname(char *path)
112 static const char null_or_empty_or_noslash[] = ".";
122 while (*s && (*s != '/')) ++s;
124 while (*s == '/') ++s;
134 if ((*++last == '/') && (last[1] == 0)) {
142 return (char *) null_or_empty_or_noslash;
146 extern void *xmalloc(size_t size)
148 void *ptr = malloc(size);
151 fprintf(stderr, "memory exhausted");
157 void xstrcat(char **string, ...)
161 /* Don't bother to calculate how big exerything
162 * will be, just be careful to not overflow... */
164 *string = xmalloc(BUFSIZ);
167 if (!(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;
179 int i, j, k, l, m, n;
181 char ** gcc_argument;
189 char *build_dlstr = 0;
195 char *our_lib_path[2];
197 char *crtbegin_path[2];
198 char *crtend_path[2];
199 const char *application_name;
200 #ifdef __UCLIBC_CTOR_DTOR__
204 int ctor_dtor = 1, cplusplus = 0, use_nostdinc_plus = 0;
205 char *GPLUSPLUS_BIN = NULL;
207 #ifdef __UCLIBC_PROFILING__
212 cc = getenv("UCLIBC_CC");
217 application_name = basename(argv[0]);
218 if (application_name[0] == '-')
221 #ifdef __UCLIBC_CTOR_DTOR__
222 /* We must use strstr since g++ might be named like a
223 * cross compiler (i.e. arm-linux-g++). We must also
224 * search carefully, in case we are searching something
225 * like /opt/c++/gcc-3.1/bin/arm-linux-g++ or some similar
227 len = strlen(application_name);
228 if ((strcmp(application_name+len-3, "g++")==0) ||
229 (strcmp(application_name+len-3, "c++")==0)) {
231 if (strcmp(cc+len-3, "gcc")==0) {
232 GPLUSPLUS_BIN = strdup(cc);
233 GPLUSPLUS_BIN[len-1]='+';
234 GPLUSPLUS_BIN[len-2]='+';
237 use_nostdinc_plus = 1;
241 devprefix = getenv("UCLIBC_DEVEL_PREFIX");
243 devprefix = UCLIBC_DEVEL_PREFIX;
246 builddir = getenv("UCLIBC_BUILD_DIR");
248 builddir = UCLIBC_BUILD_DIR;
251 incstr = getenv("UCLIBC_GCC_INC");
252 libstr = getenv("UCLIBC_GCC_LIB");
254 ep = getenv("UCLIBC_ENV");
259 if (strstr(ep,"build") != 0) {
263 if (strstr(ep,"rpath") != 0) {
268 xstrcat(&(rpath_link[0]), "-Wl,-rpath-link,", devprefix, "/lib", NULL);
269 xstrcat(&(rpath_link[1]), "-Wl,-rpath-link,", builddir, "/lib", NULL);
271 xstrcat(&(rpath[0]), "-Wl,-rpath,", devprefix, "/lib", NULL);
272 xstrcat(&(rpath[1]), "-Wl,-rpath,", builddir, "/lib", NULL);
274 xstrcat(&(uClibc_inc[0]), devprefix, "/include/", NULL);
275 xstrcat(&(uClibc_inc[1]), builddir, "/include/", NULL);
277 #ifdef __UCLIBC_CTOR_DTOR__
278 xstrcat(&(crt0_path[0]), devprefix, "/lib/crt1.o", NULL);
279 xstrcat(&(crt0_path[1]), builddir, "/lib/crt1.o", NULL);
280 xstrcat(&(crti_path[0]), devprefix, "/lib/crti.o", NULL);
281 xstrcat(&(crti_path[1]), builddir, "/lib/crti.o", NULL);
282 xstrcat(&(crtn_path[0]), devprefix, "/lib/crtn.o", NULL);
283 xstrcat(&(crtn_path[1]), builddir, "/lib/crtn.o", NULL);
285 xstrcat(&(crt0_path[0]), devprefix, "/lib/crt0.o", NULL);
286 xstrcat(&(crt0_path[1]), builddir, "/lib/crt0.o", NULL);
288 #ifdef __UCLIBC_PROFILING__
289 xstrcat(&(gcrt1_path[0]), devprefix, "/lib/gcrt1.o", NULL);
290 xstrcat(&(gcrt1_path[1]), builddir, "/lib/gcrt1.o", NULL);
293 xstrcat(&(our_lib_path[0]), "-L", devprefix, "/lib", NULL);
294 xstrcat(&(our_lib_path[1]), "-L", builddir, "/lib", NULL);
296 #ifdef __UCLIBC_HAS_SHARED__
297 build_dlstr = "-Wl,--dynamic-linker," BUILD_DYNAMIC_LINKER;
298 dlstr = getenv("UCLIBC_GCC_DLOPT");
300 dlstr = "-Wl,--dynamic-linker," DYNAMIC_LINKER;
305 libraries = __builtin_alloca(sizeof(char*) * (argc));
309 libpath = __builtin_alloca(sizeof(char*) * (argc));
312 for ( i = 1 ; i < argc ; i++ ) {
313 if (argv[i][0] == '-') { /* option */
314 switch (argv[i][1]) {
315 case 'c': /* compile or assemble */
316 case 'S': /* generate assembler code */
317 case 'E': /* preprocess only */
318 case 'M': /* generate dependencies */
321 case 'L': /* library */
322 libpath[n++] = argv[i];
324 if (argv[i][2] == 0) {
326 libpath[n++] = argv[++i];
331 case 'l': /* library */
332 libraries[m++] = argv[i];
336 case 'v': /* verbose */
337 if (argv[i][2] == 0) verbose = 1;
338 printf("Invoked as %s\n", argv[0]);
341 if (strcmp(nostdinc,argv[i]) == 0) {
343 } else if (strcmp(nostartfiles,argv[i]) == 0) {
344 #ifdef __UCLIBC_CTOR_DTOR__
348 } else if (strcmp(nodefaultlibs,argv[i]) == 0) {
351 } else if (strcmp(nostdlib,argv[i]) == 0) {
352 #ifdef __UCLIBC_CTOR_DTOR__
358 #ifdef __UCLIBC_CTOR_DTOR__
359 else if (strcmp(nostdinc_plus,argv[i]) == 0) {
361 use_nostdinc_plus = 0;
367 if (strstr(argv[i],static_linking) != NULL) {
368 use_static_linking = 1;
370 if (strcmp("-shared",argv[i]) == 0) {
375 case 'W': /* -static could be passed directly to ld */
376 if (strncmp("-Wl,",argv[i],4) == 0) {
377 if (strstr(argv[i],static_linking) != 0) {
378 use_static_linking = 1;
380 if (strstr(argv[i],"--dynamic-linker") != 0) {
385 #ifdef __UCLIBC_PROFILING__
387 if (strcmp("-pg",argv[i]) == 0) {
393 /* Check if we are doing PIC */
394 if (strcmp("-fPIC",argv[i]) == 0) {
396 } else if (strcmp("-fpic",argv[i]) == 0) {
399 #ifdef __UCLIBC_PROFILING__
400 else if (strcmp("-fprofile-arcs",argv[i]) == 0) {
407 if (strstr(argv[i]+1,static_linking) != NULL) {
408 use_static_linking = 1;
410 } else if (strcmp("--uclibc-use-build-dir",argv[i]) == 0) {
413 } else if (strcmp("--uclibc-use-rpath",argv[i]) == 0) {
417 #ifdef __UCLIBC_CTOR_DTOR__
418 else if (strcmp("--uclibc-no-ctors",argv[i]) == 0) {
425 } else { /* assume it is an existing source file */
430 gcc_argv = __builtin_alloca(sizeof(char*) * (argc + 64));
431 gcc_argument = __builtin_alloca(sizeof(char*) * (argc + 20));
434 #ifdef __UCLIBC_CTOR_DTOR__
437 if (stat(LIBGCC_DIR, &statbuf)!=0 ||
438 !S_ISDIR(statbuf.st_mode))
440 /* Bummer, gcc has moved things on us... */
441 int status, gcc_pipe[2];
445 if (!(pid = fork())) {
450 dup2(gcc_pipe[1], 1);
451 dup2(gcc_pipe[1], 2);
453 argv[2] = "-print-libgcc-file-name";
455 execvp(argv[0], argv);
460 while (wpid != pid) {
461 wpid = wait(&status);
464 if (WIFEXITED(status)) {
465 char buf[1024], *dir;
466 status = read(gcc_pipe[0], buf, sizeof(buf));
471 xstrcat(&(crtbegin_path[0]), dir, "crtbegin.o", NULL);
472 xstrcat(&(crtbegin_path[1]), dir, "crtbeginS.o", NULL);
473 xstrcat(&(crtend_path[0]), dir, "crtend.o", NULL);
474 xstrcat(&(crtend_path[1]), dir, "crtendS.o", NULL);
477 fprintf(stderr, "Unable to locale crtbegin.o provided by gcc");
483 xstrcat(&(crtbegin_path[0]), LIBGCC_DIR, "crtbegin.o", NULL);
484 xstrcat(&(crtbegin_path[1]), LIBGCC_DIR, "crtbeginS.o", NULL);
485 xstrcat(&(crtend_path[0]), LIBGCC_DIR, "crtend.o", NULL);
486 xstrcat(&(crtend_path[1]), LIBGCC_DIR, "crtendS.o", NULL);
490 if (cplusplus && GPLUSPLUS_BIN)
491 gcc_argv[i++] = GPLUSPLUS_BIN;
496 for ( j = 1 ; j < argc ; j++ ) {
500 gcc_argument[k++] = argv[j];
501 gcc_argument[k] = '\0';
505 if (linking && source_count) {
506 #if defined __HAVE_ELF__ && ! defined __UCLIBC_HAS_MMU__
507 gcc_argv[i++] = "-Wl,-elf2flt";
509 gcc_argv[i++] = nostdlib;
510 if (use_static_linking) {
511 gcc_argv[i++] = static_linking;
513 if (!use_static_linking) {
514 if (dlstr && use_build_dir) {
515 gcc_argv[i++] = build_dlstr;
517 gcc_argv[i++] = dlstr;
520 gcc_argv[i++] = rpath[use_build_dir];
523 for ( l = 0 ; l < n ; l++ ) {
524 if (libpath[l]) gcc_argv[i++] = libpath[l];
526 gcc_argv[i++] = rpath_link[use_build_dir]; /* just to be safe */
528 gcc_argv[i++] = libstr;
529 gcc_argv[i++] = our_lib_path[use_build_dir];
530 if (!use_build_dir) {
531 gcc_argv[i++] = our_usr_lib_path;
534 if (use_stdinc && source_count) {
535 gcc_argv[i++] = nostdinc;
536 #ifdef __UCLIBC_CTOR_DTOR__
539 if (use_nostdinc_plus) {
540 gcc_argv[i++] = nostdinc_plus;
542 xstrcat(&cppinc, uClibc_inc[use_build_dir], "g++/", NULL);
543 gcc_argv[i++] = "-isystem";
544 gcc_argv[i++] = cppinc;
545 xstrcat(&cppinc, uClibc_inc[use_build_dir], "g++-v3/", NULL);
546 gcc_argv[i++] = "-isystem";
547 gcc_argv[i++] = cppinc;
550 gcc_argv[i++] = "-isystem";
551 gcc_argv[i++] = uClibc_inc[use_build_dir];
552 gcc_argv[i++] = "-iwithprefix";
553 gcc_argv[i++] = "include";
555 gcc_argv[i++] = incstr;
558 if (linking && source_count) {
560 #ifdef __UCLIBC_PROFILING__
562 gcc_argv[i++] = gcrt1_path[use_build_dir];
565 #ifdef __UCLIBC_CTOR_DTOR__
567 gcc_argv[i++] = crti_path[use_build_dir];
569 gcc_argv[i++] = crtbegin_path[1];
571 gcc_argv[i++] = crtbegin_path[0];
576 #ifdef __UCLIBC_PROFILING__
580 gcc_argv[i++] = crt0_path[use_build_dir];
583 for ( l = 0 ; l < k ; l++ ) {
584 if (gcc_argument[l]) gcc_argv[i++] = gcc_argument[l];
587 //gcc_argv[i++] = "-Wl,--start-group";
588 gcc_argv[i++] = "-lgcc";
590 for ( l = 0 ; l < m ; l++ ) {
591 if (libraries[l]) gcc_argv[i++] = libraries[l];
594 #ifdef __UCLIBC_CTOR_DTOR__
596 gcc_argv[ i++ ] = "-lstdc++";
597 gcc_argv[ i++ ] = "-lm";
600 gcc_argv[i++] = "-lc";
601 gcc_argv[i++] = "-lgcc";
602 //gcc_argv[i++] = "-Wl,--end-group";
604 #ifdef __UCLIBC_CTOR_DTOR__
607 gcc_argv[i++] = crtend_path[1];
609 gcc_argv[i++] = crtend_path[0];
612 gcc_argv[i++] = crtn_path[use_build_dir];
616 for ( l = 0 ; l < k ; l++ ) {
617 if (gcc_argument[l]) gcc_argv[i++] = gcc_argument[l];
620 gcc_argv[i++] = NULL;
623 for ( j = 0 ; gcc_argv[j] ; j++ ) {
624 printf("arg[%2i] = %s\n", j, gcc_argv[j]);
628 //no need to free memory from xstrcat because we never return...
629 #ifdef __UCLIBC_CTOR_DTOR__
630 if (cplusplus && GPLUSPLUS_BIN)
631 return execvp(GPLUSPLUS_BIN, gcc_argv);
634 return execvp(cc, gcc_argv);