1/* Subroutines for the gcc driver.
2   Copyright (C) 2009-2020 Free Software Foundation, Inc.
3   Contributed by Georg-Johann Lay <avr@gjlay.de>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3.  If not see
19<http://www.gnu.org/licenses/>.  */
20
21#define IN_TARGET_CODE 1
22
23#include "config.h"
24#include "system.h"
25#include "coretypes.h"
26#include "diagnostic.h"
27#include "tm.h"
28
29// Remove -nodevicelib and -nodevicespecs from the command line if not needed.
30#define X_NODEVLIB "%<nodevicelib %<nodevicespecs"
31
32static const char dir_separator_str[] = { DIR_SEPARATOR, 0 };
33
34
35/* Implement spec function `device-specs-file��.
36
37   Validate mcu name given with -mmcu option. Compose
38   -specs=<specs-file-name>%s. If everything went well then argv[0] is the
39   inflated (absolute) first device-specs directory and argv[1] is a device
40   or core name as supplied by -mmcu=*. When building GCC the path might be
41   relative.  */
42
43const char*
44avr_devicespecs_file (int argc, const char **argv)
45{
46  const char *mmcu = NULL;
47
48#ifdef DEBUG_SPECS
49  if (verbose_flag)
50    fnotice (stderr, "Running spec function '%s' with %d args\n\n",
51             __FUNCTION__, argc);
52#endif
53
54  switch (argc)
55    {
56    case 0:
57      fatal_error (input_location,
58                   "bad usage of spec function %qs", "device-specs-file");
59      return X_NODEVLIB;
60
61    case 1:
62      if (strcmp ("device-specs", argv[0]) == 0)
63        {
64          /* FIXME:  This means "device-specs%s" from avr.h:DRIVER_SELF_SPECS
65             has not been resolved to a path.  That case can occur when the
66             c++ testsuite is run from the build directory.  DejaGNU's
67             libgloss.exp:get_multilibs runs $compiler without -B, i.e.runs
68             xgcc without specifying a prefix.  Without any prefix, there is
69             no means to find out where the specs files might be located.
70             get_multilibs runs xgcc --print-multi-lib, hence we don't actually
71             need information form a specs file and may skip it here.  */
72          return X_NODEVLIB;
73        }
74
75      mmcu = AVR_MMCU_DEFAULT;
76      break;
77
78    default:
79      mmcu = argv[1];
80
81      // Allow specifying the same MCU more than once.
82
83      for (int i = 2; i < argc; i++)
84	if (strcmp (mmcu, argv[i]) != 0)
85          {
86            error ("specified option %qs more than once", "-mmcu");
87            return X_NODEVLIB;
88          }
89
90      break;
91    }
92
93  // Filter out silly -mmcu= arguments like "foo bar".
94
95  for (const char *s = mmcu; *s; s++)
96    if (!ISALNUM (*s)
97        && '-' != *s
98        && '_' != *s)
99      {
100        error ("strange device name %qs after %qs: bad character %qc",
101               mmcu, "-mmcu=", *s);
102        return X_NODEVLIB;
103      }
104
105  return concat ("%{!nodevicespecs:-specs=device-specs", dir_separator_str,
106				 "specs-", mmcu, "%s} %<nodevicespecs"
107#if defined (WITH_AVRLIBC)
108                 " %{mmcu=avr*:" X_NODEVLIB "} %{!mmcu=*:" X_NODEVLIB "}",
109#else
110                 " " X_NODEVLIB,
111#endif
112                 NULL);
113}
114
115
116/* Re-build the -mdouble= and -mlong-double= options.  This is needed
117   because these options are not independent of each other.  */
118
119const char*
120avr_double_lib (int argc, const char **argv)
121{
122#if defined (WITH_DOUBLE64)
123  int dbl = 64;
124#elif defined (WITH_DOUBLE32)
125  int dbl = 32;
126#else
127#error "align this with config.gcc"
128#endif
129
130#if defined (WITH_LONG_DOUBLE64)
131  int ldb = 64;
132#elif defined (WITH_LONG_DOUBLE32)
133  int ldb = 32;
134#else
135#error "align this with config.gcc"
136#endif
137
138  for (int i = 0; i < argc; i++)
139    {
140      if (strcmp (argv[i], "mdouble=32") == 0)
141        {
142          dbl = 32;
143#ifdef HAVE_LONG_DOUBLE_IS_DOUBLE
144          ldb = dbl;
145#endif
146        }
147      else if (strcmp (argv[i], "mdouble=64") == 0)
148        {
149          ldb = dbl = 64;
150        }
151      else if (strcmp (argv[i], "mlong-double=32") == 0)
152        {
153          ldb = dbl = 32;
154        }
155      else if (strcmp (argv[i], "mlong-double=64") == 0)
156        {
157          ldb = 64;
158#ifdef HAVE_LONG_DOUBLE_IS_DOUBLE
159          dbl = ldb;
160#endif
161        }
162    }
163
164  return concat (" %<mdouble=* -mdouble=", dbl == 32 ? "32" : "64",
165                 " %<mlong-double=* -mlong-double=", ldb == 32 ? "32" : "64",
166                 NULL);
167}
168