1 /* Specific flags and argument handling of the Fortran front-end.
2 Copyright (C) 1997, 1999, 2000, 2001, 2002, 2003
3 Free Software Foundation, Inc.
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 file contains a filter for the main `gcc' driver, which is
23 replicated for the `g77' driver by adding this filter. The purpose
24 of this filter is to be basically identical to gcc (in that
25 it faithfully passes all of the original arguments to gcc) but,
26 unless explicitly overridden by the user in certain ways, ensure
27 that the needs of the language supported by this wrapper are met.
28
29 For GNU Fortran (g77), we do the following to the argument list
30 before passing it to `gcc':
31
32 1. Make sure `-lg2c -lm' is at the end of the list.
33
34 2. Make sure each time `-lg2c' or `-lm' is seen, it forms
35 part of the series `-lg2c -lm'.
36
37 #1 and #2 are not done if `-nostdlib' or any option that disables
38 the linking phase is present, or if `-xfoo' is in effect. Note that
39 a lack of source files or -l options disables linking.
40
41 This program was originally made out of gcc/cp/g++spec.c, but the
42 way it builds the new argument list was rewritten so it is much
43 easier to maintain, improve the way it decides to add or not add
44 extra arguments, etc. And several improvements were made in the
45 handling of arguments, primarily to make it more consistent with
46 `gcc' itself. */
47
48 #include "config.h"
49 #include "system.h"
50 #include "gcc.h"
51
52 #ifndef MATH_LIBRARY
53 #define MATH_LIBRARY "-lm"
54 #endif
55
56 #ifndef FORTRAN_INIT
57 #define FORTRAN_INIT "-lfrtbegin"
58 #endif
59
60 #ifndef FORTRAN_LIBRARY
61 #define FORTRAN_LIBRARY "-lg2c"
62 #endif
63
64 /* Options this driver needs to recognize, not just know how to
65 skip over. */
66 typedef enum
67 {
68 OPTION_b, /* Aka --prefix. */
69 OPTION_B, /* Aka --target. */
70 OPTION_c, /* Aka --compile. */
71 OPTION_driver, /* Wrapper-specific option. */
72 OPTION_E, /* Aka --preprocess. */
73 OPTION_help, /* --help. */
74 OPTION_i, /* -imacros, -include, -include-*. */
75 OPTION_l,
76 OPTION_L, /* Aka --library-directory. */
77 OPTION_M, /* Aka --dependencies. */
78 OPTION_MM, /* Aka --user-dependencies. */
79 OPTION_nostdlib, /* Aka --no-standard-libraries, or
80 -nodefaultlibs. */
81 OPTION_o, /* Aka --output. */
82 OPTION_S, /* Aka --assemble. */
83 OPTION_syntax_only, /* -fsyntax-only. */
84 OPTION_v, /* Aka --verbose. */
85 OPTION_version, /* --version. */
86 OPTION_V, /* Aka --use-version. */
87 OPTION_x, /* Aka --language. */
88 OPTION_ /* Unrecognized or unimportant. */
89 } Option;
90
91 /* The original argument list and related info is copied here. */
92 static int g77_xargc;
93 static const char *const *g77_xargv;
94 static void lookup_option PARAMS ((Option *, int *, const char **,
95 const char *));
96 static void append_arg PARAMS ((const char *));
97
98 /* The new argument list will be built here. */
99 static int g77_newargc;
100 static const char **g77_newargv;
101
102 #ifndef SWITCH_TAKES_ARG
103 #define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
104 #endif
105
106 #ifndef WORD_SWITCH_TAKES_ARG
107 #define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
108 #endif
109
110 /* Assumes text[0] == '-'. Returns number of argv items that belong to
111 (and follow) this one, an option id for options important to the
112 caller, and a pointer to the first char of the arg, if embedded (else
113 returns NULL, meaning no arg or it's the next argv).
114
115 Note that this also assumes gcc.c's pass converting long options
116 to short ones, where available, has already been run. */
117
118 static void
lookup_option(xopt,xskip,xarg,text)119 lookup_option (xopt, xskip, xarg, text)
120 Option *xopt;
121 int *xskip;
122 const char **xarg;
123 const char *text;
124 {
125 Option opt = OPTION_;
126 int skip;
127 const char *arg = NULL;
128
129 if ((skip = SWITCH_TAKES_ARG (text[1])))
130 skip -= (text[2] != '\0'); /* See gcc.c. */
131
132 if (text[1] == 'B')
133 opt = OPTION_B, skip = (text[2] == '\0'), arg = text + 2;
134 else if (text[1] == 'b')
135 opt = OPTION_b, skip = (text[2] == '\0'), arg = text + 2;
136 else if ((text[1] == 'c') && (text[2] == '\0'))
137 opt = OPTION_c, skip = 0;
138 else if ((text[1] == 'E') && (text[2] == '\0'))
139 opt = OPTION_E, skip = 0;
140 else if (text[1] == 'i')
141 opt = OPTION_i, skip = 0;
142 else if (text[1] == 'l')
143 opt = OPTION_l;
144 else if (text[1] == 'L')
145 opt = OPTION_L, arg = text + 2;
146 else if (text[1] == 'o')
147 opt = OPTION_o;
148 else if ((text[1] == 'S') && (text[2] == '\0'))
149 opt = OPTION_S, skip = 0;
150 else if (text[1] == 'V')
151 opt = OPTION_V, skip = (text[2] == '\0');
152 else if ((text[1] == 'v') && (text[2] == '\0'))
153 opt = OPTION_v, skip = 0;
154 else if (text[1] == 'x')
155 opt = OPTION_x, arg = text + 2;
156 else
157 {
158 if ((skip = WORD_SWITCH_TAKES_ARG (text + 1)) != 0) /* See gcc.c. */
159 ;
160 else if (! strncmp (text, "-fdriver", 8)) /* Really --driver!! */
161 opt = OPTION_driver; /* Never mind arg, this is unsupported. */
162 else if (! strcmp (text, "-fhelp")) /* Really --help!! */
163 opt = OPTION_help;
164 else if (! strcmp (text, "-M"))
165 opt = OPTION_M;
166 else if (! strcmp (text, "-MM"))
167 opt = OPTION_MM;
168 else if (! strcmp (text, "-nostdlib")
169 || ! strcmp (text, "-nodefaultlibs"))
170 opt = OPTION_nostdlib;
171 else if (! strcmp (text, "-fsyntax-only"))
172 opt = OPTION_syntax_only;
173 else if (! strcmp (text, "-dumpversion"))
174 opt = OPTION_version;
175 else if (! strcmp (text, "-fversion")) /* Really --version!! */
176 opt = OPTION_version;
177 else if (! strcmp (text, "-Xlinker")
178 || ! strcmp (text, "-specs"))
179 skip = 1;
180 else
181 skip = 0;
182 }
183
184 if (xopt != NULL)
185 *xopt = opt;
186 if (xskip != NULL)
187 *xskip = skip;
188 if (xarg != NULL)
189 {
190 if ((arg != NULL)
191 && (arg[0] == '\0'))
192 *xarg = NULL;
193 else
194 *xarg = arg;
195 }
196 }
197
198 /* Append another argument to the list being built. As long as it is
199 identical to the corresponding arg in the original list, just increment
200 the new arg count. Otherwise allocate a new list, etc. */
201
202 static void
append_arg(arg)203 append_arg (arg)
204 const char *arg;
205 {
206 static int newargsize;
207
208 #if 0
209 fprintf (stderr, "`%s'\n", arg);
210 #endif
211
212 if (g77_newargv == g77_xargv
213 && g77_newargc < g77_xargc
214 && (arg == g77_xargv[g77_newargc]
215 || ! strcmp (arg, g77_xargv[g77_newargc])))
216 {
217 ++g77_newargc;
218 return; /* Nothing new here. */
219 }
220
221 if (g77_newargv == g77_xargv)
222 { /* Make new arglist. */
223 int i;
224
225 newargsize = (g77_xargc << 2) + 20; /* This should handle all. */
226 g77_newargv = (const char **) xmalloc (newargsize * sizeof (char *));
227
228 /* Copy what has been done so far. */
229 for (i = 0; i < g77_newargc; ++i)
230 g77_newargv[i] = g77_xargv[i];
231 }
232
233 if (g77_newargc == newargsize)
234 fatal ("overflowed output arg list for `%s'", arg);
235
236 g77_newargv[g77_newargc++] = arg;
237 }
238
239 void
lang_specific_driver(in_argc,in_argv,in_added_libraries)240 lang_specific_driver (in_argc, in_argv, in_added_libraries)
241 int *in_argc;
242 const char *const **in_argv;
243 int *in_added_libraries ATTRIBUTE_UNUSED;
244 {
245 int argc = *in_argc;
246 const char *const *argv = *in_argv;
247 int i;
248 int verbose = 0;
249 Option opt;
250 int skip;
251 const char *arg;
252
253 /* This will be NULL if we encounter a situation where we should not
254 link in libf2c. */
255 const char *library = FORTRAN_LIBRARY;
256
257 /* 0 => -xnone in effect.
258 1 => -xfoo in effect. */
259 int saw_speclang = 0;
260
261 /* 0 => initial/reset state
262 1 => last arg was -l<library>
263 2 => last two args were -l<library> -lm. */
264 int saw_library = 0;
265
266 /* 0 => initial/reset state
267 1 => FORTRAN_INIT linked in */
268 int use_init = 0;
269 /* By default, we throw on the math library if we have one. */
270 int need_math = (MATH_LIBRARY[0] != '\0');
271
272 /* The number of input and output files in the incoming arg list. */
273 int n_infiles = 0;
274 int n_outfiles = 0;
275
276 #if 0
277 fprintf (stderr, "Incoming:");
278 for (i = 0; i < argc; i++)
279 fprintf (stderr, " %s", argv[i]);
280 fprintf (stderr, "\n");
281 #endif
282
283 g77_xargc = argc;
284 g77_xargv = argv;
285 g77_newargc = 0;
286 g77_newargv = (const char **) argv;
287
288 /* First pass through arglist.
289
290 If -nostdlib or a "turn-off-linking" option is anywhere in the
291 command line, don't do any library-option processing (except
292 relating to -x). Also, if -v is specified, but no other options
293 that do anything special (allowing -V version, etc.), remember
294 to add special stuff to make gcc command actually invoke all
295 the different phases of the compilation process so all the version
296 numbers can be seen.
297
298 Also, here is where all problems with missing arguments to options
299 are caught. If this loop is exited normally, it means all options
300 have the appropriate number of arguments as far as the rest of this
301 program is concerned. */
302
303 for (i = 1; i < argc; ++i)
304 {
305 if ((argv[i][0] == '+') && (argv[i][1] == 'e'))
306 {
307 continue;
308 }
309
310 if ((argv[i][0] != '-') || (argv[i][1] == '\0'))
311 {
312 ++n_infiles;
313 continue;
314 }
315
316 lookup_option (&opt, &skip, NULL, argv[i]);
317
318 switch (opt)
319 {
320 case OPTION_nostdlib:
321 case OPTION_c:
322 case OPTION_S:
323 case OPTION_syntax_only:
324 case OPTION_E:
325 case OPTION_M:
326 case OPTION_MM:
327 /* These options disable linking entirely or linking of the
328 standard libraries. */
329 library = 0;
330 break;
331
332 case OPTION_l:
333 ++n_infiles;
334 break;
335
336 case OPTION_o:
337 ++n_outfiles;
338 break;
339
340 case OPTION_v:
341 verbose = 1;
342 break;
343
344 case OPTION_b:
345 case OPTION_B:
346 case OPTION_L:
347 case OPTION_i:
348 case OPTION_V:
349 /* These options are useful in conjunction with -v to get
350 appropriate version info. */
351 break;
352
353 case OPTION_version:
354 printf ("\
355 GNU Fortran (GCC) %s\n\
356 Copyright (C) 2002 Free Software Foundation, Inc.\n\
357 \n\
358 GNU Fortran comes with NO WARRANTY, to the extent permitted by law.\n\
359 You may redistribute copies of GNU Fortran\n\
360 under the terms of the GNU General Public License.\n\
361 For more information about these matters, see the file named COPYING\n\
362 or type the command `info -f g77 Copying'.\n\
363 ", version_string);
364 exit (0);
365 break;
366
367 case OPTION_help:
368 /* Let gcc.c handle this, as it has a really
369 cool facility for handling --help and --verbose --help. */
370 return;
371
372 case OPTION_driver:
373 fatal ("--driver no longer supported");
374 break;
375
376 default:
377 break;
378 }
379
380 /* This is the one place we check for missing arguments in the
381 program. */
382
383 if (i + skip < argc)
384 i += skip;
385 else
386 fatal ("argument to `%s' missing", argv[i]);
387 }
388
389 if ((n_outfiles != 0) && (n_infiles == 0))
390 fatal ("no input files; unwilling to write output files");
391
392 /* If there are no input files, no need for the library. */
393 if (n_infiles == 0)
394 library = 0;
395
396 /* Second pass through arglist, transforming arguments as appropriate. */
397
398 append_arg (argv[0]); /* Start with command name, of course. */
399
400 for (i = 1; i < argc; ++i)
401 {
402 if (argv[i][0] == '\0')
403 {
404 append_arg (argv[i]); /* Interesting. Just append as is. */
405 continue;
406 }
407
408 if ((argv[i][0] == '-') && (argv[i][1] != 'l'))
409 {
410 /* Not a filename or library. */
411
412 if (saw_library == 1 && need_math) /* -l<library>. */
413 append_arg (MATH_LIBRARY);
414
415 saw_library = 0;
416
417 lookup_option (&opt, &skip, &arg, argv[i]);
418
419 if (argv[i][1] == '\0')
420 {
421 append_arg (argv[i]); /* "-" == Standard input. */
422 continue;
423 }
424
425 if (opt == OPTION_x)
426 {
427 /* Track input language. */
428 const char *lang;
429
430 if (arg == NULL)
431 lang = argv[i+1];
432 else
433 lang = arg;
434
435 saw_speclang = (strcmp (lang, "none") != 0);
436 }
437
438 append_arg (argv[i]);
439
440 for (; skip != 0; --skip)
441 append_arg (argv[++i]);
442
443 continue;
444 }
445
446 /* A filename/library, not an option. */
447
448 if (saw_speclang)
449 saw_library = 0; /* -xfoo currently active. */
450 else
451 { /* -lfoo or filename. */
452 if (strcmp (argv[i], MATH_LIBRARY) == 0
453 #ifdef ALT_LIBM
454 || strcmp (argv[i], ALT_LIBM) == 0
455 #endif
456 )
457 {
458 if (saw_library == 1)
459 saw_library = 2; /* -l<library> -lm. */
460 else
461 {
462 if (0 == use_init)
463 {
464 append_arg (FORTRAN_INIT);
465 use_init = 1;
466 }
467 append_arg (FORTRAN_LIBRARY);
468 }
469 }
470 else if (strcmp (argv[i], FORTRAN_LIBRARY) == 0)
471 saw_library = 1; /* -l<library>. */
472 else
473 { /* Other library, or filename. */
474 if (saw_library == 1 && need_math)
475 append_arg (MATH_LIBRARY);
476 saw_library = 0;
477 }
478 }
479 append_arg (argv[i]);
480 }
481
482 /* Append `-lg2c -lm' as necessary. */
483
484 if (library)
485 { /* Doing a link and no -nostdlib. */
486 if (saw_speclang)
487 append_arg ("-xnone");
488
489 switch (saw_library)
490 {
491 case 0:
492 if (0 == use_init)
493 {
494 append_arg (FORTRAN_INIT);
495 use_init = 1;
496 }
497 append_arg (library);
498 case 1:
499 if (need_math)
500 append_arg (MATH_LIBRARY);
501 default:
502 break;
503 }
504 }
505
506 #ifdef ENABLE_SHARED_LIBGCC
507 if (library)
508 {
509 int i;
510
511 for (i = 1; i < g77_newargc; i++)
512 if (g77_newargv[i][0] == '-')
513 if (strcmp (g77_newargv[i], "-static-libgcc") == 0
514 || strcmp (g77_newargv[i], "-static") == 0)
515 break;
516
517 if (i == g77_newargc)
518 append_arg ("-shared-libgcc");
519 }
520
521 #endif
522
523 if (verbose
524 && g77_newargv != g77_xargv)
525 {
526 fprintf (stderr, "Driving:");
527 for (i = 0; i < g77_newargc; i++)
528 fprintf (stderr, " %s", g77_newargv[i]);
529 fprintf (stderr, "\n");
530 }
531
532 *in_argc = g77_newargc;
533 *in_argv = g77_newargv;
534 }
535
536 /* Called before linking. Returns 0 on success and -1 on failure. */
lang_specific_pre_link()537 int lang_specific_pre_link () /* Not used for F77. */
538 {
539 return 0;
540 }
541
542 /* Number of extra output files that lang_specific_pre_link may generate. */
543 int lang_specific_extra_outfiles = 0; /* Not used for F77. */
544
545 /* Table of language-specific spec functions. */
546 const struct spec_function lang_specific_spec_functions[] =
547 {
548 { 0, 0 }
549 };
550