]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/gcc/cp/g++.c
This commit was generated by cvs2svn to compensate for changes in r55682,
[FreeBSD/FreeBSD.git] / contrib / gcc / cp / g++.c
1 /* G++ preliminary semantic processing for the compiler driver.
2    Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
3    Contributed by Brendan Kehoe (brendan@cygnus.com).
4
5 This file is part of GNU CC.
6
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING.  If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 /* This program is a wrapper to the main `gcc' driver.  For GNU C++,
23    we need to do two special things: a) append `-lg++' in situations
24    where it's appropriate, to link in libg++, and b) add `-xc++'..`-xnone'
25    around file arguments named `foo.c' or `foo.i'.  So, we do all of
26    this semantic processing then just exec gcc with the new argument
27    list.
28
29    We used to do all of this in a small shell script, but many users
30    found the performance of this as a shell script to be unacceptable.
31    In situations where your PATH has a lot of NFS-mounted directories,
32    using a script that runs sed and other things would be a nasty
33    performance hit.  With this program, we never search the PATH at all.  */
34
35 #include "config.h"
36 #ifdef __STDC__
37 #include <stdarg.h>
38 #else
39 #include <varargs.h>
40 #endif
41 #include <stdio.h>
42 #include <sys/types.h>
43 #if !defined(_WIN32)
44 #include <sys/file.h>   /* May get R_OK, etc. on some systems.  */
45 #else
46 #include <process.h>
47 #endif
48 #include <errno.h>
49
50 /* Defined to the name of the compiler; if using a cross compiler, the
51    Makefile should compile this file with the proper name
52    (e.g., "i386-aout-gcc").  */
53 #ifndef GCC_NAME
54 #define GCC_NAME "gcc"
55 #endif
56
57 /* This bit is set if we saw a `-xfoo' language specification.  */
58 #define LANGSPEC        (1<<1)
59 /* This bit is set if they did `-lm' or `-lmath'.  */
60 #define MATHLIB         (1<<2)
61
62 #ifndef MATH_LIBRARY
63 #define MATH_LIBRARY "-lm"
64 #endif
65
66 /* On MSDOS, write temp files in current dir
67    because there's no place else we can expect to use.  */
68 #ifdef __MSDOS__
69 #ifndef P_tmpdir
70 #define P_tmpdir "."
71 #endif
72 #ifndef R_OK
73 #define R_OK 4
74 #define W_OK 2
75 #define X_OK 1
76 #endif
77 #endif
78
79 #ifndef VPROTO
80 #ifdef __STDC__
81 #define PVPROTO(ARGS)           ARGS
82 #define VPROTO(ARGS)            ARGS
83 #define VA_START(va_list,var)   va_start(va_list,var)
84 #else
85 #define PVPROTO(ARGS)           ()
86 #define VPROTO(ARGS)            (va_alist) va_dcl
87 #define VA_START(va_list,var)   va_start(va_list)
88 #endif
89 #endif
90
91 #ifndef errno
92 extern int errno;
93 #endif
94
95 extern int sys_nerr;
96 #ifndef HAVE_STRERROR
97 #if defined(bsd4_4)
98 extern const char *const sys_errlist[];
99 #else
100 extern char *sys_errlist[];
101 #endif
102 #else
103 extern char *strerror();
104 #endif
105
106 /* Name with which this program was invoked.  */
107 static char *programname;
108 \f
109 char *
110 my_strerror(e)
111      int e;
112 {
113
114 #ifdef HAVE_STRERROR
115   return strerror(e);
116
117 #else
118
119   static char buffer[30];
120   if (!e)
121     return "";
122
123   if (e > 0 && e < sys_nerr)
124     return sys_errlist[e];
125
126   sprintf (buffer, "Unknown error %d", e);
127   return buffer;
128 #endif
129 }
130 \f
131 #ifdef HAVE_VPRINTF
132 /* Output an error message and exit */
133
134 static void
135 fatal VPROTO((char *format, ...))
136 {
137 #ifndef __STDC__
138   char *format;
139 #endif
140   va_list ap;
141
142   VA_START (ap, format);
143
144 #ifndef __STDC__
145   format = va_arg (ap, char*);
146 #endif
147
148   fprintf (stderr, "%s: ", programname);
149   vfprintf (stderr, format, ap);
150   va_end (ap);
151   fprintf (stderr, "\n");
152 #if 0
153   /* XXX Not needed for g++ driver.  */
154   delete_temp_files ();
155 #endif
156   exit (1);
157 }
158
159 static void
160 error VPROTO((char *format, ...))
161 {
162 #ifndef __STDC__
163   char *format;
164 #endif
165   va_list ap;
166
167   VA_START (ap, format);
168
169 #ifndef __STDC__
170   format = va_arg (ap, char*);
171 #endif
172
173   fprintf (stderr, "%s: ", programname);
174   vfprintf (stderr, format, ap);
175   va_end (ap);
176
177   fprintf (stderr, "\n");
178 }
179
180 #else /* not HAVE_VPRINTF */
181
182 static void
183 error (msg, arg1, arg2)
184      char *msg, *arg1, *arg2;
185 {
186   fprintf (stderr, "%s: ", programname);
187   fprintf (stderr, msg, arg1, arg2);
188   fprintf (stderr, "\n");
189 }
190
191 static void
192 fatal (msg, arg1, arg2)
193      char *msg, *arg1, *arg2;
194 {
195   error (msg, arg1, arg2);
196 #if 0
197   /* XXX Not needed for g++ driver.  */
198   delete_temp_files ();
199 #endif
200   exit (1);
201 }
202
203 #endif /* not HAVE_VPRINTF */
204
205 /* More 'friendly' abort that prints the line and file.
206    config.h can #define abort fancy_abort if you like that sort of thing.  */
207
208 void
209 fancy_abort ()
210 {
211   fatal ("Internal g++ abort.");
212 }
213
214 char *
215 xmalloc (size)
216      unsigned size;
217 {
218   register char *value = (char *) malloc (size);
219   if (value == 0)
220     fatal ("virtual memory exhausted");
221   return value;
222 }
223
224 /* Return a newly-allocated string whose contents concatenate those
225    of s1, s2, s3.  */
226 static char *
227 concat (s1, s2, s3)
228      char *s1, *s2, *s3;
229 {
230   int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
231   char *result = xmalloc (len1 + len2 + len3 + 1);
232
233   strcpy (result, s1);
234   strcpy (result + len1, s2);
235   strcpy (result + len1 + len2, s3);
236   *(result + len1 + len2 + len3) = 0;
237
238   return result;
239 }
240
241 static void
242 pfatal_with_name (name)
243      char *name;
244 {
245   fatal (concat ("%s: ", my_strerror (errno), ""), name);
246 }
247
248 #ifdef __MSDOS__
249 /* This is the common prefix we use to make temp file names.  */
250 char *temp_filename;
251
252 /* Length of the prefix.  */
253 int temp_filename_length;
254
255 /* Compute a string to use as the base of all temporary file names.  */
256 static char *
257 choose_temp_base_try (try, base)
258 char *try;
259 char *base;
260 {
261   char *rv;
262   if (base)
263     rv = base;
264   else if (try == (char *)0)
265     rv = 0;
266   else if (access (try, R_OK | W_OK) != 0)
267     rv = 0;
268   else
269     rv = try;
270   return rv;
271 }
272
273 static void
274 choose_temp_base ()
275 {
276   char *base = 0;
277   int len;
278
279   base = choose_temp_base_try (getenv ("TMPDIR"), base);
280   base = choose_temp_base_try (getenv ("TMP"), base);
281   base = choose_temp_base_try (getenv ("TEMP"), base);
282
283 #ifdef P_tmpdir
284   base = choose_temp_base_try (P_tmpdir, base);
285 #endif
286
287   base = choose_temp_base_try ("/usr/tmp", base);
288   base = choose_temp_base_try ("/tmp", base);
289
290   /* If all else fails, use the current directory! */  
291   if (base == (char *)0)
292     base = "./";
293
294   len = strlen (base);
295   temp_filename = xmalloc (len + sizeof("/ccXXXXXX"));
296   strcpy (temp_filename, base);
297   if (len > 0 && temp_filename[len-1] != '/')
298     temp_filename[len++] = '/';
299   strcpy (temp_filename + len, "ccXXXXXX");
300
301   mktemp (temp_filename);
302   temp_filename_length = strlen (temp_filename);
303   if (temp_filename_length == 0)
304     abort ();
305 }
306
307 static void
308 perror_exec (name)
309      char *name;
310 {
311   char *s;
312
313   if (errno < sys_nerr)
314     s = concat ("installation problem, cannot exec %s: ",
315                 my_strerror( errno ), "");
316   else
317     s = "installation problem, cannot exec %s";
318   error (s, name);
319 }
320
321 /* This is almost exactly what's in gcc.c:pexecute for MSDOS.  */
322 void
323 run_dos (program, argv)
324      char *program;
325      char *argv[];
326 {
327   char *scmd, *rf;
328   FILE *argfile;
329   int i;
330
331   choose_temp_base (); /* not in gcc.c */
332
333   scmd = (char *) malloc (strlen (program) + strlen (temp_filename) + 10);
334   rf = scmd + strlen (program) + 6;
335   sprintf (scmd, "%s.exe @%s.gp", program, temp_filename);
336
337   argfile = fopen (rf, "w");
338   if (argfile == 0)
339     pfatal_with_name (rf);
340
341   for (i=1; argv[i]; i++)
342     {
343       char *cp;
344       for (cp = argv[i]; *cp; cp++)
345         {
346           if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
347             fputc ('\\', argfile);
348           fputc (*cp, argfile);
349         }
350       fputc ('\n', argfile);
351     }
352   fclose (argfile);
353
354   i = system (scmd);
355
356   remove (rf);
357   
358   if (i == -1)
359     perror_exec (program);
360 }
361 #endif /* __MSDOS__ */
362 \f
363 int
364 main (argc, argv)
365      int argc;
366      char **argv;
367 {
368   register int i, j = 0;
369   register char *p;
370   int verbose = 0;
371
372   /* This will be 0 if we encounter a situation where we should not
373      link in libstdc++, or 2 if we should link in libg++ as well.  */
374   int library = 1;
375
376   /* Used to track options that take arguments, so we don't go wrapping
377      those with -xc++/-xnone.  */
378   char *quote = NULL;
379
380   /* The new argument list will be contained in this.  */
381   char **arglist;
382
383   /* The name of the compiler we will want to run---by default, it
384      will be the definition of `GCC_NAME', e.g., `gcc'.  */
385   char *gcc = GCC_NAME;
386
387   /* Non-zero if we saw a `-xfoo' language specification on the
388      command line.  Used to avoid adding our own -xc++ if the user
389      already gave a language for the file.  */
390   int saw_speclang = 0;
391
392   /* Non-zero if we saw `-lm' or `-lmath' on the command line.  */
393   char *saw_math = 0;
394
395   /* The number of arguments being added to what's in argv, other than
396      libraries.  We use this to track the number of times we've inserted
397      -xc++/-xnone.  */
398   int added = 0;
399
400   /* An array used to flag each argument that needs a bit set for
401      LANGSPEC or MATHLIB.  */
402   int *args;
403
404   p = argv[0] + strlen (argv[0]);
405
406   /* If we're called as g++ (or i386-aout-g++), link in libg++ as well.  */
407
408   if (strcmp (p - 3, "g++") == 0)
409     {
410       library = 2;
411     }
412
413   while (p != argv[0] && p[-1] != '/')
414     --p;
415   programname = p;
416
417   if (argc == 1)
418     fatal ("No input files specified");
419
420 #ifndef __MSDOS__
421   /* We do a little magic to find out where the main gcc executable
422      is.  If they ran us as /usr/local/bin/g++, then we will look
423      for /usr/local/bin/gcc; similarly, if they just ran us as `g++',
424      we'll just look for `gcc'.  */
425   if (p != argv[0])
426     {
427       *--p = '\0';
428       gcc = (char *) malloc ((strlen (argv[0]) + 1 + strlen (GCC_NAME) + 1)
429                              * sizeof (char));
430       sprintf (gcc, "%s/%s", argv[0], GCC_NAME);
431     }
432 #endif
433
434   args = (int *) malloc (argc * sizeof (int));
435   bzero ((char *) args, argc * sizeof (int));
436
437   for (i = 1; i < argc; i++)
438     {
439       /* If the previous option took an argument, we swallow it here.  */
440       if (quote)
441         {
442           quote = NULL;
443           continue;
444         }
445
446       if (argv[i][0] == '\0' || argv[i][1] == '\0')
447         continue;
448
449       if (argv[i][0] == '-')
450         {
451           if (library != 0 && strcmp (argv[i], "-nostdlib") == 0)
452             {
453               library = 0;
454             }
455           else if (strcmp (argv[i], "-lm") == 0
456                    || strcmp (argv[i], "-lmath") == 0)
457             args[i] |= MATHLIB;
458           else if (strcmp (argv[i], "-v") == 0)
459             {
460               verbose = 1;
461               if (argc == 2)
462                 {
463                   /* If they only gave us `-v', don't try to link
464                      in libg++.  */ 
465                   library = 0;
466                 }
467             }
468           else if (strncmp (argv[i], "-x", 2) == 0)
469             saw_speclang = 1;
470           else if (((argv[i][2] == '\0'
471                      && (char *)strchr ("bBVDUoeTuIYmLiA", argv[i][1]) != NULL)
472                     || strcmp (argv[i], "-Tdata") == 0))
473             quote = argv[i];
474           else if (library != 0 && ((argv[i][2] == '\0'
475                      && (char *) strchr ("cSEM", argv[i][1]) != NULL)
476                     || strcmp (argv[i], "-MM") == 0))
477             {
478               /* Don't specify libraries if we won't link, since that would
479                  cause a warning.  */
480               library = 0;
481             }
482           else
483             /* Pass other options through.  */
484             continue;
485         }
486       else
487         {
488           int len; 
489
490           if (saw_speclang)
491             {
492               saw_speclang = 0;
493               continue;
494             }
495
496           /* If the filename ends in .c or .i, put options around it.
497              But not if a specified -x option is currently active.  */
498           len = strlen (argv[i]);
499           if (len > 2
500               && (argv[i][len - 1] == 'c' || argv[i][len - 1] == 'i')
501               && argv[i][len - 2] == '.')
502             {
503               args[i] |= LANGSPEC;
504               added += 2;
505             }
506         }
507     }
508
509   if (quote)
510     fatal ("argument to `%s' missing\n", quote);
511
512   if (added || library)
513     {
514       arglist = (char **) malloc ((argc + added + 4) * sizeof (char *));
515
516       for (i = 1, j = 1; i < argc; i++, j++)
517         {
518           arglist[j] = argv[i];
519
520           /* Make sure -lg++ is before the math library, since libg++
521              itself uses those math routines.  */
522           if (!saw_math && (args[i] & MATHLIB) && library)
523             {
524               --j;
525               saw_math = argv[i];
526             }
527
528           /* Wrap foo.c and foo.i files in a language specification to
529              force the gcc compiler driver to run cc1plus on them.  */
530           if (args[i] & LANGSPEC)
531             {
532               int len = strlen (argv[i]);
533               if (argv[i][len - 1] == 'i')
534                 arglist[j++] = "-xc++-cpp-output";
535               else
536                 arglist[j++] = "-xc++";
537               arglist[j++] = argv[i];
538               arglist[j] = "-xnone";
539             }
540         }
541
542       /* Add `-lg++' if we haven't already done so.  */
543       if (library == 2)
544         arglist[j++] = "-lg++";
545       if (library)
546         arglist[j++] = "-lstdc++";
547       if (saw_math)
548         arglist[j++] = saw_math;
549       else if (library)
550         arglist[j++] = MATH_LIBRARY;
551
552       arglist[j] = NULL;
553     }
554   else
555     /* No need to copy 'em all.  */
556     arglist = argv;
557
558   arglist[0] = gcc;
559
560   if (verbose)
561     {
562       if (j == 0)
563         j = argc;
564
565       for (i = 0; i < j; i++)
566         fprintf (stderr, " %s", arglist[i]);
567       fprintf (stderr, "\n");
568     }
569 #if !defined(OS2) && !defined (_WIN32)
570 #ifdef __MSDOS__
571   run_dos (gcc, arglist);
572 #else /* !__MSDOS__ */
573   if (execvp (gcc, arglist) < 0)
574     pfatal_with_name (gcc);
575 #endif /* __MSDOS__ */
576 #else /* OS2 or _WIN32 */
577   if (spawnvp (1, gcc, arglist) < 0)
578     pfatal_with_name (gcc);
579 #endif
580
581   return 0;
582 }