| /* Subroutines for the gcc driver. |
| Copyright (C) 2009-2022 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); |
| } |