1 | /* Specific flags and argument handling of the Fortran front-end. |
2 | Copyright (C) 1997-2023 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GCC. |
5 | |
6 | GNU CC is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; either version 3, or (at your option) |
9 | any later version. |
10 | |
11 | GNU CC is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | GNU General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
19 | |
20 | /* This file is copied more or less verbatim from g77. */ |
21 | /* This file contains a filter for the main `gcc' driver, which is |
22 | replicated for the `gfortran' driver by adding this filter. The purpose |
23 | of this filter is to be basically identical to gcc (in that |
24 | it faithfully passes all of the original arguments to gcc) but, |
25 | unless explicitly overridden by the user in certain ways, ensure |
26 | that the needs of the language supported by this wrapper are met. |
27 | |
28 | For GNU Fortran 95(gfortran), we do the following to the argument list |
29 | before passing it to `gcc': |
30 | |
31 | 1. Make sure `-lgfortran -lm' is at the end of the list. |
32 | |
33 | 2. Make sure each time `-lgfortran' or `-lm' is seen, it forms |
34 | part of the series `-lgfortran -lm'. |
35 | |
36 | #1 and #2 are not done if `-nostdlib' or any option that disables |
37 | the linking phase is present, or if `-xfoo' is in effect. Note that |
38 | a lack of source files or -l options disables linking. |
39 | |
40 | This program was originally made out of gcc/cp/g++spec.cc, but the |
41 | way it builds the new argument list was rewritten so it is much |
42 | easier to maintain, improve the way it decides to add or not add |
43 | extra arguments, etc. And several improvements were made in the |
44 | handling of arguments, primarily to make it more consistent with |
45 | `gcc' itself. */ |
46 | |
47 | #include "config.h" |
48 | #include "system.h" |
49 | #include "coretypes.h" |
50 | #include "opt-suggestions.h" |
51 | #include "gcc.h" |
52 | #include "opts.h" |
53 | |
54 | #include "tm.h" |
55 | #include "intl.h" |
56 | |
57 | #ifndef MATH_LIBRARY |
58 | #define MATH_LIBRARY "m" |
59 | #endif |
60 | |
61 | #ifndef FORTRAN_LIBRARY |
62 | #define FORTRAN_LIBRARY "gfortran" |
63 | #endif |
64 | |
65 | /* Name of the spec file. */ |
66 | #define SPEC_FILE "libgfortran.spec" |
67 | |
68 | /* The original argument list and related info is copied here. */ |
69 | static unsigned int g77_xargc; |
70 | static const struct cl_decoded_option *g77_x_decoded_options; |
71 | static void append_arg (const struct cl_decoded_option *); |
72 | |
73 | /* The new argument list will be built here. */ |
74 | static unsigned int g77_newargc; |
75 | static struct cl_decoded_option *g77_new_decoded_options; |
76 | |
77 | /* This will be NULL if we encounter a situation where we should not |
78 | link in the fortran libraries. */ |
79 | static const char *library = NULL; |
80 | |
81 | |
82 | /* Return whether strings S1 and S2 are both NULL or both the same |
83 | string. */ |
84 | |
85 | static bool |
86 | strings_same (const char *s1, const char *s2) |
87 | { |
88 | return s1 == s2 || (s1 != NULL && s2 != NULL && strcmp (s1: s1, s2: s2) == 0); |
89 | } |
90 | |
91 | /* Return whether decoded option structures OPT1 and OPT2 are the |
92 | same. */ |
93 | |
94 | static bool |
95 | options_same (const struct cl_decoded_option *opt1, |
96 | const struct cl_decoded_option *opt2) |
97 | { |
98 | return (opt1->opt_index == opt2->opt_index |
99 | && strings_same (s1: opt1->arg, s2: opt2->arg) |
100 | && strings_same (s1: opt1->orig_option_with_args_text, |
101 | s2: opt2->orig_option_with_args_text) |
102 | && strings_same (s1: opt1->canonical_option[0], |
103 | s2: opt2->canonical_option[0]) |
104 | && strings_same (s1: opt1->canonical_option[1], |
105 | s2: opt2->canonical_option[1]) |
106 | && strings_same (s1: opt1->canonical_option[2], |
107 | s2: opt2->canonical_option[2]) |
108 | && strings_same (s1: opt1->canonical_option[3], |
109 | s2: opt2->canonical_option[3]) |
110 | && (opt1->canonical_option_num_elements |
111 | == opt2->canonical_option_num_elements) |
112 | && opt1->value == opt2->value |
113 | && opt1->errors == opt2->errors); |
114 | } |
115 | |
116 | /* Append another argument to the list being built. As long as it is |
117 | identical to the corresponding arg in the original list, just increment |
118 | the new arg count. Otherwise allocate a new list, etc. */ |
119 | |
120 | static void |
121 | append_arg (const struct cl_decoded_option *arg) |
122 | { |
123 | static unsigned int newargsize; |
124 | |
125 | if (g77_new_decoded_options == g77_x_decoded_options |
126 | && g77_newargc < g77_xargc |
127 | && options_same (opt1: arg, opt2: &g77_x_decoded_options[g77_newargc])) |
128 | { |
129 | ++g77_newargc; |
130 | return; /* Nothing new here. */ |
131 | } |
132 | |
133 | if (g77_new_decoded_options == g77_x_decoded_options) |
134 | { /* Make new arglist. */ |
135 | unsigned int i; |
136 | |
137 | newargsize = (g77_xargc << 2) + 20; /* This should handle all. */ |
138 | g77_new_decoded_options = XNEWVEC (struct cl_decoded_option, newargsize); |
139 | |
140 | /* Copy what has been done so far. */ |
141 | for (i = 0; i < g77_newargc; ++i) |
142 | g77_new_decoded_options[i] = g77_x_decoded_options[i]; |
143 | } |
144 | |
145 | if (g77_newargc == newargsize) |
146 | fatal_error (input_location, "overflowed output argument list for %qs" , |
147 | arg->orig_option_with_args_text); |
148 | |
149 | g77_new_decoded_options[g77_newargc++] = *arg; |
150 | } |
151 | |
152 | /* Append an option described by OPT_INDEX, ARG and VALUE to the list |
153 | being built. */ |
154 | static void |
155 | append_option (size_t opt_index, const char *arg, int value) |
156 | { |
157 | struct cl_decoded_option decoded; |
158 | |
159 | generate_option (opt_index, arg, value, CL_DRIVER, decoded: &decoded); |
160 | append_arg (arg: &decoded); |
161 | } |
162 | |
163 | /* Append a libgfortran argument to the list being built. If |
164 | FORCE_STATIC, ensure the library is linked statically. */ |
165 | |
166 | static void |
167 | add_arg_libgfortran (bool force_static ATTRIBUTE_UNUSED) |
168 | { |
169 | #ifdef HAVE_LD_STATIC_DYNAMIC |
170 | if (force_static) |
171 | append_option (opt_index: OPT_Wl_, LD_STATIC_OPTION, value: 1); |
172 | #endif |
173 | append_option (opt_index: OPT_l, FORTRAN_LIBRARY, value: 1); |
174 | #ifdef HAVE_LD_STATIC_DYNAMIC |
175 | if (force_static) |
176 | append_option (opt_index: OPT_Wl_, LD_DYNAMIC_OPTION, value: 1); |
177 | #endif |
178 | } |
179 | |
180 | void |
181 | lang_specific_driver (struct cl_decoded_option **in_decoded_options, |
182 | unsigned int *in_decoded_options_count, |
183 | int *in_added_libraries ATTRIBUTE_UNUSED) |
184 | { |
185 | unsigned int argc = *in_decoded_options_count; |
186 | struct cl_decoded_option *decoded_options = *in_decoded_options; |
187 | unsigned int i; |
188 | int verbose = 0; |
189 | |
190 | /* 0 => -xnone in effect. |
191 | 1 => -xfoo in effect. */ |
192 | int saw_speclang = 0; |
193 | |
194 | /* 0 => initial/reset state |
195 | 1 => last arg was -l<library> |
196 | 2 => last two args were -l<library> -lm. */ |
197 | int saw_library = 0; |
198 | |
199 | /* By default, we throw on the math library if we have one. */ |
200 | int need_math = (MATH_LIBRARY[0] != '\0'); |
201 | |
202 | /* Whether we should link a static libgfortran. */ |
203 | int static_lib = 0; |
204 | |
205 | /* Whether we need to link statically. */ |
206 | int static_linking = 0; |
207 | |
208 | /* The number of input and output files in the incoming arg list. */ |
209 | int n_infiles = 0; |
210 | int n_outfiles = 0; |
211 | |
212 | library = FORTRAN_LIBRARY; |
213 | |
214 | #if 0 |
215 | fprintf (stderr, "Incoming:" ); |
216 | for (i = 0; i < argc; i++) |
217 | fprintf (stderr, " %s" , decoded_options[i].orig_option_with_args_text); |
218 | fprintf (stderr, "\n" ); |
219 | #endif |
220 | |
221 | g77_xargc = argc; |
222 | g77_x_decoded_options = decoded_options; |
223 | g77_newargc = 0; |
224 | g77_new_decoded_options = decoded_options; |
225 | |
226 | /* First pass through arglist. |
227 | |
228 | If -nostdlib or a "turn-off-linking" option is anywhere in the |
229 | command line, don't do any library-option processing (except |
230 | relating to -x). */ |
231 | |
232 | for (i = 1; i < argc; ++i) |
233 | { |
234 | if (decoded_options[i].errors & CL_ERR_MISSING_ARG) |
235 | continue; |
236 | |
237 | switch (decoded_options[i].opt_index) |
238 | { |
239 | case OPT_SPECIAL_input_file: |
240 | ++n_infiles; |
241 | continue; |
242 | |
243 | case OPT_nostdlib: |
244 | case OPT_nodefaultlibs: |
245 | case OPT_c: |
246 | case OPT_r: |
247 | case OPT_S: |
248 | case OPT_fsyntax_only: |
249 | case OPT_E: |
250 | /* These options disable linking entirely or linking of the |
251 | standard libraries. */ |
252 | library = 0; |
253 | break; |
254 | |
255 | case OPT_static_libgfortran: |
256 | #ifdef HAVE_LD_STATIC_DYNAMIC |
257 | static_lib = 1; |
258 | #endif |
259 | break; |
260 | |
261 | case OPT_static: |
262 | #ifdef HAVE_LD_STATIC_DYNAMIC |
263 | static_linking = 1; |
264 | #endif |
265 | break; |
266 | |
267 | case OPT_l: |
268 | ++n_infiles; |
269 | break; |
270 | |
271 | case OPT_o: |
272 | ++n_outfiles; |
273 | break; |
274 | |
275 | case OPT_v: |
276 | verbose = 1; |
277 | break; |
278 | |
279 | case OPT__version: |
280 | printf (format: "GNU Fortran %s%s\n" , pkgversion_string, version_string); |
281 | printf (format: "Copyright %s 2023 Free Software Foundation, Inc.\n" , |
282 | _("(C)" )); |
283 | fputs (_("This is free software; see the source for copying conditions. There is NO\n\ |
284 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" ), |
285 | stdout); |
286 | exit (status: 0); |
287 | break; |
288 | |
289 | case OPT__help: |
290 | /* Let gcc.cc handle this, as it has a really |
291 | cool facility for handling --help and --verbose --help. */ |
292 | return; |
293 | |
294 | default: |
295 | break; |
296 | } |
297 | } |
298 | |
299 | if ((n_outfiles != 0) && (n_infiles == 0)) |
300 | fatal_error (input_location, |
301 | "no input files; unwilling to write output files" ); |
302 | |
303 | /* If there are no input files, no need for the library. */ |
304 | if (n_infiles == 0) |
305 | library = 0; |
306 | |
307 | /* Second pass through arglist, transforming arguments as appropriate. */ |
308 | |
309 | append_arg (arg: &decoded_options[0]); /* Start with command name, of course. */ |
310 | |
311 | for (i = 1; i < argc; ++i) |
312 | { |
313 | if (decoded_options[i].errors & CL_ERR_MISSING_ARG) |
314 | { |
315 | append_arg (arg: &decoded_options[i]); |
316 | continue; |
317 | } |
318 | |
319 | if (decoded_options[i].opt_index == OPT_SPECIAL_input_file |
320 | && decoded_options[i].arg[0] == '\0') |
321 | { |
322 | /* Interesting. Just append as is. */ |
323 | append_arg (arg: &decoded_options[i]); |
324 | continue; |
325 | } |
326 | |
327 | if (decoded_options[i].opt_index != OPT_l |
328 | && (decoded_options[i].opt_index != OPT_SPECIAL_input_file |
329 | || strcmp (s1: decoded_options[i].arg, s2: "-" ) == 0)) |
330 | { |
331 | /* Not a filename or library. */ |
332 | |
333 | if (saw_library == 1 && need_math) /* -l<library>. */ |
334 | append_option (opt_index: OPT_l, MATH_LIBRARY, value: 1); |
335 | |
336 | saw_library = 0; |
337 | |
338 | if (decoded_options[i].opt_index == OPT_SPECIAL_input_file) |
339 | { |
340 | append_arg (arg: &decoded_options[i]); /* "-" == Standard input. */ |
341 | continue; |
342 | } |
343 | |
344 | if (decoded_options[i].opt_index == OPT_x) |
345 | { |
346 | /* Track input language. */ |
347 | const char *lang = decoded_options[i].arg; |
348 | |
349 | saw_speclang = (strcmp (s1: lang, s2: "none" ) != 0); |
350 | } |
351 | |
352 | append_arg (arg: &decoded_options[i]); |
353 | |
354 | continue; |
355 | } |
356 | |
357 | /* A filename/library, not an option. */ |
358 | |
359 | if (saw_speclang) |
360 | saw_library = 0; /* -xfoo currently active. */ |
361 | else |
362 | { /* -lfoo or filename. */ |
363 | if (decoded_options[i].opt_index == OPT_l |
364 | && strcmp (s1: decoded_options[i].arg, MATH_LIBRARY) == 0) |
365 | { |
366 | if (saw_library == 1) |
367 | saw_library = 2; /* -l<library> -lm. */ |
368 | else |
369 | add_arg_libgfortran (force_static: static_lib && !static_linking); |
370 | } |
371 | else if (decoded_options[i].opt_index == OPT_l |
372 | && strcmp (s1: decoded_options[i].arg, FORTRAN_LIBRARY) == 0) |
373 | { |
374 | saw_library = 1; /* -l<library>. */ |
375 | add_arg_libgfortran (force_static: static_lib && !static_linking); |
376 | continue; |
377 | } |
378 | else |
379 | { /* Other library, or filename. */ |
380 | if (saw_library == 1 && need_math) |
381 | append_option (opt_index: OPT_l, MATH_LIBRARY, value: 1); |
382 | saw_library = 0; |
383 | } |
384 | } |
385 | append_arg (arg: &decoded_options[i]); |
386 | } |
387 | |
388 | /* Append `-lgfortran -lm' as necessary. */ |
389 | |
390 | if (library) |
391 | { /* Doing a link and no -nostdlib. */ |
392 | if (saw_speclang) |
393 | append_option (opt_index: OPT_x, arg: "none" , value: 1); |
394 | |
395 | switch (saw_library) |
396 | { |
397 | case 0: |
398 | add_arg_libgfortran (force_static: static_lib && !static_linking); |
399 | /* Fall through. */ |
400 | |
401 | case 1: |
402 | if (need_math) |
403 | append_option (opt_index: OPT_l, MATH_LIBRARY, value: 1); |
404 | default: |
405 | break; |
406 | } |
407 | } |
408 | |
409 | #ifdef ENABLE_SHARED_LIBGCC |
410 | if (library) |
411 | { |
412 | unsigned int i; |
413 | |
414 | for (i = 1; i < g77_newargc; i++) |
415 | if (g77_new_decoded_options[i].opt_index == OPT_static_libgcc |
416 | || g77_new_decoded_options[i].opt_index == OPT_static) |
417 | break; |
418 | |
419 | if (i == g77_newargc) |
420 | append_option (opt_index: OPT_shared_libgcc, NULL, value: 1); |
421 | } |
422 | |
423 | #endif |
424 | |
425 | if (verbose && g77_new_decoded_options != g77_x_decoded_options) |
426 | { |
427 | fprintf (stderr, _("Driving:" )); |
428 | for (i = 0; i < g77_newargc; i++) |
429 | fprintf (stderr, format: " %s" , |
430 | g77_new_decoded_options[i].orig_option_with_args_text); |
431 | fprintf (stderr, format: "\n" ); |
432 | } |
433 | |
434 | *in_decoded_options_count = g77_newargc; |
435 | *in_decoded_options = g77_new_decoded_options; |
436 | } |
437 | |
438 | |
439 | /* Called before linking. Returns 0 on success and -1 on failure. */ |
440 | int |
441 | lang_specific_pre_link (void) |
442 | { |
443 | if (library) |
444 | do_spec ("%:include(libgfortran.spec)" ); |
445 | |
446 | return 0; |
447 | } |
448 | |
449 | /* Number of extra output files that lang_specific_pre_link may generate. */ |
450 | int = 0; /* Not used for F77. */ |
451 | |