1 /* Additional functions for the GCC driver on Darwin native.
2    Copyright (C) 2006-2021 Free Software Foundation, Inc.
3    Contributed by Apple Computer Inc.
4 
5 This file is part of GCC.
6 
7 GCC 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 3, or (at your option)
10 any later version.
11 
12 GCC 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 GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20 
21 #include "config.h"
22 #include "libiberty.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "opts.h"
27 #include "diagnostic-core.h"
28 
29 /* Validate a version string (either given on the command line or, perhaps
30    as MACOSX_DEPLOYMENT_TARGET).
31 
32    The specs %version-compare() function doesn't accept leading '0' on
33    numbers so strip them out.  Do sanity checking here too.
34 
35    Return:
36      * original string means it was OK and we didn't want to change it.
37      * new string means it was OK but we rewrote it to avoid possible format
38      problems.
39      * NULL means we didn't like what we saw.
40 */
41 
42 static const char *
validate_macosx_version_min(const char * version_str)43 validate_macosx_version_min (const char *version_str)
44 {
45   size_t version_len;
46   unsigned long major, minor = 0, tiny = 0;
47   char *end;
48   const char *old_version = version_str;
49   bool need_rewrite = false;
50 
51   version_len = strlen (version_str);
52   if (version_len < 2) /* The minimum would be 11  */
53     return NULL;
54 
55   /* Version string must consist of digits and periods only.  */
56   if (strspn (version_str, "0123456789.") != version_len)
57     return NULL;
58 
59   if (!ISDIGIT (version_str[0]) || !ISDIGIT (version_str[version_len - 1]))
60     return NULL;
61 
62   if (version_str[0] == '0')
63     need_rewrite = true;
64 
65   major = strtoul (version_str, &end, 10);
66 
67   if (major < 10 || major > 11 ) /* MacOS 10 and 11 are known. */
68     return NULL;
69 
70   /* Skip a separating period, if there's one.  */
71   version_str = end + ((*end == '.') ? 1 : 0);
72 
73   if (major == 11 && *end != '\0' && !ISDIGIT (version_str[0]))
74      /* For MacOS 11, we allow just the major number, but if the minor is
75 	there it must be numeric.  */
76     return NULL;
77   else if (major == 11 && *end == '\0')
78     /* We will rewrite 11 =>  11.0.0.  */
79     need_rewrite = true;
80   else if (major == 10 && (*end == '\0' || !ISDIGIT (version_str[0])))
81     /* Otherwise, minor version components must be present and numeric.  */
82     return NULL;
83 
84   /* If we have one or more leading zeros on a component, then rewrite the
85      version string.  */
86   if (*end != '\0' && version_str[0] == '0' && version_str[1] != '\0'
87       && version_str[1] != '.')
88     need_rewrite = true;
89 
90   minor = strtoul (version_str, &end, 10);
91   version_str = end + ((*end == '.') ? 1 : 0);
92   if (minor > 99)
93     return NULL;
94 
95   /* If 'tiny' is present it must be numeric.  */
96   if (*end != '\0' && !ISDIGIT (version_str[0]))
97     return NULL;
98 
99   /* If we have one or more leading zeros on a component, then rewrite the
100      version string.  */
101   if (*end != '\0' && version_str[0] == '0'
102       && version_str[1] != '\0')
103     need_rewrite = true;
104 
105   tiny = strtoul (version_str, &end, 10);
106   if (tiny > 99)
107     return NULL;
108 
109   /* Version string must contain no more than three tokens.  */
110   if (*end != '\0')
111     return NULL;
112 
113   if (need_rewrite)
114     {
115       char *new_version;
116       asprintf (&new_version, "%2lu.%lu.%lu", major, minor, tiny);
117       return new_version;
118     }
119 
120   return old_version;
121 }
122 
123 #ifndef CROSS_DIRECTORY_STRUCTURE
124 #include <sys/sysctl.h>
125 #include "xregex.h"
126 
127 /* Determine the version of the running OS.
128    We only look at the first two components (ignoring the patch one) and
129    report NN.MM.0 where NN is currently either 10 or 11 and MM is the OS
130    minor release number.
131    If we can't parse what the kernel gives us, warn the user, and do nothing.  */
132 
133 static char *
darwin_find_version_from_kernel(void)134 darwin_find_version_from_kernel (void)
135 {
136   char osversion[32];
137   size_t osversion_len = sizeof (osversion) - 1;
138   static int osversion_name[2] = { CTL_KERN, KERN_OSRELEASE };
139   int major_vers;
140   char * version_p;
141   char * new_flag;
142 
143   if (sysctl (osversion_name, ARRAY_SIZE (osversion_name), osversion,
144 	      &osversion_len, NULL, 0) == -1)
145     {
146       warning (0, "sysctl for kern.osversion failed: %m");
147       return NULL;
148     }
149 
150   /* Try to parse the first two parts of the OS version number.  Warn
151      user and return if it doesn't make sense.  */
152   if (! ISDIGIT (osversion[0]))
153     goto parse_failed;
154   major_vers = osversion[0] - '0';
155   version_p = osversion + 1;
156   if (ISDIGIT (*version_p))
157     major_vers = major_vers * 10 + (*version_p++ - '0');
158   if (*version_p++ != '.')
159     goto parse_failed;
160 
161   /* Darwin20 sees a transition to macOS 11.  In this, it seems that the
162      mapping to macOS minor version is now shifted to the kernel minor
163      version - 1 (at least for the initial releases).  At this stage, we
164      don't know what macOS version will correspond to Darwin21.  */
165   if (major_vers >= 20)
166     {
167       int minor_vers = *version_p++ - '0';
168       if (ISDIGIT (*version_p))
169 	minor_vers = minor_vers * 10 + (*version_p++ - '0');
170       if (*version_p++ != '.')
171 	goto parse_failed;
172       if (minor_vers > 0)
173 	minor_vers -= 1; /* Kernel 20.3 => macOS 11.2.  */
174       /* It's not yet clear whether patch level will be considered.  */
175       asprintf (&new_flag, "11.%02d.00", minor_vers);
176     }
177   else if (major_vers - 4 <= 4)
178     /* On 10.4 and earlier, the old linker is used which does not
179        support three-component system versions.
180        FIXME: we should not assume this - a newer linker could be used.  */
181     asprintf (&new_flag, "10.%d", major_vers - 4);
182   else
183     /* Although the newer linker supports three-component system
184        versions, there's no guarantee that the minor version component
185        of the kernel and the system are the same. Apple's clang always
186        uses 0 as the minor version: do the same.  */
187     asprintf (&new_flag, "10.%d.0", major_vers - 4);
188 
189   return new_flag;
190 
191  parse_failed:
192   warning (0, "couldn%'t understand kern.osversion %q.*s",
193 	   (int) osversion_len, osversion);
194   return NULL;
195 }
196 #endif
197 
198 /* When running on a Darwin system and using that system's headers and
199    libraries, default the -mmacosx-version-min flag to be the version
200    of the system on which the compiler is running.
201 
202    When building cross or native cross compilers, default to the OSX
203    version of the target (as provided by the most specific target header
204    included in tm.h).  This may be overidden by setting the flag explicitly
205    (or by the MACOSX_DEPLOYMENT_TARGET environment).  */
206 
207 static const char *
darwin_default_min_version(void)208 darwin_default_min_version (void)
209 {
210   /* Try to retrieve the deployment target from the environment.  */
211   const char *new_flag = getenv ("MACOSX_DEPLOYMENT_TARGET");
212 
213   /* Apparently, an empty string for MACOSX_DEPLOYMENT_TARGET means
214      "use the default".  Or, possibly "use 10.1".  We choose
215      to ignore the environment variable, as if it was never set.  */
216   if (new_flag == NULL || new_flag[0] == 0)
217 #ifndef CROSS_DIRECTORY_STRUCTURE
218     /* Try to find the version from the kernel, if we fail - we print a
219        message and give up.  */
220     new_flag = darwin_find_version_from_kernel ();
221 #else
222     /* For cross-compilers, default to a minimum version determined by
223        the configuration. */
224     new_flag = DEF_MIN_OSX_VERSION;
225 #endif /* CROSS_DIRECTORY_STRUCTURE */
226 
227   if (new_flag != NULL)
228     {
229       const char *checked = validate_macosx_version_min (new_flag);
230       if (checked == NULL)
231 	{
232 	  warning (0, "could not understand version %s", new_flag);
233 	  return NULL;
234 	}
235       new_flag = xstrndup (checked, strlen (checked));
236     }
237   return new_flag;
238 }
239 
240 /* See if we can find the sysroot from the SDKROOT environment variable.  */
241 
242 static const char *
maybe_get_sysroot_from_sdkroot()243 maybe_get_sysroot_from_sdkroot ()
244 {
245   const char *maybe_sysroot = getenv ("SDKROOT");
246 
247   /* We'll use the same rules as the clang driver, for compatibility.
248      1) The path must be absolute
249      2) Ignore "/", that is the default anyway and we do not want the
250 	sysroot semantics to be applied to it.
251      3) It must exist (actually, we'll check it's readable too).  */
252 
253    if (maybe_sysroot  == NULL
254        || *maybe_sysroot != '/'
255        || strlen (maybe_sysroot) == 1
256        || access (maybe_sysroot, R_OK) == -1)
257     return NULL;
258 
259   return xstrndup (maybe_sysroot, strlen (maybe_sysroot));
260 }
261 
262 /* Translate -filelist and -framework options in *DECODED_OPTIONS
263    (size *DECODED_OPTIONS_COUNT) to use -Xlinker so that they are
264    considered to be linker inputs in the case that no other inputs are
265    specified.  Handling these options in DRIVER_SELF_SPECS does not
266    suffice because specs are too late to add linker inputs, and
267    handling them in LINK_SPEC does not suffice because the linker will
268    not be called if there are no other inputs.  When native, also
269    default the -mmacosx-version-min flag.  */
270 
271 void
darwin_driver_init(unsigned int * decoded_options_count,struct cl_decoded_option ** decoded_options)272 darwin_driver_init (unsigned int *decoded_options_count,
273 		    struct cl_decoded_option **decoded_options)
274 {
275   unsigned int i;
276   bool seenX86 = false;
277   bool seenX86_64 = false;
278   bool seenPPC = false;
279   bool seenPPC64 = false;
280   bool seenM32 = false;
281   bool seenM64 = false;
282   bool appendM32 = false;
283   bool appendM64 = false;
284   const char *vers_string = NULL;
285   bool seen_version_min = false;
286   bool seen_sysroot_p = false;
287 
288   for (i = 1; i < *decoded_options_count; i++)
289     {
290       if ((*decoded_options)[i].errors & CL_ERR_MISSING_ARG)
291 	continue;
292 
293       switch ((*decoded_options)[i].opt_index)
294 	{
295 	case OPT_arch:
296 	  /* Support provision of a single -arch xxxx flag as a means of
297 	     specifying the sub-target/multi-lib.  Translate this into -m32/64
298 	     as appropriate.  */
299 	  if (!strcmp ((*decoded_options)[i].arg, "i386"))
300 	    seenX86 = true;
301 	  else if (!strcmp ((*decoded_options)[i].arg, "x86_64"))
302 	    seenX86_64 = true;
303 	  else if (!strcmp ((*decoded_options)[i].arg, "ppc"))
304 	    seenPPC = true;
305 	  else if (!strcmp ((*decoded_options)[i].arg, "ppc64"))
306 	    seenPPC64 = true;
307 	  else
308 	    error ("this compiler does not support %s",
309 		   (*decoded_options)[i].arg);
310 	  /* Now we've examined it, drop the -arch arg.  */
311 	  if (*decoded_options_count > i) {
312 	    memmove (*decoded_options + i,
313 		     *decoded_options + i + 1,
314 		     ((*decoded_options_count - i - 1)
315 		      * sizeof (struct cl_decoded_option)));
316 	  }
317 	  --i;
318 	  --*decoded_options_count;
319 	  break;
320 
321 	case OPT_m32:
322 	  seenM32 = true;
323 	  break;
324 
325 	case OPT_m64:
326 	  seenM64 = true;
327 	  break;
328 
329 	case OPT_filelist:
330 	case OPT_framework:
331 	  ++*decoded_options_count;
332 	  *decoded_options = XRESIZEVEC (struct cl_decoded_option,
333 					 *decoded_options,
334 					 *decoded_options_count);
335 	  memmove (*decoded_options + i + 2,
336 		   *decoded_options + i + 1,
337 		   ((*decoded_options_count - i - 2)
338 		    * sizeof (struct cl_decoded_option)));
339 	  generate_option (OPT_Xlinker, (*decoded_options)[i].arg, 1,
340 			   CL_DRIVER, &(*decoded_options)[i + 1]);
341 	  generate_option (OPT_Xlinker,
342 			   (*decoded_options)[i].canonical_option[0], 1,
343 			   CL_DRIVER, &(*decoded_options)[i]);
344 	  break;
345 
346 	case OPT_mmacosx_version_min_:
347 	  seen_version_min = true;
348 	  vers_string =
349 	    validate_macosx_version_min ((*decoded_options)[i].arg);
350 	  if (vers_string == NULL)
351 	    warning (0, "%qs is not valid for %<-mmacosx-version-min%>",
352 		     (*decoded_options)[i].arg);
353 	  else if (vers_string == (*decoded_options)[i].arg)
354 	    vers_string = xstrndup ((*decoded_options)[i].arg, 32);
355 	  /* Now we've examined it, and verified/re-written, put it to
356 	     one side and append later.  */
357 	  if (*decoded_options_count > i) {
358 	    memmove (*decoded_options + i,
359 		     *decoded_options + i + 1,
360 		     ((*decoded_options_count - i - 1)
361 		      * sizeof (struct cl_decoded_option)));
362 	  }
363 	  --i;
364 	  --*decoded_options_count;
365 	  break;
366 
367 	case OPT__sysroot_:
368 	case OPT_isysroot:
369 	  seen_sysroot_p = true;
370 	  break;
371 
372 	default:
373 	  break;
374 	}
375     }
376 
377   /* Turn -arch xxxx into the appropriate -m32/-m64 flag.
378      If the User tried to specify multiple arch flags (which is possible with
379      some Darwin compilers) warn that this mode is not supported by this
380      compiler (and ignore the arch flags, which means that the default multi-
381      lib will be generated).  */
382   /* TODO: determine if these warnings would better be errors.  */
383 #if DARWIN_X86
384   if (seenPPC || seenPPC64)
385     warning (0, "this compiler does not support PowerPC (arch flags ignored)");
386   if (seenX86)
387     {
388       if (seenX86_64 || seenM64)
389 	warning (0, "%s conflicts with i386 (arch flags ignored)",
390 	        (seenX86_64? "x86_64": "m64"));
391       else if (! seenM32) /* Add -m32 if the User didn't. */
392 	appendM32 = true;
393     }
394   else if (seenX86_64)
395     {
396       if (seenX86 || seenM32)
397 	warning (0, "%s conflicts with x86_64 (arch flags ignored)",
398 		 (seenX86? "i386": "m32"));
399       else if (! seenM64) /* Add -m64 if the User didn't. */
400 	appendM64 = true;
401     }
402 #elif DARWIN_PPC
403   if (seenX86 || seenX86_64)
404     warning (0, "this compiler does not support X86 (arch flags ignored)");
405   if (seenPPC)
406     {
407       if (seenPPC64 || seenM64)
408 	warning (0, "%s conflicts with ppc (arch flags ignored)",
409 		 (seenPPC64? "ppc64": "m64"));
410       else if (! seenM32) /* Add -m32 if the User didn't. */
411 	appendM32 = true;
412     }
413   else if (seenPPC64)
414     {
415       if (seenPPC || seenM32)
416 	warning (0, "%s conflicts with ppc64 (arch flags ignored)",
417 		 (seenPPC? "ppc": "m32"));
418       else if (! seenM64) /* Add -m64 if the User didn't. */
419 	appendM64 = true;
420     }
421 #endif
422 
423   if (appendM32 || appendM64)
424     {
425       ++*decoded_options_count;
426       *decoded_options = XRESIZEVEC (struct cl_decoded_option,
427 				     *decoded_options,
428 				     *decoded_options_count);
429       generate_option (appendM32 ? OPT_m32 : OPT_m64, NULL, 1, CL_DRIVER,
430 		       &(*decoded_options)[*decoded_options_count - 1]);
431     }
432 
433   if (! seen_sysroot_p)
434     {
435       /* We will pick up an SDKROOT if we didn't specify a sysroot and treat
436 	 it as overriding any configure-time --with-sysroot.  */
437        const char *sdkroot = maybe_get_sysroot_from_sdkroot ();
438        if (sdkroot)
439 	{
440 	  ++*decoded_options_count;
441 	  *decoded_options = XRESIZEVEC (struct cl_decoded_option,
442 					 *decoded_options,
443 					 *decoded_options_count);
444 	  generate_option (OPT__sysroot_, sdkroot, 1, CL_DRIVER,
445 			   &(*decoded_options)[*decoded_options_count - 1]);
446 	}
447     }
448 
449   /* We will need to know the OS X version we're trying to build for here
450      so that we can figure out the mechanism and source for the sysroot to
451      be used.  */
452   if (! seen_version_min && *decoded_options_count > 1)
453     /* Not set by the User, try to figure it out.  */
454     vers_string = darwin_default_min_version ();
455 
456   /* Create and push a cleaned up version, plus the major version for
457      assemblers and other cases that need it.  */
458   if (vers_string != NULL)
459     {
460        ++*decoded_options_count;
461        *decoded_options = XRESIZEVEC (struct cl_decoded_option,
462 				      *decoded_options,
463 				      *decoded_options_count);
464       generate_option (OPT_mmacosx_version_min_, vers_string, 1, CL_DRIVER,
465 		       &(*decoded_options)[*decoded_options_count - 1]);
466 
467       char *asm_major = NULL;
468       const char *first_period = strchr(vers_string, '.');
469       if (first_period != NULL)
470 	{
471 	  const char *second_period = strchr(first_period+1, '.');
472 	  if (second_period  != NULL)
473 	    asm_major = xstrndup (vers_string, second_period-vers_string);
474 	  else
475 	    asm_major = xstrdup (vers_string);
476         }
477       /* Else we appear to have a weird macosx version with no major number.
478          Punt on this for now.  */
479       if (asm_major != NULL)
480         {
481 	  ++*decoded_options_count;
482 	  *decoded_options = XRESIZEVEC (struct cl_decoded_option,
483 					 *decoded_options,
484 					 *decoded_options_count);
485 	  generate_option (OPT_asm_macosx_version_min_, asm_major, 1, CL_DRIVER,
486 			  &(*decoded_options)[*decoded_options_count - 1]);
487         }
488     }
489 }
490