Handle missing vfprintf() & _doprnt() functions with linked in modules,
[gcc.git] / gcc / gcc.c
index c558de3beac0b87bac2cbda7684f8a86ddf2e97b..1941aed2751d7dff8abae731def47436c80b5556 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -33,17 +33,16 @@ compilation is specified by a string called a "spec".  */
 \f
 #include "config.h"
 
-#include "gansidecl.h"
-#include "system.h"
-
-#include <signal.h>
-#include <sys/stat.h>
 #ifdef __STDC__
 #include <stdarg.h>
 #else
 #include <varargs.h>
 #endif
+#include "system.h"
+#include <signal.h>
+#include <sys/stat.h>
 
+#include "gansidecl.h"
 #include "obstack.h"
 
 
@@ -52,6 +51,7 @@ extern int pexecute PROTO ((const char *, char * const *, const char *,
                            const char *, char **, char **, int));
 extern int pwait PROTO ((int, int *, int));
 extern char *update_path PROTO((char *, char *));
+extern void set_std_prefix PROTO((char *, int));
 /* Flag arguments to pexecute.  */
 #define PEXECUTE_FIRST   1
 #define PEXECUTE_LAST    2
@@ -75,11 +75,6 @@ extern char *update_path PROTO((char *, char *));
 #define exit __posix_exit
 #endif
 
-/* Define O_RDONLY if the system hasn't defined it for us.  */
-#ifndef O_RDONLY
-#define O_RDONLY 0
-#endif
-
 #ifdef USG
 #define vfork fork
 #endif /* USG */
@@ -122,6 +117,10 @@ static char dir_separator_str[] = {DIR_SEPARATOR, 0};
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
+#ifndef GET_ENVIRONMENT
+#define GET_ENVIRONMENT(ENV_VALUE,ENV_NAME) ENV_VALUE = getenv (ENV_NAME)
+#endif
+
 extern char *choose_temp_base PROTO((void));
 
 #ifndef HAVE_STRERROR
@@ -247,21 +246,15 @@ static void print_multilib_info   PROTO((void));
 static void pfatal_with_name   PROTO((char *));
 static void perror_with_name   PROTO((char *));
 static void pfatal_pexecute    PROTO((char *, char *));
-#ifdef HAVE_VPRINTF
 static void fatal              PVPROTO((char *, ...));
 static void error              PVPROTO((char *, ...));
-#else
-/* We must not provide any prototype here, even if ANSI C.  */
-static void fatal              PROTO(());
-static void error              PROTO(());
-#endif
 
 void fancy_abort ();
 char *xmalloc ();
 char *xrealloc ();
 
 #ifdef LANG_SPECIFIC_DRIVER
-extern void lang_specific_driver PROTO ((void (*) (), int *, char ***));
+extern void lang_specific_driver PROTO ((void (*) PVPROTO((char *, ...)), int *, char ***, int *));
 #endif
 \f
 /* Specs are strings containing lines, each of which (if not blank)
@@ -473,6 +466,10 @@ proper position among the other output files.  */
 #endif
 #endif
 
+#ifndef LINKER_NAME
+#define LINKER_NAME "collect2"
+#endif
+
 static char *cpp_spec = CPP_SPEC;
 static char *cpp_predefines = CPP_PREDEFINES;
 static char *cc1_spec = CC1_SPEC;
@@ -486,6 +483,7 @@ static char *libgcc_spec = LIBGCC_SPEC;
 static char *endfile_spec = ENDFILE_SPEC;
 static char *startfile_spec = STARTFILE_SPEC;
 static char *switches_need_spaces = SWITCHES_NEED_SPACES;
