1 /* d-spec.c -- Specific flags and argument handling of the D front end.
2    Copyright (C) 2006-2021 Free Software Foundation, Inc.
3 
4 GCC is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8 
9 GCC is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with GCC; see the file COPYING3.  If not see
16 <http://www.gnu.org/licenses/>.  */
17 
18 #include "config.h"
19 #include "system.h"
20 #include "coretypes.h"
21 #include "opt-suggestions.h"
22 #include "gcc.h"
23 #include "tm.h"
24 #include "opts.h"
25 
26 /* This bit is set if the arguments is a D source file.  */
27 #define DSOURCE		(1<<1)
28 /* This bit is set if they did `-lstdc++'.  */
29 #define WITHLIBCXX	(1<<2)
30 /* Skip this option.  */
31 #define SKIPOPT		(1<<3)
32 
33 #ifndef LIBSTDCXX
34 #define LIBSTDCXX "stdc++"
35 #endif
36 #ifndef LIBSTDCXX_PROFILE
37 #define LIBSTDCXX_PROFILE LIBSTDCXX
38 #endif
39 
40 #ifndef LIBPHOBOS
41 #define LIBPHOBOS "gphobos"
42 #endif
43 #ifndef LIBPHOBOS_PROFILE
44 #define LIBPHOBOS_PROFILE LIBPHOBOS
45 #endif
46 
47 /* What do with libgphobos.  */
48 enum phobos_action
49 {
50   /* libgphobos should not be linked in.  */
51   PHOBOS_NOLINK = -1,
52   /* libgphobos should be linked in if it is needed.  */
53   PHOBOS_DEFAULT = 0,
54   /* libgphobos is needed and should be linked in.  */
55   PHOBOS_LINK,
56   /* libgphobos is needed and should be linked statically.  */
57   PHOBOS_STATIC,
58   /* libgphobos is needed and should be linked dynamically.  */
59   PHOBOS_DYNAMIC
60 };
61 
62 static phobos_action phobos_library = PHOBOS_DEFAULT;
63 
64 /* If true, do load libgphobos.spec even if not needed otherwise.  */
65 static bool need_spec = false;
66 
67 void
lang_specific_driver(cl_decoded_option ** in_decoded_options,unsigned int * in_decoded_options_count,int * in_added_libraries)68 lang_specific_driver (cl_decoded_option **in_decoded_options,
69 		      unsigned int *in_decoded_options_count,
70 		      int *in_added_libraries)
71 {
72   unsigned int i, j;
73 
74   /* If nonzero, the user gave us the `-p' or `-pg' flag.  */
75   int saw_profile_flag = 0;
76 
77   /* If true, the user gave `-g'.  Used by -debuglib.  */
78   bool saw_debug_flag = false;
79 
80   /* The new argument list will be contained in this.  */
81   cl_decoded_option *new_decoded_options;
82 
83   /* "-lstdc++" if it appears on the command line.  */
84   const cl_decoded_option *saw_libcxx = 0;
85 
86   /* Whether we need the C++ STD library.  */
87   bool need_stdcxx = false;
88 
89   /* True if we saw -static.  */
90   bool static_link = false;
91 
92   /* True if we should add -shared-libgcc to the command-line.  */
93   bool shared_libgcc = true;
94 
95   /* What default library to use instead of phobos.  */
96   const char *defaultlib = NULL;
97 
98   /* What debug library to use instead of phobos.  */
99   const char *debuglib = NULL;
100 
101   /* The total number of arguments with the new stuff.  */
102   unsigned int num_args = 1;
103 
104   /* "-fonly" if it appears on the command line.  */
105   const char *only_source_option = 0;
106 
107   /* Whether the -o option was used.  */
108   bool saw_opt_o = false;
109 
110   /* Whether the -c option was used.  Also used for -E, -fsyntax-only,
111      in general anything which implies only compilation and not linking.  */
112   bool saw_opt_c = false;
113 
114   /* Whether the -S option was used.  */
115   bool saw_opt_S = false;
116 
117   /* The first input file with an extension of .d.  */
118   const char *first_d_file = NULL;
119 
120   /* The total number of arguments with the new stuff.  */
121   unsigned int argc = *in_decoded_options_count;
122 
123   /* The argument list.  */
124   cl_decoded_option *decoded_options = *in_decoded_options;
125 
126   /* The number of libraries added in.  */
127   int added_libraries = *in_added_libraries;
128 
129   /* An array used to flag each argument that needs a bit set for
130      DSOURCE, MATHLIB, WITHTHREAD, WITHLIBC or WITHLIBCXX.  */
131   int *args = XCNEWVEC (int, argc);
132 
133   for (i = 1; i < argc; i++)
134     {
135       const char *arg = decoded_options[i].arg;
136       const int value = decoded_options[i].value;
137 
138       switch (decoded_options[i].opt_index)
139 	{
140 	case OPT_dstartfiles:
141 	  need_spec = true;
142 	  break;
143 
144 	case OPT_nostdlib:
145 	case OPT_nodefaultlibs:
146 	  phobos_library = PHOBOS_NOLINK;
147 	  break;
148 
149 	case OPT_nophoboslib:
150 	  phobos_library = PHOBOS_NOLINK;
151 	  args[i] |= SKIPOPT;
152 	  break;
153 
154 	case OPT_fdruntime:
155 	  if (!value)
156 	    phobos_library = PHOBOS_NOLINK;
157 	  else
158 	    phobos_library = PHOBOS_LINK;
159 	  break;
160 
161 	case OPT_defaultlib_:
162 	  if (defaultlib != NULL)
163 	    free (CONST_CAST (char *, defaultlib));
164 	  if (arg != NULL)
165 	    {
166 	      args[i] |= SKIPOPT;
167 	      defaultlib = XNEWVEC (char, strlen (arg));
168 	      strcpy (CONST_CAST (char *, defaultlib), arg);
169 	    }
170 	  break;
171 
172 	case OPT_debuglib_:
173 	  if (debuglib != NULL)
174 	    free (CONST_CAST (char *, debuglib));
175 	  if (arg != NULL)
176 	    {
177 	      args[i] |= SKIPOPT;
178 	      debuglib = XNEWVEC (char, strlen (arg));
179 	      strcpy (CONST_CAST (char *, debuglib), arg);
180 	    }
181 	  break;
182 
183 	case OPT_l:
184 	  if ((strcmp (arg, LIBSTDCXX) == 0)
185 	      || (strcmp (arg, LIBSTDCXX_PROFILE) == 0))
186 	    {
187 	      args[i] |= WITHLIBCXX;
188 	      need_stdcxx = false;
189 	    }
190 	  /* Unrecognized libraries (e.g. -ltango) may require libphobos.  */
191 	  else if (phobos_library == PHOBOS_DEFAULT)
192 	    phobos_library = PHOBOS_LINK;
193 	  break;
194 
195 	case OPT_pg:
196 	case OPT_p:
197 	  saw_profile_flag++;
198 	  break;
199 
200 	case OPT_g:
201 	  saw_debug_flag = true;
202 	  break;
203 
204 	case OPT_v:
205 	  /* If they only gave us `-v', don't try to link in libphobos.  */
206 	  if (argc == 2)
207 	    phobos_library = PHOBOS_NOLINK;
208 	  break;
209 
210 	case OPT_x:
211 	  if (phobos_library == PHOBOS_DEFAULT && (strcmp (arg, "d") == 0))
212 	    phobos_library = PHOBOS_LINK;
213 	  break;
214 
215 	case OPT_Xlinker:
216 	case OPT_Wl_:
217 	  /* Arguments that go directly to the linker might be .o files
218 	     or something, and so might cause libphobos to be needed.  */
219 	  if (phobos_library == PHOBOS_DEFAULT)
220 	    phobos_library = PHOBOS_LINK;
221 	  break;
222 
223 	case OPT_c:
224 	case OPT_E:
225 	case OPT_M:
226 	case OPT_MM:
227 	case OPT_fsyntax_only:
228 	  /* Don't specify libaries if we won't link, since that would
229 	     cause a warning.  */
230 	  saw_opt_c = true;
231 	  phobos_library = PHOBOS_NOLINK;
232 	  break;
233 
234 	case OPT_S:
235 	  saw_opt_S = true;
236 	  phobos_library = PHOBOS_NOLINK;
237 	  break;
238 
239 	case OPT_o:
240 	  saw_opt_o = true;
241 	  break;
242 
243 	case OPT_static:
244 	  static_link = true;
245 	  break;
246 
247 	case OPT_static_libgcc:
248 	  shared_libgcc = false;
249 	  break;
250 
251 	case OPT_static_libphobos:
252 	  if (phobos_library != PHOBOS_NOLINK)
253 	    phobos_library = PHOBOS_STATIC;
254 	  args[i] |= SKIPOPT;
255 	  break;
256 
257 	case OPT_shared_libphobos:
258 	  if (phobos_library != PHOBOS_NOLINK)
259 	    phobos_library = PHOBOS_DYNAMIC;
260 	  args[i] |= SKIPOPT;
261 	  break;
262 
263 	case OPT_fonly_:
264 	  args[i] |= SKIPOPT;
265 	  only_source_option = decoded_options[i].orig_option_with_args_text;
266 
267 	  if (arg != NULL)
268 	    {
269 	      const char *suffix = strrchr (only_source_option, '.');
270 	      if (suffix == NULL || strcmp (suffix, ".d") != 0)
271 		only_source_option = concat (only_source_option, ".d", NULL);
272 	    }
273 	  break;
274 
275 	case OPT_SPECIAL_input_file:
276 	  {
277 	    if (arg[0] == '\0' || arg[1] == '\0')
278 	      continue;
279 
280 	    if (phobos_library == PHOBOS_DEFAULT)
281 	      phobos_library = PHOBOS_LINK;
282 
283 	    /* Record that this is a D source file.  */
284 	    const char *suffix = strrchr (arg, '.');
285 	    if (suffix != NULL && strcmp (suffix, ".d") == 0)
286 	      {
287 		if (first_d_file == NULL)
288 		  first_d_file = arg;
289 
290 		args[i] |= DSOURCE;
291 	      }
292 
293 	    /* If this is a C++ source file, we'll need to link
294 	       against libstdc++ library.  */
295 	    if (suffix != NULL
296 		&& (strcmp (suffix, ".cc") == 0
297 		    || (strcmp (suffix, ".cpp") == 0)
298 		    || (strcmp (suffix, ".c++") == 0)))
299 	      need_stdcxx = true;
300 
301 	    break;
302 	  }
303 	}
304     }
305 
306   /* There's no point adding -shared-libgcc if we don't have a shared
307      libgcc.  */
308 #ifndef ENABLE_SHARED_LIBGCC
309   shared_libgcc = false;
310 #endif
311 
312   /* Make sure to have room for the trailing NULL argument.
313      - need_stdcxx might add `-lstdcxx'
314      - libphobos adds `-Bstatic -lphobos -Bdynamic'
315      - only_source adds 1 more arg, also maybe add `-o'.  */
316   num_args = argc + need_stdcxx + shared_libgcc
317     + (phobos_library != PHOBOS_NOLINK) * 4 + 2;
318   new_decoded_options = XNEWVEC (cl_decoded_option, num_args);
319 
320   i = 0;
321   j = 0;
322 
323   /* Copy the 0th argument, i.e., the name of the program itself.  */
324   new_decoded_options[j++] = decoded_options[i++];
325 
326   /* NOTE: We start at 1 now, not 0.  */
327   while (i < argc)
328     {
329       if (args[i] & SKIPOPT)
330 	{
331 	  ++i;
332 	  continue;
333 	}
334 
335       new_decoded_options[j] = decoded_options[i];
336 
337       if (!saw_libcxx && (args[i] & WITHLIBCXX))
338 	{
339 	  --j;
340 	  saw_libcxx = &decoded_options[i];
341 	}
342 
343       if (args[i] & DSOURCE)
344 	{
345 	  if (only_source_option)
346 	    --j;
347 	}
348 
349       i++;
350       j++;
351     }
352 
353   if (only_source_option)
354     {
355       const char *only_source_arg = only_source_option + 7;
356       generate_option (OPT_fonly_, only_source_arg, 1, CL_DRIVER,
357 		       &new_decoded_options[j]);
358       j++;
359 
360       generate_option_input_file (only_source_arg,
361 				  &new_decoded_options[j++]);
362     }
363 
364   /* If no reason to link against libphobos library, then don't add it.  */
365   if (phobos_library == PHOBOS_DEFAULT)
366     phobos_library = PHOBOS_NOLINK;
367 
368   /* If we didn't see a -o option, add one.  This is because we need the
369      driver to pass all .d files to the D compiler.  Without a -o option
370      the driver will invoke the compiler separately for each input file.  */
371   if (first_d_file != NULL && !saw_opt_o)
372     {
373       if (saw_opt_c || saw_opt_S)
374 	{
375 	  const char *base = lbasename (first_d_file);
376 	  int baselen = strlen (base) - 2;
377 	  char *out = XNEWVEC (char, baselen + 3);
378 
379 	  memcpy (out, base, baselen);
380 	  /* The driver will convert .o to some other suffix if appropriate.  */
381 	  out[baselen] = '.';
382 	  if (saw_opt_S)
383 	    out[baselen + 1] = 's';
384 	  else
385 	    out[baselen + 1] = 'o';
386 	  out[baselen + 2] = '\0';
387 	  generate_option (OPT_o, out, 1, CL_DRIVER,
388 			   &new_decoded_options[j]);
389 	}
390       else
391 	{
392 	  /* Wouldn't be necessary if the driver converted .out also.  */
393 	  const char *out = NULL;
394 
395 #ifdef TARGET_EXECUTABLE_SUFFIX
396 	  if (TARGET_EXECUTABLE_SUFFIX[0] != 0)
397 	    out = "a" TARGET_EXECUTABLE_SUFFIX;
398 #endif
399 	  if (out == NULL)
400 	    out = "a.out";
401 
402 	  generate_option (OPT_o, out, 1, CL_DRIVER,
403 			   &new_decoded_options[j]);
404 	}
405       j++;
406     }
407 
408   /* Add `-lgphobos' if we haven't already done so.  */
409   if (phobos_library != PHOBOS_NOLINK)
410     {
411       /* Default to static linking.  */
412       if (phobos_library != PHOBOS_DYNAMIC)
413 	phobos_library = PHOBOS_STATIC;
414 
415 #ifdef HAVE_LD_STATIC_DYNAMIC
416       if (phobos_library == PHOBOS_STATIC && !static_link)
417 	{
418 	  generate_option (OPT_Wl_, LD_STATIC_OPTION, 1, CL_DRIVER,
419 			   &new_decoded_options[j++]);
420 	}
421 #endif
422       /* Order of precedence in determining what library to link against is:
423 	 - `-l<lib>' from `-debuglib=<lib>' if `-g' was also seen.
424 	 - `-l<lib>' from `-defaultlib=<lib>'.
425 	 - `-lgphobos' unless `-nophoboslib' or `-fno-druntime' was seen.  */
426       if (debuglib && saw_debug_flag)
427 	{
428 	  generate_option (OPT_l, debuglib, 1, CL_DRIVER,
429 			   &new_decoded_options[j++]);
430 	  added_libraries++;
431 	}
432       else if (defaultlib)
433 	{
434 	  generate_option (OPT_l, defaultlib, 1, CL_DRIVER,
435 			   &new_decoded_options[j++]);
436 	  added_libraries++;
437 	}
438       else
439 	{
440 	  generate_option (OPT_l,
441 			   saw_profile_flag ? LIBPHOBOS_PROFILE : LIBPHOBOS, 1,
442 			   CL_DRIVER, &new_decoded_options[j++]);
443 	  added_libraries++;
444 	}
445 
446 #ifdef HAVE_LD_STATIC_DYNAMIC
447       if (phobos_library == PHOBOS_STATIC && !static_link)
448 	{
449 	  generate_option (OPT_Wl_, LD_DYNAMIC_OPTION, 1, CL_DRIVER,
450 			   &new_decoded_options[j++]);
451 	}
452 #endif
453     }
454 
455   if (saw_libcxx)
456     new_decoded_options[j++] = *saw_libcxx;
457   else if (need_stdcxx)
458     {
459       generate_option (OPT_l,
460 		       (saw_profile_flag
461 			? LIBSTDCXX_PROFILE
462 			: LIBSTDCXX),
463 		       1, CL_DRIVER, &new_decoded_options[j++]);
464       added_libraries++;
465     }
466 
467   if (shared_libgcc && !static_link)
468     {
469       generate_option (OPT_shared_libgcc, NULL, 1, CL_DRIVER,
470 		       &new_decoded_options[j++]);
471     }
472 
473   *in_decoded_options_count = j;
474   *in_decoded_options = new_decoded_options;
475   *in_added_libraries = added_libraries;
476 }
477 
478 /* Called before linking.  Returns 0 on success and -1 on failure.  */
479 
480 int
lang_specific_pre_link(void)481 lang_specific_pre_link (void)
482 {
483   if ((phobos_library != PHOBOS_NOLINK) || need_spec)
484     do_spec ("%:include(libgphobos.spec)");
485 
486   return 0;
487 }
488 
489 /* Number of extra output files that lang_specific_pre_link may generate.  */
490 
491 int lang_specific_extra_outfiles = 0;  /* Not used for D.  */
492 
493