#include <sys/types.h>
#include <ctype.h>
#include <signal.h>
-#include <sys/file.h>
#include <sys/stat.h>
#include "config.h"
#include "obstack.h"
#include "gvarargs.h"
-#ifdef USG
#ifndef R_OK
#define R_OK 4
#define W_OK 2
#define X_OK 1
#endif
+#ifdef USG
#define vfork fork
#endif /* USG */
/* By default there is no special suffix for executables. */
#ifndef EXECUTABLE_SUFFIX
-#if __MSDOS__
-#define EXECUTABLE_SUFFIX ".exe"
-#else
#define EXECUTABLE_SUFFIX ""
#endif
+
+/* By default, colon separates directories in a path. */
+#ifndef PATH_SEPARATOR
+#define PATH_SEPARATOR ':'
#endif
#define obstack_chunk_alloc xmalloc
static struct obstack obstack;
+/* This is the obstack to build an environment variable to pass to
+ collect2 that describes all of the relevant switches of what to
+ pass the compiler in building the list of pointers to constructors
+ and destructors. */
+
+static struct obstack collect_obstack;
+
extern char *version_string;
static void set_spec ();
%{S*:X} substitutes X if one or more switches whose names with -S are
specified to CC. Note that the tail part of the -S option
(i.e. the part matched by the `*') will be substituted for each
- occurance of %* within X.
+ occurrence of %* within X.
%{S:X} substitutes X, but only if the -S switch was given to CC.
%{!S:X} substitutes X, but only if the -S switch was NOT given to CC.
%{|S:X} like %{S:X}, but if no S switch, substitute `-'.
%{|!S:X} like %{!S:X}, but if there is an S switch, substitute `-'.
%{.S:X} substitutes X, but only if processing a file with suffix S.
%{!.S:X} substitutes X, but only if NOT processing a file with suffix S.
+ %(Spec) processes a specification defined in a specs file as *Spec:
+ %[Spec] as above, but put __ around -D arguments
The conditional text X in a %{S:X} or %{!S:X} construct may contain
other nested % constructs or spaces, or even newlines. They are
#ifndef WORD_SWITCH_TAKES_ARG
#define WORD_SWITCH_TAKES_ARG(STR) \
(!strcmp (STR, "Tdata") || !strcmp (STR, "include") \
- || !strcmp (STR, "imacros"))
+ || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info"))
#endif
\f
/* Record the mapping from file suffixes for compilation specs. */
{
{".c", "@c"},
{"@c",
- "cpp -lang-c %{nostdinc} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
+ "cpp -lang-c %{nostdinc*} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d}\
-undef -D__GNUC__=2 %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
%{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
%{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
+ %{aux-info*}\
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %{R} %{j} %{J} %{h} %{d2} %a \
%{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\
%{!pipe:%g.s} %A\n }}}}"},
{"-",
- "%{E:cpp -lang-c %{nostdinc} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
+ "%{E:cpp -lang-c %{nostdinc*} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d}\
-undef -D__GNUC__=2 %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
%{!E:%e-E required when input is from standard input}"},
{".m", "@objective-c"},
{"@objective-c",
- "cpp -lang-objc %{nostdinc} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
+ "cpp -lang-objc %{nostdinc*} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d}\
-undef -D__OBJC__ -D__GNUC__=2 %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
%{traditional} %{v:-version} %{pg:-p} %{p} %{f*} \
-lang-objc %{gen-decls} \
+ %{aux-info*}\
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %{R} %{j} %{J} %{h} %{d2} %a \
{".h", "@c-header"},
{"@c-header",
"%{!E:%eCompilation of header file requested} \
- cpp %{nostdinc} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
+ cpp %{nostdinc*} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} \
-undef -D__GNUC__=2 %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
{".cxx", "@c++"},
{".C", "@c++"},
{"@c++",
- "cpp -lang-c++ %{nostdinc} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
+ "cpp -lang-c++ %{nostdinc*} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
%{C:%{!E:%eGNU C++ does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} \
-undef -D__GNUC__=2 -D__GNUG__=2 -D__cplusplus \
%{!Q:-quiet} -dumpbase %b.cc %{d*} %{m*} %{a}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} %{traditional}\
%{v:-version} %{pg:-p} %{p} %{f*}\
+ %{aux-info*}\
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %{R} %{j} %{J} %{h} %{d2} %a \
"cc1 %i %1 %{!Q:-quiet} %{d*} %{m*} %{a}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} %{traditional}\
%{v:-version} %{pg:-p} %{p} %{f*}\
+ %{aux-info*}\
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %{R} %{j} %{J} %{h} %{d2} %a \
"cc1plus %i %1 %2 %{!Q:-quiet} %{d*} %{m*} %{a}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} %{traditional}\
%{v:-version} %{pg:-p} %{p} %{f*}\
+ %{aux-info*}\
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %{R} %{j} %{J} %{h} %{d2} %a \
%{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o} %i %A\n }"},
{".S", "@assembler-with-cpp"},
{"@assembler-with-cpp",
- "cpp -lang-asm %{nostdinc} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
+ "cpp -lang-asm %{nostdinc*} %{C} %{v} %{A*} %{D*} %{U*} %{I*} %{i*} %{P}\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{trigraphs} \
-undef -$ %{!undef:%p %P} -D__ASSEMBLER__ \
#ifdef LINK_LIBGCC_SPECIAL
/* Have gcc do the search. */
+/* -u* was put back because both BSD and SysV seem to support it. */
static char *link_command_spec = "\
-%{!c:%{!M:%{!MM:%{!E:%{!S:ld %X %l %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
- %{r} %{s} %{T*} %{t} %{x} %{z}\
+%{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+ %{r} %{s} %{T*} %{t} %{u*} %{x} %{z}\
%{!A:%{!nostdlib:%S}} \
%{L*} %D %o %{!nostdlib:libgcc.a%s %L libgcc.a%s %{!A:%E}}\n }}}}}";
#else
/* Use -l and have the linker do the search. */
static char *link_command_spec = "\
-%{!c:%{!M:%{!MM:%{!E:%{!S:ld %X %l %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
- %{r} %{T*} %{t} %{x} %{z}\
+%{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+ %{r} %{s} %{T*} %{t} %{u*} %{x} %{z}\
%{!A:%{!nostdlib:%S}} \
%{L*} %D %o %{!nostdlib:-lgcc %L -lgcc %{!A:%E}}\n }}}}}";
#endif
/* A vector of options to give to the linker.
- These options are accumlated by %x
+ These options are accumulated by %x
and substituted into the linker command with %X. */
static int n_linker_options;
static char **linker_options;
else if (in[0] == '#')
{
while (*in && *in != '\n') in++;
- if (*in) in++;
}
else
*out++ = *in++;
}
\f
/* Structure to keep track of the specs that have been defined so far. These
- are accessed using %Sspecname in a compiler or link spec. */
+ are accessed using %(specname) or %[specname] in a compiler or link spec. */
struct spec_list
{
mktemp (temp_filename);
temp_filename_length = strlen (temp_filename);
}
+\f
+
+/* Routine to add variables to the environment. We do this to pass
+ the pathname of the gcc driver, and the directories search to the
+ collect2 program, which is being run as ld. This way, we can be
+ sure of executing the right compiler when collect2 wants to build
+ constructors and destructors. Since the environment variables we
+ use come from an obstack, we don't have to worry about allocating
+ space for them. */
+
+#ifndef HAVE_PUTENV
+
+putenv (str)
+ char *str;
+{
+#ifndef VMS /* nor about VMS */
+
+ extern char **environ;
+ char **old_environ = environ;
+ char **envp;
+ int num_envs = 0;
+ int name_len = 1;
+ int str_len = strlen (str);
+ char *p = str;
+ int ch;
+
+ while ((ch = *p++) != '\0' && ch != '=')
+ name_len++;
+
+ if (!ch)
+ abort ();
+
+ /* Search for replacing an existing environment variable, and
+ count the number of total environment variables. */
+ for (envp = old_environ; *envp; envp++)
+ {
+ num_envs++;
+ if (!strncmp (str, *envp, name_len))
+ {
+ *envp = str;
+ return;
+ }
+ }
+
+ /* Add a new environment variable */
+ environ = (char **) xmalloc (sizeof (char *) * (num_envs+2));
+ *environ = str;
+ bcopy (old_environ, environ+1, sizeof (char *) * (num_envs+1));
+
+#endif /* VMS */
+}
+
+#endif /* HAVE_PUTENV */
+
+\f
+/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables for collect. */
+
+static void
+putenv_from_prefixes (paths, env_var)
+ struct path_prefix *paths;
+ char *env_var;
+{
+ int suffix_len = (machine_suffix) ? strlen (machine_suffix) : 0;
+ int first_time = TRUE;
+ struct prefix_list *pprefix;
+
+ obstack_grow (&collect_obstack, env_var, strlen (env_var));
+
+ for (pprefix = paths->plist; pprefix != 0; pprefix = pprefix->next)
+ {
+ int len = strlen (pprefix->prefix);
+
+ if (machine_suffix)
+ {
+ if (!first_time)
+ obstack_grow (&collect_obstack, ":", 1);
+
+ first_time = FALSE;
+ obstack_grow (&collect_obstack, pprefix->prefix, len);
+ obstack_grow (&collect_obstack, machine_suffix, suffix_len);
+ }
+
+ if (!pprefix->require_machine_suffix)
+ {
+ if (!first_time)
+ obstack_grow (&collect_obstack, ":", 1);
+
+ first_time = FALSE;
+ obstack_grow (&collect_obstack, pprefix->prefix, len);
+ }
+ }
+ obstack_grow (&collect_obstack, "\0", 1);
+ putenv (obstack_finish (&collect_obstack));
+}
+
\f
/* Search for NAME using the prefix list PREFIXES. MODE is passed to
access to check permissions.
FILE *argfile;
int i;
- scmd = (char *)malloc(strlen(program) + strlen(temp_filename) + 6);
- sprintf(scmd, "%s @%s.gp", program, temp_filename);
- argfile = fopen(scmd+strlen(program)+2, "w");
+ scmd = (char *)malloc (strlen (program) + strlen (temp_filename) + 6);
+ sprintf (scmd, "%s @%s.gp", program, temp_filename);
+ argfile = fopen (scmd+strlen (program) + 2, "w");
if (argfile == 0)
- pfatal_with_name(scmd+strlen(program)+2);
+ pfatal_with_name (scmd + strlen (program) + 2);
for (i=1; argv[i]; i++)
- fprintf(argfile, "%s\n", argv[i]);
- fclose(argfile);
+ {
+ 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);
+ i = system (scmd);
- remove(scmd+strlen(program)+2);
+ remove (scmd + strlen (program) + 2);
return i << 8;
}
/* If -v, print what we are about to do, and maybe query. */
- if (verbose_flag || save_temps_flag)
+ if (verbose_flag)
{
/* Print each piped command as a separate line. */
for (i = 0; i < n_commands ; i++)
startp = endp = temp;
while (1)
{
- if ((*endp == ':') || (*endp == 0))
+ if (*endp == PATH_SEPARATOR || *endp == 0)
{
strncpy (nstore, startp, endp-startp);
if (endp == startp)
startp = endp = temp;
while (1)
{
- if ((*endp == ':') || (*endp == 0))
+ if (*endp == PATH_SEPARATOR || *endp == 0)
{
strncpy (nstore, startp, endp-startp);
if (endp == startp)
startp = endp = temp;
while (1)
{
- if ((*endp == ':') || (*endp == 0))
+ if (*endp == PATH_SEPARATOR || *endp == 0)
{
strncpy (nstore, startp, endp-startp);
if (endp == startp)
{
struct prefix_list *pl
= (i == 0 ? library_prefix.plist : startfile_prefix.plist);
+ int bufsize = 100;
+ char *buffer = (char *) xmalloc (bufsize);
+ int idx;
+
for (; pl; pl = pl->next)
{
#ifdef RELATIVE_PREFIX_NOT_LINKDIR
do_spec_1 (" ", 0, 0);
#endif
do_spec_1 (pl->prefix, 1, 0);
- do_spec_1 (machine_suffix, 1, 0);
+ /* Remove slash from machine_suffix. */
+ if (strlen (machine_suffix) >= bufsize)
+ bufsize = strlen (machine_suffix) * 2 + 1;
+ buffer = (char *) xrealloc (buffer, bufsize);
+ strcpy (buffer, machine_suffix);
+ idx = strlen (buffer);
+ if (buffer[idx - 1] == '/')
+ buffer[idx - 1] = 0;
+ do_spec_1 (buffer, 1, 0);
/* Make this a separate argument. */
do_spec_1 (" ", 0, 0);
}
#ifdef SPACE_AFTER_L_OPTION
do_spec_1 (" ", 0, 0);
#endif
- do_spec_1 (pl->prefix, 1, 0);
+ /* Remove slash from pl->prefix. */
+ if (strlen (pl->prefix) >= bufsize)
+ bufsize = strlen (pl->prefix) * 2 + 1;
+ buffer = (char *) xrealloc (buffer, bufsize);
+ strcpy (buffer, pl->prefix);
+ idx = strlen (buffer);
+ if (buffer[idx - 1] == '/')
+ buffer[idx - 1] = 0;
+ do_spec_1 (buffer, 1, 0);
/* Make this a separate argument. */
do_spec_1 (" ", 0, 0);
}
}
}
+ free (buffer);
}
break;
do_spec_1 (buf, 0, NULL);
}
}
+
+ /* Discard the closing paren or bracket. */
+ if (*p)
+ p++;
}
break;
/* First see whether we have %*. */
substitution = 0;
- while (*r && *r == '}')
+ while (r < q)
{
if (*r == '%' && r[1] == '*')
substitution = 1;
obstack_init (&obstack);
+ /* Set up to remember the pathname of gcc and any options
+ needed for collect. */
+ obstack_init (&collect_obstack);
+ obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=")-1);
+ obstack_grow (&collect_obstack, programname, strlen (programname)+1);
+ putenv (obstack_finish (&collect_obstack));
+
/* Choose directory for temp files. */
choose_temp_base ();
if (error_count == 0)
{
int tmp = execution_count;
+ int i;
+ int first_time;
+
+ /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
+ for collect. */
+ putenv_from_prefixes (&exec_prefix, "COMPILER_PATH=");
+ putenv_from_prefixes (&startfile_prefix, "LIBRARY_PATH=");
+
+ /* Build COLLECT_GCC_OPTIONS to have all of the options specified to
+ the compiler. */
+ obstack_grow (&collect_obstack, "COLLECT_GCC_OPTIONS=",
+ sizeof ("COLLECT_GCC_OPTIONS=")-1);
+
+ first_time = TRUE;
+ for (i = 0; i < n_switches; i++)
+ {
+ char **args;
+ if (!first_time)
+ obstack_grow (&collect_obstack, " ", 1);
+
+ first_time = FALSE;
+ obstack_grow (&collect_obstack, "-", 1);
+ obstack_grow (&collect_obstack, switches[i].part1,
+ strlen (switches[i].part1));
+
+ for (args = switches[i].args; args && *args; args++)
+ {
+ obstack_grow (&collect_obstack, " ", 1);
+ obstack_grow (&collect_obstack, *args, strlen (*args));
+ }
+ }
+ obstack_grow (&collect_obstack, "\0", 1);
+ putenv (obstack_finish (&collect_obstack));
+
value = do_spec (link_command_spec);
if (value < 0)
error_count = 1;
struct compiler *comp;
register char *p;
register char c;
+ struct spec_list *spec;
for (comp = compilers; comp->spec; comp++)
{
validate_switches (p + 1);
}
+ /* look through the linked list of extra specs read from the specs file */
+ for (spec = specs ; spec ; spec = spec->next)
+ {
+ p = spec->spec;
+ while (c = *p++)
+ if (c == '%' && *p == '{')
+ /* We have a switch spec. */
+ validate_switches (p + 1);
+ }
+
p = link_command_spec;
while (c = *p++)
if (c == '%' && *p == '{')