#ifndef _WIN32
#include <sys/file.h> /* May get R_OK, etc. on some systems. */
-#else
-#include <process.h>
-int __spawnv ();
-int __spawnvp ();
#endif
#include "config.h"
#define X_OK 1
#endif
+/* ??? Need to find a GCC header to put these in. */
+extern int pexecute PROTO ((const char *, char * const *, const char *,
+ const char *, char **, char **, int));
+extern int pwait PROTO ((int, int *, int));
+/* Flag arguments to pexecute. */
+#define PEXECUTE_FIRST 1
+#define PEXECUTE_LAST 2
+#define PEXECUTE_SEARCH 4
+#define PEXECUTE_VERBOSE 8
+
#ifndef WIFSIGNALED
#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
#endif
#define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
#endif
-/* Define O_RDONLY if the system hasn't defined it for us. */
+/* Define O_RDONLY if the system hasn't defined it for us. */
#ifndef O_RDONLY
#define O_RDONLY 0
#endif
#define EXECUTABLE_SUFFIX ""
#endif
-/* By default, the suffix for object files is ".o". */
+/* By default, the suffix for object files is ".o". */
#ifdef OBJECT_SUFFIX
#define HAVE_OBJECT_SUFFIX
#else
extern char *strerror();
#endif
-extern int execv (), execvp ();
-
/* If a stage of compilation returns an exit status >= 1,
compilation of that file ceases. */
static char *print_file_name = NULL;
-/* As print_file_name, but search for executable file. */
+/* As print_file_name, but search for executable file. */
static char *print_prog_name = NULL;
static void print_multilib_info PROTO((void));
static void pfatal_with_name PROTO((char *));
static void perror_with_name PROTO((char *));
-static void perror_exec PROTO((char *));
+static void pfatal_pexecute PROTO((char *, char *));
#ifdef HAVE_VPRINTF
static void fatal PVPROTO((char *, ...));
static void error PVPROTO((char *, ...));
static char *switches_need_spaces = SWITCHES_NEED_SPACES;
/* Some compilers have limits on line lengths, and the multilib_select
- string can be very long, so we build it at run time. */
+ and/or multilib_matches strings can be very long, so we build them at
+ run time. */
static struct obstack multilib_obstack;
-static char *multilib_raw[] = {
-#include "multilib.h"
-};
static char *multilib_select;
+static char *multilib_matches;
+static char *multilib_defaults;
+#include "multilib.h"
+
+/* Check whether a particular argument is a default argument. */
+
+#ifndef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "" }
+#endif
+
+static char *multilib_defaults_raw[] = MULTILIB_DEFAULTS;
#ifdef EXTRA_SPECS
static struct { char *name, *spec; } extra_specs[] = { EXTRA_SPECS };
static struct compiler default_compilers[] =
{
+ /* Add lists of suffixes of known languages here. If those languages
+ were no present when we built the driver, we will hit these copies
+ and given a more meaningful error than "file not used since
+ linking is not done". */
+ {".cc", "#C++"}, {".cxx", "#C++"}, {".cpp", "#C++"}, {".c++", "#C++"},
+ {".C", "#C++"}, {".ads", "#Ada"}, {".adb", "#Ada"}, {".ada", "#Ada"},
+ {".f", "#Fortran"}, {".for", "#Fortran"}, {".F", "#Fortran"},
+ {".fpp", "#Fortran"},
+ /* Next come the entries for C. */
{".c", "@c"},
{"@c",
"cpp -lang-c%{ansi:89} %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
my_strerror(e)
int e;
{
-
#ifdef HAVE_STRERROR
+
return strerror(e);
#else
return p;
}
\f
-/* Structure to keep track of the specs that have been defined so far. These
- are accessed using %(specname) or %[specname] in a compiler or link spec. */
+/* Structure to keep track of the specs that have been defined so far.
+ These are accessed using %(specname) or %[specname] in a compiler
+ or link spec. */
struct spec_list
{
- char *name; /* Name of the spec. */
- char *spec; /* The spec itself. */
- struct spec_list *next; /* Next spec in linked list. */
+ char *name; /* Name of the spec. */
+ char *spec; /* The spec itself. */
+ struct spec_list *next; /* Next spec in linked list. */
};
-/* List of specs that have been defined so far. */
+/* List of specs that have been defined so far. */
static struct spec_list *specs = (struct spec_list *) 0;
\f
/* Change the value of spec NAME to SPEC. If SPEC is empty, then the spec is
removed; If the spec starts with a + then SPEC is added to the end of the
- current spec. */
+ current spec. */
static void
set_spec (name, spec)
cross_compile = atoi (sl->spec);
else if (! strcmp (name, "multilib"))
multilib_select = sl->spec;
+ else if (! strcmp (name, "multilib_matches"))
+ multilib_matches = sl->spec;
+ else if (! strcmp (name, "multilib_extra"))
+ multilib_extra = sl->spec;
+ else if (! strcmp (name, "multilib_defaults"))
+ multilib_defaults = sl->spec;
#ifdef EXTRA_SPECS
else
{
static char *programname;
\f
-/* Structures to keep track of prefixes to try when looking for files. */
+/* Structures to keep track of prefixes to try when looking for files. */
struct prefix_list
{
- char *prefix; /* String to prepend to the path. */
- struct prefix_list *next; /* Next in linked list. */
+ char *prefix; /* String to prepend to the path. */
+ struct prefix_list *next; /* Next in linked list. */
int require_machine_suffix; /* Don't use without machine_suffix. */
/* 2 means try both machine_suffix and just_machine_suffix. */
int *used_flag_ptr; /* 1 if a file was found with this prefix. */
char *name; /* Name of this list (used in config stuff) */
};
-/* List of prefixes to try when looking for executables. */
+/* List of prefixes to try when looking for executables. */
static struct path_prefix exec_prefixes = { 0, 0, "exec" };
-/* List of prefixes to try when looking for startup (crt0) files. */
+/* List of prefixes to try when looking for startup (crt0) files. */
static struct path_prefix startfile_prefixes = { 0, 0, "startfile" };
return obstack_finish (&collect_obstack);
}
-/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables for collect. */
+/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
+ for collect. */
static void
putenv_from_prefixes (paths, env_var)
\f
/* Search for NAME using the prefix list PREFIXES. MODE is passed to
access to check permissions.
- Return 0 if not found, otherwise return its name, allocated with malloc. */
+ Return 0 if not found, otherwise return its name, allocated with malloc. */
static char *
find_a_file (pprefix, name, mode)
}
}
-/* Get rid of all prefixes built up so far in *PLISTP. */
+/* Get rid of all prefixes built up so far in *PLISTP. */
static void
free_path_prefix (pprefix)
}
pprefix->plist = (struct prefix_list *) 0;
}
-\f
-/* stdin file number. */
-#define STDIN_FILE_NO 0
-
-/* stdout file number. */
-#define STDOUT_FILE_NO 1
-
-/* value of `pipe': port index for reading. */
-#define READ_PORT 0
-
-/* value of `pipe': port index for writing. */
-#define WRITE_PORT 1
-
-/* Pipe waiting from last process, to be used as input for the next one.
- Value is STDIN_FILE_NO if no pipe is waiting
- (i.e. the next command is the first of a group). */
-
-static int last_pipe_input;
-
-/* Fork one piped subcommand. FUNC is the system call to use
- (either execv or execvp). ARGV is the arg vector to use.
- NOT_LAST is nonzero if this is not the last subcommand
- (i.e. its output should be piped to the next one.) */
-
-#ifdef __MSDOS__
-
-#include <process.h>
-static int
-pexecute (search_flag, program, argv, not_last)
- int search_flag;
- char *program;
- char *argv[];
- int not_last;
-{
-#ifdef __GO32__
- int i = (search_flag ? spawnv : spawnvp) (1, program, argv);
-#else
- char *scmd, *rf;
- FILE *argfile;
- int i, el = search_flag ? 0 : 4;
-
- scmd = (char *) xmalloc (strlen (program) + strlen (temp_filename) + 6 + el);
- rf = scmd + strlen(program) + 2 + el;
- sprintf (scmd, "%s%s @%s.gp", program,
- (search_flag ? "" : ".exe"), temp_filename);
- argfile = fopen (rf, "w");
- if (argfile == 0)
- pfatal_with_name (rf);
-
- for (i=1; argv[i]; i++)
- {
- char *cp;
- for (cp = argv[i]; *cp; cp++)
- {
- if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
- fputc ('\\', argfile);
- fputc (*cp, argfile);
- }
- fputc ('\n', argfile);
- }
- fclose (argfile);
-
- i = system (scmd);
-
- remove (rf);
-#endif
-
- if (i == -1)
- {
- perror_exec (program);
- return MIN_FATAL_STATUS << 8;
- }
- return i << 8;
-}
-
-#endif
-
-#if !defined(__MSDOS__) && !defined(OS2) && !defined(_WIN32)
-
-static int
-pexecute (search_flag, program, argv, not_last)
- int search_flag;
- char *program;
- char *argv[];
- int not_last;
-{
- int (*func)() = (search_flag ? execv : execvp);
- int pid;
- int pdes[2];
- int input_desc = last_pipe_input;
- int output_desc = STDOUT_FILE_NO;
- int retries, sleep_interval;
-
- /* If this isn't the last process, make a pipe for its output,
- and record it as waiting to be the input to the next process. */
-
- if (not_last)
- {
- if (pipe (pdes) < 0)
- pfatal_with_name ("pipe");
- output_desc = pdes[WRITE_PORT];
- last_pipe_input = pdes[READ_PORT];
- }
- else
- last_pipe_input = STDIN_FILE_NO;
-
- /* Fork a subprocess; wait and retry if it fails. */
- sleep_interval = 1;
- for (retries = 0; retries < 4; retries++)
- {
- pid = vfork ();
- if (pid >= 0)
- break;
- sleep (sleep_interval);
- sleep_interval *= 2;
- }
-
- switch (pid)
- {
- case -1:
-#ifdef vfork
- pfatal_with_name ("fork");
-#else
- pfatal_with_name ("vfork");
-#endif
- /* NOTREACHED */
- return 0;
-
- case 0: /* child */
- /* Move the input and output pipes into place, if nec. */
- if (input_desc != STDIN_FILE_NO)
- {
- close (STDIN_FILE_NO);
- dup (input_desc);
- close (input_desc);
- }
- if (output_desc != STDOUT_FILE_NO)
- {
- close (STDOUT_FILE_NO);
- dup (output_desc);
- close (output_desc);
- }
-
- /* Close the parent's descs that aren't wanted here. */
- if (last_pipe_input != STDIN_FILE_NO)
- close (last_pipe_input);
-
- /* Exec the program. */
- (*func) (program, argv);
- perror_exec (program);
- exit (-1);
- /* NOTREACHED */
- return 0;
-
- default:
- /* In the parent, after forking.
- Close the descriptors that we made for this child. */
- if (input_desc != STDIN_FILE_NO)
- close (input_desc);
- if (output_desc != STDOUT_FILE_NO)
- close (output_desc);
-
- /* Return child's process number. */
- return pid;
- }
-}
-
-#endif /* not __MSDOS__ and not OS2 and not _WIN32 */
-
-#if defined(OS2)
-
-static int
-pexecute (search_flag, program, argv, not_last)
- int search_flag;
- char *program;
- char *argv[];
- int not_last;
-{
- return (search_flag ? spawnv : spawnvp) (1, program, argv);
-}
-#endif /* OS2 */
-
-#if defined(_WIN32)
-
-static int
-pexecute (search_flag, program, argv, not_last)
- int search_flag;
- char *program;
- char *argv[];
- int not_last;
-{
- return (search_flag ? __spawnv : __spawnvp) (1, program, argv);
-}
-#endif /* _WIN32 */
-
\f
/* Execute the command specified by the arguments on the current line of spec.
When using pipes, this includes several piped-together commands
for (n_commands = 1, i = 0; i < argbuf_index; i++)
if (strcmp (argbuf[i], "|") == 0)
{ /* each command. */
-#ifdef __MSDOS__
- fatal ("-pipe not supported under MS-DOS");
+#if defined (__MSDOS__) || defined (_WIN32) || defined (OS2)
+ fatal ("-pipe not supported");
#endif
argbuf[i] = 0; /* termination of command args. */
commands[n_commands].prog = argbuf[i + 1];
/* Run each piped subprocess. */
- last_pipe_input = STDIN_FILE_NO;
for (i = 0; i < n_commands; i++)
{
+ char *errmsg_fmt, *errmsg_arg;
char *string = commands[i].argv[0];
- commands[i].pid = pexecute (string != commands[i].prog,
- string, commands[i].argv,
- i + 1 < n_commands);
+ commands[i].pid = pexecute (string, commands[i].argv,
+ programname, temp_filename,
+ &errmsg_fmt, &errmsg_arg,
+ ((i == 0 ? PEXECUTE_FIRST : 0)
+ | (i + 1 == n_commands ? PEXECUTE_LAST : 0)
+ | (string == commands[i].prog
+ ? PEXECUTE_SEARCH : 0)
+ | (verbose_flag ? PEXECUTE_VERBOSE : 0)));
+
+ if (commands[i].pid == -1)
+ pfatal_pexecute (errmsg_fmt, errmsg_arg);
if (string != commands[i].prog)
free (string);
int status;
int pid;
-#ifdef __MSDOS__
- status = pid = commands[i].pid;
-#else
-#ifdef _WIN32
- pid = cwait (&status, commands[i].pid, WAIT_CHILD);
-#else
- pid = wait (&status);
-#endif
-#endif
+ pid = pwait (commands[i].pid, &status, 0);
if (pid < 0)
abort ();
printf ("*predefines:\n%s\n\n", cpp_predefines);
printf ("*cross_compile:\n%d\n\n", cross_compile);
printf ("*multilib:\n%s\n\n", multilib_select);
+ printf ("*multilib_defaults:\n%s\n\n", multilib_defaults);
+ printf ("*multilib_extra:\n%s\n\n", multilib_extra);
+ printf ("*multilib_matches:\n%s\n\n", multilib_matches);
#ifdef EXTRA_SPECS
{
int len;
/* The string after the S/P is the name of a spec that is to be
- processed. */
+ processed. */
while (*p && *p != ')' && *p != ']')
p++;
{
int c1 = *p++; /* Select first or second version number. */
char *v = compiler_version;
- char *q, *copy;
+ char *q;
+
+ /* The format of the version string is
+ ([^0-9]*-)?[0-9]+[.][0-9]+([.][0-9]+)?([- ].*)? */
+
+ /* Ignore leading non-digits. i.e. "foo-" in "foo-2.7.2". */
+ while (! isdigit (*v))
+ v++;
+ if (v > compiler_version && v[-1] != '-')
+ abort ();
+
/* If desired, advance to second version number. */
if (c1 == '2')
{
/* Set V after the first period. */
- while (*v != 0 && *v != ' ' && *v != '.')
- v++;
- if (*v == '.')
+ while (isdigit (*v))
v++;
+ if (*v != '.')
+ abort ();
+ v++;
}
+
/* Set Q at the next period or at the end. */
q = v;
- while (*q != 0 && *q != ' ' && *q != '.')
+ while (isdigit (*q))
q++;
- /* Empty string means zero. */
- if (v == q)
- {
- v = "0";
- q = v + 1;
- }
+ if (*q != 0 && *q != ' ' && *q != '.' && *q != '-')
+ abort ();
+
/* Put that part into the command. */
obstack_grow (&obstack, v, q - v);
arg_going = 1;
case 'W': case 'f': case 'm':
if (! strncmp (name + 1, "no-", 3))
{
- /* We have Xno-YYY, search for XYYY. */
+ /* We have Xno-YYY, search for XYYY. */
for (i = switchnum + 1; i < n_switches; i++)
if (switches[i].part1[0] == name[0]
&& ! strcmp (&switches[i].part1[1], &name[4]))
obstack_init (&obstack);
- /* Build multilib_select from the separate lines that make up each multilib
- selection. */
+ /* Build multilib_select, et. al from the separate lines that make up each
+ multilib selection. */
{
char **q = multilib_raw;
+ int need_space;
obstack_init (&multilib_obstack);
- while ((p = *q++) != (char *)0)
+ while ((p = *q++) != (char *) 0)
obstack_grow (&multilib_obstack, p, strlen (p));
obstack_1grow (&multilib_obstack, 0);
multilib_select = obstack_finish (&multilib_obstack);
+
+ q = multilib_matches_raw;
+ while ((p = *q++) != (char *) 0)
+ obstack_grow (&multilib_obstack, p, strlen (p));
+
+ obstack_1grow (&multilib_obstack, 0);
+ multilib_matches = obstack_finish (&multilib_obstack);
+
+ need_space = FALSE;
+ for (i = 0;
+ i < sizeof (multilib_defaults_raw) / sizeof (multilib_defaults_raw[0]);
+ i++)
+ {
+ if (need_space)
+ obstack_1grow (&multilib_obstack, ' ');
+ obstack_grow (&multilib_obstack,
+ multilib_defaults_raw[i],
+ strlen (multilib_defaults_raw[i]));
+ need_space = TRUE;
+ }
+
+ obstack_1grow (&multilib_obstack, 0);
+ multilib_defaults = obstack_finish (&multilib_obstack);
}
/* Set up to remember the pathname of gcc and any options
register char *p;
int len;
+ if (cp->spec[0][0] == '#')
+ error ("%s: %s compiler not installed on this system",
+ input_filename, &cp->spec[0][1]);
+
input_basename = input_filename;
for (p = input_filename; *p; p++)
if (*p == '/' || *p == DIR_SEPARATOR)
char *first;
#endif
- /* First compute the size of the result and get sufficient memory. */
+ /* First compute the size of the result and get sufficient memory. */
VA_START (args, first);
#ifndef __STDC__
newstr = (char *) xmalloc (length + 1);
va_end (args);
- /* Now copy the individual pieces to the result string. */
+ /* Now copy the individual pieces to the result string. */
VA_START (args, first);
#ifndef __STDC__
}
static void
-perror_exec (name)
- char *name;
+pfatal_pexecute (errmsg_fmt, errmsg_arg)
+ char *errmsg_fmt;
+ char *errmsg_arg;
{
- error ("installation problem, cannot exec `%s': %s",
- name, my_strerror (errno));
+ if (errmsg_arg)
+ {
+ /* Space for trailing '\0' is in %s. */
+ char *msg = xmalloc (strlen (errmsg_fmt) + strlen (errmsg_arg));
+ sprintf (msg, errmsg_fmt, errmsg_arg);
+ errmsg_fmt = msg;
+ }
+
+ fatal ("%s: %s", errmsg_fmt, my_strerror (errno));
}
/* More 'friendly' abort that prints the line and file.
VA_START (ap, format);
#ifndef __STDC__
- format = va_arg (ap, char*);
+ format = va_arg (ap, char *);
#endif
fprintf (stderr, "%s: ", programname);
VA_START (ap, format);
#ifndef __STDC__
- format = va_arg (ap, char*);
+ format = va_arg (ap, char *);
#endif
fprintf (stderr, "%s: ", programname);
}
}
\f
-/* Check whether a particular argument was used. */
+/* Check whether a particular argument was used. The first time we
+ canonialize the switches to keep only the ones we care about. */
static int
used_arg (p, len)
char *p;
int len;
{
- int i;
+ struct mswitchstr {
+ char *str;
+ char *replace;
+ int len;
+ int rep_len;
+ };
+
+ static struct mswitchstr *mswitches;
+ static int n_mswitches;
+ int i, j;
+
+ if (!mswitches)
+ {
+ struct mswitchstr *matches;
+ char *q;
+ int cnt = (*multilib_matches != '\0');
+
+ /* Break multilib_matches into the component strings of string and replacement
+ string */
+ for (p = multilib_matches; *p != '\0'; p++)
+ if (*p == ';')
+ cnt++;
+
+ matches = (struct mswitchstr *) alloca ((sizeof (struct mswitchstr)) * cnt);
+ i = 0;
+ q = multilib_matches;
+ while (*q != '\0')
+ {
+ matches[i].str = q;
+ while (*q != ' ')
+ {
+ if (*q == '\0')
+ abort ();
+ q++;
+ }
+ *q = '\0';
+ matches[i].len = q - matches[i].str;
- for (i = 0; i < n_switches; i++)
- if (! strncmp (switches[i].part1, p, len)
- && strlen (switches[i].part1) == len)
- return 1;
- return 0;
-}
+ matches[i].replace = ++q;
+ while (*q != ';' && *q != '\0')
+ {
+ if (*q == ' ')
+ abort ();
+ q++;
+ }
+ matches[i].rep_len = q - matches[i].replace;
+ i++;
+ if (*q == ';')
+ *q++ = '\0';
+ else
+ break;
+ }
-/* Check whether a particular argument is a default argument. */
+ /* Now build a list of the replacement string for switches that we care about */
+ mswitches = (struct mswitchstr *) xmalloc ((sizeof (struct mswitchstr)) * n_switches);
+ for (i = 0; i < n_switches; i++)
+ {
+ int xlen = strlen (switches[i].part1);
+ for (j = 0; j < cnt; j++)
+ if (xlen == matches[j].len && ! strcmp (switches[i].part1, matches[j].str))
+ {
+ mswitches[n_mswitches].str = matches[j].replace;
+ mswitches[n_mswitches].len = matches[j].rep_len;
+ mswitches[n_mswitches].replace = (char *)0;
+ mswitches[n_mswitches].rep_len = 0;
+ n_mswitches++;
+ break;
+ }
+ }
+ }
-#ifndef MULTILIB_DEFAULTS
-#define MULTILIB_DEFAULTS { NULL }
-#endif
+ for (i = 0; i < n_mswitches; i++)
+ if (len == mswitches[i].len && ! strncmp (p, mswitches[i].str, len))
+ return 1;
-static char *multilib_defaults[] = MULTILIB_DEFAULTS;
+ return 0;
+}
static int
default_arg (p, len)
char *p;
int len;
{
- int count = sizeof multilib_defaults / sizeof multilib_defaults[0];
+ char *start, *end;
int i;
- for (i = 0; i < count; i++)
- if (multilib_defaults[i] != NULL
- && strncmp (multilib_defaults[i], p, len) == 0
- && multilib_defaults[i][len] == '\0')
- return 1;
+ for (start = multilib_defaults; *start != '\0'; start = end+1)
+ {
+ while (*start == ' ' || *start == '\t')
+ start++;
+
+ if (*start == '\0')
+ break;
+
+ for (end = start+1; *end != ' ' && *end != '\t' && *end != '\0'; end++)
+ ;
+
+ if ((end - start) == len && strncmp (p, start, len) == 0)
+ return 1;
+ }
return 0;
}
}
if (! skip)
- putchar ('\n');
+ {
+ /* If there are extra options, print them now */
+ if (multilib_extra && *multilib_extra)
+ {
+ int print_at = TRUE;
+ char *q;
+
+ for (q = multilib_extra; *q != '\0'; q++)
+ {
+ if (*q == ' ')
+ print_at = TRUE;
+ else
+ {
+ if (print_at)
+ putchar ('@');
+ putchar (*q);
+ print_at = FALSE;
+ }
+ }
+ }
+ putchar ('\n');
+ }
++p;
}