Home | History | Annotate | Line # | Download | only in avr
      1 /* Subroutines for the gcc driver.
      2    Copyright (C) 2009-2022 Free Software Foundation, Inc.
      3    Contributed by Georg-Johann Lay <avr (at) gjlay.de>
      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 #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 
     32 static 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 
     43 const char*
     44 avr_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 		 // Return X_NODEVLIB when we are compiling for a core.  As
    109 		 // there are devices like AVR128DA32, a simple mmcu=avr* to
    110 		 // discriminate between cores and devices ceased to work,
    111 		 // hence use spec function no-devlib=avr_no_devlib from below.
    112 		 // See also PR107201.
    113 		 " %{mmcu=avr*:%:no-devlib(avr%*)} %{!mmcu=*:" X_NODEVLIB "}",
    114 #else
    115                  " " X_NODEVLIB,
    116 #endif
    117                  NULL);
    118 }
    119 
    120 
    121 /* Return X_NODEVLIB when ARGV[] contains a core like "avr5",
    122    otherwise return "".  */
    123 
    124 const char *
    125 avr_no_devlib (int argc, const char **argv)
    126 {
    127   for (int i = 0; i < argc; ++i)
    128     {
    129       if (avr_get_parch (argv[i]))
    130 	return X_NODEVLIB;
    131     }
    132 
    133   return "";
    134 }
    135 
    136 
    137 /* Re-build the -mdouble= and -mlong-double= options.  This is needed
    138    because these options are not independent of each other.  */
    139 
    140 const char *
    141 avr_double_lib (int argc, const char **argv)
    142 {
    143 #if defined (WITH_DOUBLE64)
    144   int dbl = 64;
    145 #elif defined (WITH_DOUBLE32)
    146   int dbl = 32;
    147 #else
    148 #error "align this with config.gcc"
    149 #endif
    150 
    151 #if defined (WITH_LONG_DOUBLE64)
    152   int ldb = 64;
    153 #elif defined (WITH_LONG_DOUBLE32)
    154   int ldb = 32;
    155 #else
    156 #error "align this with config.gcc"
    157 #endif
    158 
    159   for (int i = 0; i < argc; i++)
    160     {
    161       if (strcmp (argv[i], "mdouble=32") == 0)
    162         {
    163           dbl = 32;
    164 #ifdef HAVE_LONG_DOUBLE_IS_DOUBLE
    165           ldb = dbl;
    166 #endif
    167         }
    168       else if (strcmp (argv[i], "mdouble=64") == 0)
    169         {
    170           ldb = dbl = 64;
    171         }
    172       else if (strcmp (argv[i], "mlong-double=32") == 0)
    173         {
    174           ldb = dbl = 32;
    175         }
    176       else if (strcmp (argv[i], "mlong-double=64") == 0)
    177         {
    178           ldb = 64;
    179 #ifdef HAVE_LONG_DOUBLE_IS_DOUBLE
    180           dbl = ldb;
    181 #endif
    182         }
    183     }
    184 
    185   return concat (" %<mdouble=* -mdouble=", dbl == 32 ? "32" : "64",
    186                  " %<mlong-double=* -mlong-double=", ldb == 32 ? "32" : "64",
    187                  NULL);
    188 }
    189