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