/* Subroutines for the gcc driver.
Copyright (C) 2009-2020 Free Software Foundation, Inc.
Contributed by Georg-Johann Lay <avr@gjlay.de>
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 3, 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 COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define IN_TARGET_CODE 1
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "diagnostic.h"
#include "tm.h"
// Remove -nodevicelib and -nodevicespecs from the command line if not needed.
#define X_NODEVLIB "%<nodevicelib %<nodevicespecs"
static const char dir_separator_str[] = { DIR_SEPARATOR, 0 };
/* Implement spec function `device-specs-fileĀ“.
Validate mcu name given with -mmcu option. Compose
-specs=<specs-file-name>%s. If everything went well then argv[0] is the
inflated (absolute) first device-specs directory and argv[1] is a device
or core name as supplied by -mmcu=*. When building GCC the path might be
relative. */
const char*
avr_devicespecs_file (int argc, const char **argv)
{
const char *mmcu = NULL;
#ifdef DEBUG_SPECS
if (verbose_flag)
fnotice (stderr, "Running spec function '%s' with %d args\n\n",
__FUNCTION__, argc);
#endif
switch (argc)
{
case 0:
fatal_error (input_location,
"bad usage of spec function %qs", "device-specs-file");
return X_NODEVLIB;
case 1:
if (strcmp ("device-specs", argv[0]) == 0)
{
/* FIXME: This means "device-specs%s" from avr.h:DRIVER_SELF_SPECS
has not been resolved to a path. That case can occur when the
c++ testsuite is run from the build directory. DejaGNU's
libgloss.exp:get_multilibs runs $compiler without -B, i.e.runs
xgcc without specifying a prefix. Without any prefix, there is
no means to find out where the specs files might be located.
get_multilibs runs xgcc --print-multi-lib, hence we don't actually
need information form a specs file and may skip it here. */
return X_NODEVLIB;
}
mmcu = AVR_MMCU_DEFAULT;
break;
default:
mmcu = argv[1];
// Allow specifying the same MCU more than once.
for (int i = 2; i < argc; i++)
if (strcmp (mmcu, argv[i]) != 0)
{
error ("specified option %qs more than once", "-mmcu");
return X_NODEVLIB;
}
break;
}
// Filter out silly -mmcu= arguments like "foo bar".
for (const char *s = mmcu; *s; s++)
if (!ISALNUM (*s)
&& '-' != *s
&& '_' != *s)
{
error ("strange device name %qs after %qs: bad character %qc",
mmcu, "-mmcu=", *s);
return X_NODEVLIB;
}
return concat ("%{!nodevicespecs:-specs=device-specs", dir_separator_str,
"specs-", mmcu, "%s} %<nodevicespecs"
#if defined (WITH_AVRLIBC)
" %{mmcu=avr*:" X_NODEVLIB "} %{!mmcu=*:" X_NODEVLIB "}",
#else
" " X_NODEVLIB,
#endif
NULL);
}
/* Re-build the -mdouble= and -mlong-double= options. This is needed
because these options are not independent of each other. */
const char*
avr_double_lib (int argc, const char **argv)
{
#if defined (WITH_DOUBLE64)
int dbl = 64;
#elif defined (WITH_DOUBLE32)
int dbl = 32;
#else
#error "align this with config.gcc"
#endif
#if defined (WITH_LONG_DOUBLE64)
int ldb = 64;
#elif defined (WITH_LONG_DOUBLE32)
int ldb = 32;
#else
#error "align this with config.gcc"
#endif
for (int i = 0; i < argc; i++)
{
if (strcmp (argv[i], "mdouble=32") == 0)
{
dbl = 32;
#ifdef HAVE_LONG_DOUBLE_IS_DOUBLE
ldb = dbl;
#endif
}
else if (strcmp (argv[i], "mdouble=64") == 0)
{
ldb = dbl = 64;
}
else if (strcmp (argv[i], "mlong-double=32") == 0)
{
ldb = dbl = 32;
}
else if (strcmp (argv[i], "mlong-double=64") == 0)
{
ldb = 64;
#ifdef HAVE_LONG_DOUBLE_IS_DOUBLE
dbl = ldb;
#endif
}
}
return concat (" %<mdouble=* -mdouble=", dbl == 32 ? "32" : "64",
" %<mlong-double=* -mlong-double=", ldb == 32 ? "32" : "64",
NULL);
}