blob: d8b0a7fd3f82a87b137e17599ebd648fc1cd8cfa [file] [log] [blame]
/* APPLE LOCAL file 5235474 5683689 */
/* Additional functions for the GCC driver on Darwin native.
Copyright (C) 2006, 2007 Free Software Foundation, Inc.
Contributed by Apple Computer Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to
the Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
#ifndef CROSS_DIRECTORY_STRUCTURE
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "gcc.h"
#include <sys/sysctl.h>
#include "xregex.h"
#ifndef SWITCH_TAKES_ARG
#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
#endif
#ifndef WORD_SWITCH_TAKES_ARG
#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
#endif
/* This function is used when running on a Darwin system and using that
system's headers and libraries. Unless specified otherwise by
command-line options or environment variables, this routine will
set the appropriate version specification flag to a default value.
The version flag used is based on VERS_TYPE, and is either:
DARWIN_VERSION_MACOSX to use -mmacosx-version-min and
DARWIN_VERSION_IPHONEOS to use -miphoneos-version-min. */
void
darwin_default_min_version (int * argc_p, char *** argv_p,
enum darwin_version_type vers_type)
{
const int argc = *argc_p;
char ** const argv = *argv_p;
int i;
char osversion[32];
size_t osversion_len = sizeof (osversion) - 1;
static int osversion_name[2] = { CTL_KERN, KERN_OSRELEASE };
char * version_p;
char * version_pend;
int major_vers;
char minor_vers[6];
static char new_flag[sizeof ("-mxxxxxx-version-min=99.99.99") + 6];
/* If the command-line is empty, just return. */
if (argc <= 1)
return;
/* Don't do this if the user has specified -b or -V at the start
of the command-line. */
if (argv[1][0] == '-'
&& (argv[1][1] == 'V' ||
((argv[1][1] == 'b') && (NULL != strchr(argv[1] + 2,'-')))))
return;
/* Don't do this if the user specified -mmacosx-version-min=,
-miphoneos-version-min, -mno-macosx-version-min, or
-mno-iphoneos-version-min. */
for (i = 1; i < argc; i++)
if (argv[i][0] == '-')
{
const char * const p = argv[i];
if (strncmp (p, "-mno-macosx-version-min", 23) == 0
|| strncmp (p, "-mno-iphoneos-version-min", 25) == 0
|| strncmp (p, "-mmacosx-version-min", 20) == 0
|| strncmp (p, "-miphoneos-version-min", 22) == 0)
return;
/* It doesn't count if it's an argument to a different switch. */
if (p[0] == '-'
&& ((SWITCH_TAKES_ARG (p[1]) > (p[2] != 0))
|| WORD_SWITCH_TAKES_ARG (p + 1)))
i++;
}
/* Retrieve the deployment target from the environment and insert
it as a flag. */
{
const char * macosx_deployment_target;
const char * iphoneos_deployment_target;
bool iphoneos_env_set, macosx_env_set;
macosx_deployment_target = getenv ("MACOSX_DEPLOYMENT_TARGET");
iphoneos_deployment_target = getenv ("IPHONEOS_DEPLOYMENT_TARGET");
/* We choose to ignore an environment variable set to an empty
string. */
macosx_env_set = macosx_deployment_target
&& macosx_deployment_target[0];
iphoneos_env_set = iphoneos_deployment_target
&& iphoneos_deployment_target[0];
if (macosx_env_set && iphoneos_env_set)
{
/* Conflicting DEPLOYMENT_TARGETs given. Don't emit a warning
for now (see rdar://5819018) -- just choose based on
VERS_TYPE. */
if (vers_type == DARWIN_VERSION_IPHONEOS)
macosx_env_set = 0;
else
iphoneos_env_set = 0;
}
if (macosx_env_set)
{
++*argc_p;
*argv_p = xmalloc (sizeof (char *) * *argc_p);
(*argv_p)[0] = argv[0];
(*argv_p)[1] = concat ("-mmacosx-version-min=",
macosx_deployment_target, NULL);
memcpy (*argv_p + 2, argv + 1, (argc - 1) * sizeof (char *));
return;
}
if (iphoneos_env_set)
{
++*argc_p;
*argv_p = xmalloc (sizeof (char *) * *argc_p);
(*argv_p)[0] = argv[0];
(*argv_p)[1] = concat ("-miphoneos-version-min=",
iphoneos_deployment_target, NULL);
memcpy (*argv_p + 2, argv + 1, (argc - 1) * sizeof (char *));
return;
}
}
/* For iPhone OS, if no version number is specified, we default to
2.0. */
if (vers_type == DARWIN_VERSION_IPHONEOS)
{
++*argc_p;
*argv_p = xmalloc (sizeof (char *) * *argc_p);
(*argv_p)[0] = argv[0];
(*argv_p)[1] = xstrdup ("-miphoneos-version-min=2.0");
memcpy (*argv_p + 2, argv + 1, (argc - 1) * sizeof (char *));
return;
}
gcc_assert (vers_type == DARWIN_VERSION_MACOSX);
/* Determine the version of the running OS. If we can't, warn user,
and do nothing. */
if (sysctl (osversion_name, ARRAY_SIZE (osversion_name), osversion,
&osversion_len, NULL, 0) == -1)
{
fprintf (stderr, "sysctl for kern.osversion failed: %s\n",
xstrerror (errno));
return;
}
/* Try to parse the first two parts of the OS version number. Warn
user and return if it doesn't make sense. */
if (! ISDIGIT (osversion[0]))
goto parse_failed;
major_vers = osversion[0] - '0';
version_p = osversion + 1;
if (ISDIGIT (*version_p))
major_vers = major_vers * 10 + (*version_p++ - '0');
if (major_vers > 4 + 9)
goto parse_failed;
if (*version_p++ != '.')
goto parse_failed;
version_pend = strchr(version_p, '.');
if (!version_pend)
goto parse_failed;
if (! ISDIGIT (*version_p))
goto parse_failed;
strncpy(minor_vers, version_p, version_pend - version_p);
minor_vers[version_pend - version_p] = '\0';
/* The major kernel version number is 4 plus the second OS version
component. */
if (major_vers - 4 <= 4)
/* On 10.4 and earlier, the old linker is used which does not
support three-component system versions. */
sprintf (new_flag, "-mmacosx-version-min=10.%d", major_vers - 4);
else
sprintf (new_flag, "-mmacosx-version-min=10.%d.%s", major_vers - 4,
minor_vers);
/* Add the new flag. */
++*argc_p;
*argv_p = xmalloc (sizeof (char *) * *argc_p);
(*argv_p)[0] = argv[0];
(*argv_p)[1] = new_flag;
memcpy (*argv_p + 2, argv + 1, (argc - 1) * sizeof (char *));
return;
parse_failed:
fprintf (stderr, "couldn't understand kern.osversion `%.*s'\n",
(int) osversion_len, osversion);
return;
}
#endif /* CROSS_DIRECTORY_STRUCTURE */