+static char *linker_name_spec = LINKER_NAME;
 
 /* Some compilers have limits on line lengths, and the multilib_select
    and/or multilib_matches strings can be very long, so we build them at
@@ -704,7 +702,7 @@ static int n_default_compilers
 /* Don't generate -L options.  */
 static char *link_command_spec = "\
 %{!fsyntax-only: \
- %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+ %{!c:%{!M:%{!MM:%{!E:%{!S:%(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
                        %{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
                        %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
                        %{static:} %{L*} %o\
@@ -716,7 +714,7 @@ static char *link_command_spec = "\
 /* Use -L.  */
 static char *link_command_spec = "\
 %{!fsyntax-only: \
- %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+ %{!c:%{!M:%{!MM:%{!E:%{!S:%(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
                        %{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
                        %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
                        %{static:} %{L*} %D %o\
@@ -1089,6 +1087,7 @@ static struct spec_list static_specs[] = {
   INIT_STATIC_SPEC ("multilib_defaults",       &multilib_defaults),
   INIT_STATIC_SPEC ("multilib_extra",          &multilib_extra),
   INIT_STATIC_SPEC ("multilib_matches",                &multilib_matches),
+  INIT_STATIC_SPEC ("linker",                  &linker_name_spec),
 };
 
 #ifdef EXTRA_SPECS             /* additional specs needed */
@@ -2126,6 +2125,7 @@ execute ()
   commands[0].prog = argbuf[0]; /* first command.  */
   commands[0].argv = &argbuf[0];
   string = find_a_file (&exec_prefixes, commands[0].prog, X_OK);
+
   if (string)
     commands[0].argv[0] = string;
 
@@ -2280,6 +2280,11 @@ static struct infile *infiles;
 
 static int n_infiles;
 
+/* This counts the number of libraries added by LANG_SPECIFIC_DRIVER, so that
+   we can tell if there were any user supplied any files or libraries.  */
+
+static int added_libraries;
+
 /* And a vector of corresponding output files is made up later.  */
 
 static char **outfiles;
@@ -2358,10 +2363,11 @@ process_command (argc, argv)
   int have_o = 0;
   int lang_n_infiles = 0;
 
-  gcc_exec_prefix = getenv ("GCC_EXEC_PREFIX");
+  GET_ENVIRONMENT (gcc_exec_prefix, "GCC_EXEC_PREFIX");
 
   n_switches = 0;
   n_infiles = 0;
+  added_libraries = 0;
 
   /* Figure compiler version from version string.  */
 
@@ -2379,6 +2385,20 @@ process_command (argc, argv)
 
   if (gcc_exec_prefix)
     {
+      int len = strlen (gcc_exec_prefix);
+      if (len > sizeof ("/lib/gcc-lib/")-1
+         && (gcc_exec_prefix[len-1] == '/'
+             || gcc_exec_prefix[len-1] == DIR_SEPARATOR))
+       {
+         temp = gcc_exec_prefix + len - sizeof ("/lib/gcc-lib/") + 1;
+         if ((*temp == '/' || *temp == DIR_SEPARATOR)
+             && strncmp (temp+1, "lib", 3) == 0
+             && (temp[4] == '/' || temp[4] == DIR_SEPARATOR)
+             && strncmp (temp+5, "gcc-lib", 7) == 0)
+           len -= sizeof ("/lib/gcc-lib/") - 1;
+       }
+
+      set_std_prefix (gcc_exec_prefix, len);
       add_prefix (&exec_prefixes, gcc_exec_prefix, "GCC", 0, 0, NULL_PTR);
       add_prefix (&startfile_prefixes, gcc_exec_prefix, "GCC", 0, 0, NULL_PTR);
     }
@@ -2386,7 +2406,7 @@ process_command (argc, argv)
   /* COMPILER_PATH and LIBRARY_PATH have values
      that are lists of directory names with colons.  */
 
-  temp = getenv ("COMPILER_PATH");
+  GET_ENVIRONMENT (temp, "COMPILER_PATH");
   if (temp)
     {
       char *startp, *endp;
@@ -2420,7 +2440,7 @@ process_command (argc, argv)
        }
     }
 
-  temp = getenv ("LIBRARY_PATH");
+  GET_ENVIRONMENT (temp, "LIBRARY_PATH");
   if (temp && *cross_compile == '0')
     {
       char *startp, *endp;
@@ -2453,7 +2473,7 @@ process_command (argc, argv)
     }
 
   /* Use LPATH like LIBRARY_PATH (for the CMU build program).  */
-  temp = getenv ("LPATH");
+  GET_ENVIRONMENT (temp, "LPATH");
   if (temp && *cross_compile == '0')
     {
       char *startp, *endp;
@@ -2490,7 +2510,7 @@ process_command (argc, argv)
 
 #ifdef LANG_SPECIFIC_DRIVER
   /* Do language-specific adjustment/addition of flags.  */
-  lang_specific_driver (fatal, &argc, &argv);
+  lang_specific_driver (fatal, &argc, &argv, &added_libraries);
 #endif
 
   /* Scan argv twice.  Here, the first time, just count how many switches
@@ -2509,7 +2529,7 @@ process_command (argc, argv)
        }
       else if (! strcmp (argv[i], "-dumpversion"))
        {
-         printf ("%s\n", version_string);
+         printf ("%s\n", spec_version);
          exit (0);
        }
       else if (! strcmp (argv[i], "-dumpmachine"))
@@ -2728,6 +2748,36 @@ process_command (argc, argv)
                spec_version = p + 1;
              compiler_version = spec_version;
              warn_std_ptr = &warn_std;
+
+             /* Validate the version number.  Use the same checks
+                done when inserting it into a spec.
+
+                The format of the version string is
+                ([^0-9]*-)?[0-9]+[.][0-9]+([.][0-9]+)?([- ].*)?  */
+             {
+               char *v = compiler_version;
+
+               /* Ignore leading non-digits.  i.e. "foo-" in "foo-2.7.2".  */
+               while (! ISDIGIT (*v))
+                 v++;
+
+               if (v > compiler_version && v[-1] != '-')
+                 fatal ("invalid version number format");
+
+               /* Set V after the first period.  */
+               while (ISDIGIT (*v))
+                 v++;
+
+               if (*v != '.')
+                 fatal ("invalid version number format");
+
+               v++;
+               while (ISDIGIT (*v))
+                 v++;
+
+               if (*v != 0 && *v != ' ' && *v != '.' && *v != '-')
+                 fatal ("invalid version number format");
+             }
              break;
 
            case 'c':
@@ -2766,7 +2816,7 @@ process_command (argc, argv)
     }
 
   if (have_c && have_o && lang_n_infiles > 1)
-    fatal ("cannot specify -o with -c and multiple compilations");
+    fatal ("cannot specify -o with -c or -S and multiple compilations");
 
   /* Set up the search paths before we go looking for config files.  */
 
@@ -2883,23 +2933,23 @@ process_command (argc, argv)
          for (j = 4; argv[i][j]; j++)
            if (argv[i][j] == ',')
              {
-               infiles[n_infiles].language = 0;
+               infiles[n_infiles].language = "*";
                infiles[n_infiles++].name
                  = save_string (argv[i] + prev, j - prev);
                prev = j + 1;
              }
          /* Record the part after the last comma.  */
-         infiles[n_infiles].language = 0;
+         infiles[n_infiles].language = "*";
          infiles[n_infiles++].name = argv[i] + prev;
        }
       else if (strcmp (argv[i], "-Xlinker") == 0)
        {
-         infiles[n_infiles].language = 0;
+         infiles[n_infiles].language = "*";
          infiles[n_infiles++].name = argv[++i];
        }
       else if (strncmp (argv[i], "-l", 2) == 0)
        {
-         infiles[n_infiles].language = 0;
+         infiles[n_infiles].language = "*";
          infiles[n_infiles++].name = argv[i];
        }
       else if (strcmp (argv[i], "-specs") == 0)
