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