OSDN Git Service

Rename the very badly named 'UCLIBC_GCC' to 'UCLIBC_ENV' and
[uclinux-h8/uClibc.git] / extra / gcc-uClibc / gcc-uClibc.c
1 /*
2  * Copyright (C) 2000 Manuel Novoa III
3  * Copyright (C) 2002 Erik Andersen
4  *
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.
8  *
9  * April 7, 2001
10  *
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
15  * command line.
16  *
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.
19  *
20  *
21  * April 18, 2001
22  *
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.
29  *
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.
36  *
37  * The wrapper now displays the command line passed to gcc when '-v' is used.
38  *
39  * May 31, 2001
40  *
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.
44  *
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
49  * example,
50  *
51  *   export UCLIBC_GCC_DLOPT="-Wl,--dynamic-linker,/lib/ld-alt-linker.so.3"
52  *
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.
57  *
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.
61  *
62  * Added options --uclibc-use-build-dir and --uclibc-use-rpath so that those
63  * behaviors can be invoked from the command line.
64  *
65  */
66
67 /*
68  *
69  * TODO:
70  * Check/modify gcc-specific environment variables?
71  */
72
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <stdarg.h>
76 #include <string.h>
77 #include <unistd.h>
78 #include <sys/stat.h>
79 #include <sys/wait.h>
80
81 #include "gcc-uClibc.h"
82
83 static char *our_usr_lib_path = "-L"UCLIBC_DEVEL_PREFIX"/lib";
84
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++";
92 #endif
93
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)
98 {
99         register const char *s;
100         register const char *p;
101         p = s = path;
102         while (*s) {
103                 if (*s++ == '/') {
104                         p = s;
105                 }
106         }
107         return (char *) p;
108 }
109
110 char *dirname(char *path)
111 {
112         static const char null_or_empty_or_noslash[] = ".";
113         register char *s;
114         register char *last;
115         char *first;
116
117         last = s = path;
118
119         if (s != NULL) {
120
121         LOOP:
122                 while (*s && (*s != '/')) ++s;
123                 first = s;
124                 while (*s == '/') ++s;
125                 if (*s) {
126                         last = first;
127                         goto LOOP;
128                 }
129
130                 if (last == path) {
131                         if (*last != '/') {
132                                 goto DOT;
133                         }
134                         if ((*++last == '/') && (last[1] == 0)) {
135                                 ++last;
136                         }
137                 }
138                 *last = 0;
139                 return path;
140         }
141  DOT:
142         return (char *) null_or_empty_or_noslash;
143 }
144
145
146 extern void *xmalloc(size_t size)
147 {
148         void *ptr = malloc(size);
149
150         if (!ptr) {
151             fprintf(stderr, "memory exhausted");
152             exit(EXIT_FAILURE);
153         }
154         return ptr;
155 }
156
157 void xstrcat(char **string, ...)
158 {
159         const char *c;
160         va_list p; 
161         /* Don't bother to calculate how big exerything 
162          * will be, just be careful to not overflow...  */
163         va_start(p, string);
164         *string = xmalloc(BUFSIZ);
165         **string = '\0';
166         while(1) {
167             if (!(c = va_arg(p, const char *)))
168                 break;
169             strcat(*string, c); 
170         }
171         va_end(p);
172 }
173
174 int main(int argc, char **argv)
175 {
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;
180         char ** gcc_argv;
181         char ** gcc_argument;
182         char ** libraries;
183         char ** libpath;
184         char *dlstr;
185         char *incstr;
186         char *devprefix;
187         char *builddir;
188         char *libstr;
189         char *build_dlstr = 0;
190         char *cc;
191         char *ep;
192         char *rpath_link[2];
193         char *rpath[2];
194         char *uClibc_inc[2];
195         char *our_lib_path[2];
196         char *crt0_path[2];
197         char *crtbegin_path[2];
198         char *crtend_path[2];
199         const char *application_name;
200 #ifdef __UCLIBC_CTOR_DTOR__
201         char *crti_path[2];
202         char *crtn_path[2];
203         int len;
204         int ctor_dtor = 1, cplusplus = 0, use_nostdinc_plus = 0;
205         char *GPLUSPLUS_BIN = NULL;
206 #endif
207 #ifdef __UCLIBC_PROFILING__
208         int profile = 0;
209         char *gcrt1_path[2];
210 #endif
211
212         cc     = getenv("UCLIBC_CC");
213         if (!cc) {
214                 cc = GCC_BIN;
215         }
216
217         application_name = basename(argv[0]);
218         if (application_name[0] == '-')
219                 application_name++;
220
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 
226          * perversion...  */
227         len = strlen(application_name);
228         if ((strcmp(application_name+len-3, "g++")==0) ||
229                 (strcmp(application_name+len-3, "c++")==0)) {
230             len = strlen(cc);
231             if (strcmp(cc+len-3, "gcc")==0) {
232                 GPLUSPLUS_BIN = strdup(cc);
233                 GPLUSPLUS_BIN[len-1]='+';
234                 GPLUSPLUS_BIN[len-2]='+';
235             }
236             cplusplus = 1;
237             use_nostdinc_plus = 1;
238         }
239 #endif
240
241         devprefix = getenv("UCLIBC_DEVEL_PREFIX");
242         if (!devprefix) {
243                 devprefix = UCLIBC_DEVEL_PREFIX;
244         }
245
246         builddir = getenv("UCLIBC_BUILD_DIR");
247         if (!builddir) {
248                 builddir = UCLIBC_BUILD_DIR;
249         }
250
251         incstr = getenv("UCLIBC_GCC_INC");
252         libstr = getenv("UCLIBC_GCC_LIB");
253
254         ep     = getenv("UCLIBC_ENV");
255         if (!ep) {
256                 ep = "";
257         }
258
259         if (strstr(ep,"build") != 0) {
260                 use_build_dir = 1;
261         }
262
263         if (strstr(ep,"rpath") != 0) {
264                 use_rpath = 1;
265         }
266
267
268         xstrcat(&(rpath_link[0]), "-Wl,-rpath-link,", devprefix, "/lib", NULL);
269         xstrcat(&(rpath_link[1]), "-Wl,-rpath-link,", builddir, "/lib", NULL);
270
271         xstrcat(&(rpath[0]), "-Wl,-rpath,", devprefix, "/lib", NULL);
272         xstrcat(&(rpath[1]), "-Wl,-rpath,", builddir, "/lib", NULL);
273
274         xstrcat(&(uClibc_inc[0]), devprefix, "/include/", NULL);
275         xstrcat(&(uClibc_inc[1]), builddir, "/include/", NULL);
276
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);
284 #else
285         xstrcat(&(crt0_path[0]), devprefix, "/lib/crt0.o", NULL);
286         xstrcat(&(crt0_path[1]), builddir, "/lib/crt0.o", NULL);
287 #endif
288 #ifdef __UCLIBC_PROFILING__
289         xstrcat(&(gcrt1_path[0]), devprefix, "/lib/gcrt1.o", NULL);
290         xstrcat(&(gcrt1_path[1]), builddir, "/lib/gcrt1.o", NULL);
291 #endif
292
293         xstrcat(&(our_lib_path[0]), "-L", devprefix, "/lib", NULL);
294         xstrcat(&(our_lib_path[1]), "-L", builddir, "/lib", NULL);
295
296 #ifdef __UCLIBC_HAS_SHARED__
297         build_dlstr = "-Wl,--dynamic-linker," BUILD_DYNAMIC_LINKER;
298         dlstr = getenv("UCLIBC_GCC_DLOPT");
299         if (!dlstr) {
300                 dlstr = "-Wl,--dynamic-linker," DYNAMIC_LINKER;
301         }
302 #endif
303
304         m = 0;
305         libraries = __builtin_alloca(sizeof(char*) * (argc));
306         libraries[m] = '\0';
307
308         n = 0;
309         libpath = __builtin_alloca(sizeof(char*) * (argc));
310         libpath[n] = '\0';
311
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 */
319                                         linking = 0;
320                                         break;
321                                 case 'L':               /* library */
322                                         libpath[n++] = argv[i];
323                                         libpath[n] = '\0';
324                                         if (argv[i][2] == 0) {
325                                             argv[i] = '\0';
326                                             libpath[n++] = argv[++i];
327                                             libpath[n] = '\0';
328                                         }
329                                         argv[i] = '\0';
330                                         break;
331                                 case 'l':               /* library */
332                                         libraries[m++] = argv[i];
333                                         libraries[m] = '\0';
334                                         argv[i] = '\0';
335                                         break;
336                                 case 'v':               /* verbose */
337                                         if (argv[i][2] == 0) verbose = 1;
338                                         printf("Invoked as %s\n", argv[0]);
339                                         break;
340                                 case 'n':
341                                         if (strcmp(nostdinc,argv[i]) == 0) {
342                                                 use_stdinc = 0;
343                                         } else if (strcmp(nostartfiles,argv[i]) == 0) {
344 #ifdef __UCLIBC_CTOR_DTOR__
345                                                 ctor_dtor = 0;
346 #endif
347                                                 use_start = 0;
348                                         } else if (strcmp(nodefaultlibs,argv[i]) == 0) {
349                                                 use_stdlib = 0;
350                                                 argv[i] = '\0';
351                                         } else if (strcmp(nostdlib,argv[i]) == 0) {
352 #ifdef __UCLIBC_CTOR_DTOR__
353                                                 ctor_dtor = 0;
354 #endif
355                                                 use_start = 0;
356                                                 use_stdlib = 0;
357                                         } 
358 #ifdef __UCLIBC_CTOR_DTOR__
359                                         else if (strcmp(nostdinc_plus,argv[i]) == 0) {
360                                                 if (cplusplus==1) {
361                                                         use_nostdinc_plus = 0;
362                                                 }
363                                         }
364 #endif
365                                         break;
366                                 case 's':
367                                         if (strstr(argv[i],static_linking) != NULL) {
368                                                 use_static_linking = 1;
369                                         }
370                                         if (strcmp("-shared",argv[i]) == 0) {
371                                                 use_start = 0;
372                                                 use_pic = 1;
373                                         }
374                                         break;
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;
379                                                 }
380                                                 if (strstr(argv[i],"--dynamic-linker") != 0) {
381                                                         dlstr = 0;
382                                                 }
383                                         }
384                                         break;
385 #ifdef __UCLIBC_PROFILING__
386                                 case 'p':
387                                         if (strcmp("-pg",argv[i]) == 0) {
388                                             profile = 1;
389                                         }
390                                         break;
391 #endif
392                                 case 'f':
393                                         /* Check if we are doing PIC */
394                                         if (strcmp("-fPIC",argv[i]) == 0) {
395                                             use_pic = 1;
396                                         } else if (strcmp("-fpic",argv[i]) == 0) {
397                                             use_pic = 1;
398                                         } 
399 #ifdef __UCLIBC_PROFILING__
400                                         else if (strcmp("-fprofile-arcs",argv[i]) == 0) {
401                                             profile = 1;
402                                         }
403 #endif
404                                         break;
405
406                                 case '-':
407                                         if (strstr(argv[i]+1,static_linking) != NULL) {
408                                             use_static_linking = 1;
409                                             argv[i]='\0';
410                                         } else if (strcmp("--uclibc-use-build-dir",argv[i]) == 0) {
411                                             use_build_dir = 1;
412                                             argv[i]='\0';
413                                         } else if (strcmp("--uclibc-use-rpath",argv[i]) == 0) {
414                                             use_rpath = 1;
415                                             argv[i]='\0';
416                                         }
417 #ifdef __UCLIBC_CTOR_DTOR__
418                                         else if (strcmp("--uclibc-no-ctors",argv[i]) == 0) {
419                                             ctor_dtor = 0;
420                                             argv[i]='\0';
421                                         }
422 #endif
423                                         break;
424                         }
425                 } else {                                /* assume it is an existing source file */
426                         ++source_count;
427                 }
428         }
429
430         gcc_argv = __builtin_alloca(sizeof(char*) * (argc + 64));
431         gcc_argument = __builtin_alloca(sizeof(char*) * (argc + 20));
432
433         i = 0; k = 0;
434 #ifdef __UCLIBC_CTOR_DTOR__
435         if (ctor_dtor) {
436             struct stat statbuf;
437             if (stat(LIBGCC_DIR, &statbuf)!=0 || 
438                     !S_ISDIR(statbuf.st_mode))
439             {
440                 /* Bummer, gcc has moved things on us... */
441                 int status, gcc_pipe[2];
442                 pid_t pid, wpid;
443
444                 pipe(gcc_pipe);
445                 if (!(pid = fork())) {
446                     char *argv[4];
447                     close(gcc_pipe[0]);
448                     close(1);
449                     close(2);
450                     dup2(gcc_pipe[1], 1);
451                     dup2(gcc_pipe[1], 2);
452                     argv[0] = cc; 
453                     argv[2] = "-print-libgcc-file-name";
454                     argv[3] = NULL;
455                     execvp(argv[0], argv);
456                     close(gcc_pipe[1]);
457                     _exit(-1);
458                 }
459                 wpid=0;
460                 while (wpid != pid) {
461                     wpid = wait(&status);
462                 }
463                 close(gcc_pipe[1]);
464                 if (WIFEXITED(status)) {
465                     char buf[1024], *dir;
466                     status = read(gcc_pipe[0], buf, sizeof(buf));
467                     if (status < 0) {
468                         goto crash_n_burn;
469                     }
470                     dir = dirname(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);
475                 } else {
476 crash_n_burn:
477                     fprintf(stderr, "Unable to locale crtbegin.o provided by gcc");
478                     exit(EXIT_FAILURE);
479                 }
480                 close(gcc_pipe[0]);
481
482             } else {
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);
487             }
488         }
489
490         if (cplusplus && GPLUSPLUS_BIN)
491             gcc_argv[i++] = GPLUSPLUS_BIN;
492         else
493 #endif
494             gcc_argv[i++] = cc;
495         
496         for ( j = 1 ; j < argc ; j++ ) {
497                 if (argv[j]=='\0') {
498                     continue;
499                 } else {
500                         gcc_argument[k++] = argv[j];
501                         gcc_argument[k] = '\0';
502                 }
503         }
504
505         if (linking && source_count) {
506 #if defined __HAVE_ELF__ && ! defined __UCLIBC_HAS_MMU__
507             gcc_argv[i++] = "-Wl,-elf2flt";
508 #endif
509             gcc_argv[i++] = nostdlib;
510             if (use_static_linking) {
511                 gcc_argv[i++] = static_linking;
512             }
513             if (!use_static_linking) {
514                 if (dlstr && use_build_dir) {
515                     gcc_argv[i++] = build_dlstr;
516                 } else if (dlstr) {
517                     gcc_argv[i++] = dlstr;
518                 }
519                 if (use_rpath) {
520                     gcc_argv[i++] = rpath[use_build_dir];
521                 }
522             }
523             for ( l = 0 ; l < n ; l++ ) {
524                 if (libpath[l]) gcc_argv[i++] = libpath[l];
525             }
526             gcc_argv[i++] = rpath_link[use_build_dir]; /* just to be safe */
527             if( libstr )
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;
532             }
533         }
534         if (use_stdinc && source_count) {
535             gcc_argv[i++] = nostdinc;
536 #ifdef __UCLIBC_CTOR_DTOR__
537             if (cplusplus) {
538                 char *cppinc;
539                 if (use_nostdinc_plus) {
540                         gcc_argv[i++] = nostdinc_plus;
541                 }
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;
548             }
549 #endif
550             gcc_argv[i++] = "-isystem";
551             gcc_argv[i++] = uClibc_inc[use_build_dir];
552             gcc_argv[i++] = "-iwithprefix";
553             gcc_argv[i++] = "include";
554             if( incstr )
555                 gcc_argv[i++] = incstr;
556         }
557
558         if (linking && source_count) {
559
560 #ifdef __UCLIBC_PROFILING__
561             if (profile) {
562                 gcc_argv[i++] = gcrt1_path[use_build_dir];
563             }
564 #endif
565 #ifdef __UCLIBC_CTOR_DTOR__
566             if (ctor_dtor) {
567                 gcc_argv[i++] = crti_path[use_build_dir];
568                 if (use_pic) {
569                     gcc_argv[i++] = crtbegin_path[1];
570                 } else {
571                     gcc_argv[i++] = crtbegin_path[0];
572                 }
573             }
574 #endif
575             if (use_start) {
576 #ifdef __UCLIBC_PROFILING__
577                 if (!profile)
578 #endif
579                 {
580                     gcc_argv[i++] = crt0_path[use_build_dir];
581                 }
582             }
583             for ( l = 0 ; l < k ; l++ ) {
584                 if (gcc_argument[l]) gcc_argv[i++] = gcc_argument[l];
585             }
586             if (use_stdlib) {
587                 //gcc_argv[i++] = "-Wl,--start-group";
588                 gcc_argv[i++] = "-lgcc";
589             }
590             for ( l = 0 ; l < m ; l++ ) {
591                 if (libraries[l]) gcc_argv[i++] = libraries[l];
592             }
593             if (use_stdlib) {
594 #ifdef __UCLIBC_CTOR_DTOR__
595                 if (cplusplus) {
596                     gcc_argv[ i++ ] = "-lstdc++";
597                     gcc_argv[ i++ ] = "-lm";
598                 }
599 #endif
600                 gcc_argv[i++] = "-lc";
601                 gcc_argv[i++] = "-lgcc";
602                 //gcc_argv[i++] = "-Wl,--end-group";
603             }
604 #ifdef __UCLIBC_CTOR_DTOR__
605             if (ctor_dtor) {
606                 if (use_pic) {
607                     gcc_argv[i++] = crtend_path[1];
608                 } else {
609                     gcc_argv[i++] = crtend_path[0];
610                 }
611
612                 gcc_argv[i++] = crtn_path[use_build_dir];
613             }
614 #endif
615         } else {
616             for ( l = 0 ; l < k ; l++ ) {
617                 if (gcc_argument[l]) gcc_argv[i++] = gcc_argument[l];
618             }
619         }
620         gcc_argv[i++] = NULL;
621
622         if (verbose) {
623                 for ( j = 0 ; gcc_argv[j] ; j++ ) {
624                         printf("arg[%2i] = %s\n", j, gcc_argv[j]);
625                 }
626                 fflush(stdout);
627         }
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);
632         else
633 #endif
634             return execvp(cc, gcc_argv);
635 }