@@ -3804,13 +3854,12 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                      char *x = (char *) alloca (strlen (name) * 2 + 1);
                      char *buf = x;
                      char *y = name;
+                     int flag = 0;
 
                      /* Copy all of NAME into BUF, but put __ after
                         every -D and at the end of each arg,  */
                      while (1)
                        {
-                         int flag;
-
                          if (! strncmp (y, "-D", 2))
                            {
                              *x++ = '-';
@@ -4416,7 +4465,7 @@ main (argc, argv)
        first_time = FALSE;
        obstack_grow (&collect_obstack, "'-", 2);
         q = switches[i].part1;
-       while ((p = (char *) index (q,'\'')))
+       while ((p = index (q,'\'')))
           {
             obstack_grow (&collect_obstack, q, p-q);
             obstack_grow (&collect_obstack, "'\\''", 4);
@@ -4429,7 +4478,7 @@ main (argc, argv)
          {
            obstack_grow (&collect_obstack, " '", 2);
            q = *args;
-           while ((p = (char *) index (q,'\'')))
+           while ((p = index (q,'\'')))
              {
                obstack_grow (&collect_obstack, q, p-q);
                obstack_grow (&collect_obstack, "'\\''", 4);
@@ -4510,7 +4559,15 @@ main (argc, argv)
         as a unit.  If GCC_EXEC_PREFIX is defined, base
         standard_startfile_prefix on that as well.  */
       if (*standard_startfile_prefix == '/'
-         || *standard_startfile_prefix == DIR_SEPARATOR)
+         || *standard_startfile_prefix == DIR_SEPARATOR
+         || *standard_startfile_prefix == '$'
+#ifdef __MSDOS__
+         /* Check for disk name on MS-DOS-based systems.  */
+          || (standard_startfile_prefix[1] == ':'
+             && (standard_startfile_prefix[2] == DIR_SEPARATOR
+                 || standard_startfile_prefix[2] == '/'))
+#endif
+         )
        add_prefix (&startfile_prefixes, standard_startfile_prefix, "BINUTILS",
                    0, 0, NULL_PTR);
       else
@@ -4633,7 +4690,7 @@ main (argc, argv)
        exit (0);
     }
 
-  if (n_infiles == 0)
+  if (n_infiles == added_libraries)
     fatal ("No input files");
 
   /* Make a place to record the compiler output file names
@@ -4741,6 +4798,13 @@ main (argc, argv)
     {
       int tmp = execution_count;
 
+      /* We'll use ld if we can't find collect2. */
+      if (! strcmp (linker_name_spec, "collect2"))
+       {
+         char *s = find_a_file (&exec_prefixes, "collect2", X_OK);
+         if (s == NULL)
+           linker_name_spec = "ld";
+       }
       /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
         for collect.  */
       putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH=");
@@ -4778,7 +4842,7 @@ main (argc, argv)
 
 /* Find the proper compilation spec for the file name NAME,
    whose length is LENGTH.  LANGUAGE is the specified language,
-   or 0 if none specified.  */
+   or 0 if this file is to be passed to the linker.  */
 
 static struct compiler *
 lookup_compiler (name, length, language)
@@ -4788,19 +4852,19 @@ lookup_compiler (name, length, language)
 {
   struct compiler *cp;
 
-  /* Look for the language, if one is spec'd.  */
+  /* If this was specified by the user to be a linker input, indicate that. */
+  if (language != 0 && language[0] == '*')
+    return 0;
+
+  /* Otherwise, look for the language, if one is spec'd.  */
   if (language != 0)
     {
       for (cp = compilers + n_compilers - 1; cp >= compilers; cp--)
-       {
-         if (language != 0)
-           {
-             if (cp->suffix[0] == '@'
-                 && !strcmp (cp->suffix + 1, language))
-               return cp;
-           }
-       }
+       if (cp->suffix[0] == '@' && !strcmp (cp->suffix + 1, language))
+         return cp;
+
       error ("language %s not recognized", language);
+      return 0;
     }
 
   /* Look for a suffix.  */
@@ -4808,23 +4872,24 @@ lookup_compiler (name, length, language)
     {
       if (/* The suffix `-' matches only the file name `-'.  */
          (!strcmp (cp->suffix, "-") && !strcmp (name, "-"))
-         ||
-         (strlen (cp->suffix) < length
-          /* See if the suffix matches the end of NAME.  */
+         || (strlen (cp->suffix) < length
+             /* See if the suffix matches the end of NAME.  */
 #ifdef OS2
-          && (!strcmp (cp->suffix,
-                       name + length - strlen (cp->suffix))
-           || !strpbrk (cp->suffix, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
-            && !strcasecmp (cp->suffix,
-                         name + length - strlen (cp->suffix)))))
+             && ((!strcmp (cp->suffix,
+                          name + length - strlen (cp->suffix))
+                  || !strpbrk (cp->suffix, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
+                 && !strcasecmp (cp->suffix,
+                                 name + length - strlen (cp->suffix)))
 #else
-          && !strcmp (cp->suffix,
-                      name + length - strlen (cp->suffix))))
+             && !strcmp (cp->suffix,
+                         name + length - strlen (cp->suffix))
 #endif
+        ))
        {
          if (cp->spec[0][0] == '@')
            {
              struct compiler *new;
+
              /* An alias entry maps a suffix to a language.
                 Search for the language; pass 0 for NAME and LENGTH
                 to avoid infinite recursion if language not found.
@@ -4836,6 +4901,7 @@ lookup_compiler (name, length, language)
                     (char *) new->spec, sizeof new->spec);
              return new;
            }
+
          /* A non-alias entry: return it.  */
          return cp;
        }
@@ -4950,6 +5016,8 @@ pfatal_pexecute (errmsg_fmt, errmsg_arg)
      char *errmsg_fmt;
      char *errmsg_arg;
 {
+  int save_errno = errno;
+
   if (errmsg_arg)
     {
       /* Space for trailing '\0' is in %s.  */
@@ -4958,7 +5026,7 @@ pfatal_pexecute (errmsg_fmt, errmsg_arg)
       errmsg_fmt = msg;
     }
 
-  fatal ("%s: %s", errmsg_fmt, my_strerror (errno));
+  fatal ("%s: %s", errmsg_fmt, my_strerror (save_errno));
 }
 
 /* More 'friendly' abort that prints the line and file.
@@ -4970,8 +5038,6 @@ fancy_abort ()
   fatal ("Internal gcc abort.");
 }
 \f
-#ifdef HAVE_VPRINTF
-
 /* Output an error message and exit */
 
 static void
@@ -5016,29 +5082,6 @@ error VPROTO((char *format, ...))
 
   fprintf (stderr, "\n");
 }
-
-#else /* not HAVE_VPRINTF */
-
-static void
-fatal (msg, arg1, arg2)
-     char *msg, *arg1, *arg2;
-{
-  error (msg, arg1, arg2);
-  delete_temp_files ();
-  exit (1);
-}
-
-static void
-error (msg, arg1, arg2)
-     char *msg, *arg1, *arg2;
-{
-  fprintf (stderr, "%s: ", programname);
-  fprintf (stderr, msg, arg1, arg2);
-  fprintf (stderr, "\n");
-}
-
-#endif /* not HAVE_VPRINTF */
-
 \f
 static void
 validate_all_switches ()