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 2, or (at your option) any later
+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
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>.
This paragraph is here to try to keep Sun CC from dying.
The number of chars here seems crucial!!!! */
/* Flag set by cppspec.c to 1. */
int is_cpp_driver;
+/* Flag set to nonzero if an @file argument has been supplied to gcc. */
+static bool at_file_supplied;
+
/* Flag saying to pass the greatest exit code returned by a sub-process
to the calling program. */
static int pass_exit_codes;
static struct compiler *lookup_compiler (const char *, size_t, const char *);
static char *build_search_list (const struct path_prefix *, const char *,
bool, bool);
+static void xputenv (const char *);
static void putenv_from_prefixes (const struct path_prefix *, const char *,
bool);
static int access_check (const char *, int);
static const char *replace_outfile_spec_function (int, const char **);
static const char *version_compare_spec_function (int, const char **);
static const char *include_spec_function (int, const char **);
+static const char *print_asm_header_spec_function (int, const char **);
\f
/* The Specs Language
#define LINKER_NAME "collect2"
#endif
+#ifdef HAVE_AS_DEBUG_PREFIX_MAP
+#define ASM_MAP " %{fdebug-prefix-map=*:--debug-prefix-map %*}"
+#else
+#define ASM_MAP ""
+#endif
+
/* Define ASM_DEBUG_SPEC to be a spec suitable for translating '-g'
to the assembler. */
#ifndef ASM_DEBUG_SPEC
# if defined(DBX_DEBUGGING_INFO) && defined(DWARF2_DEBUGGING_INFO) \
&& defined(HAVE_AS_GDWARF2_DEBUG_FLAG) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
-# define ASM_DEBUG_SPEC \
- (PREFERRED_DEBUGGING_TYPE == DBX_DEBUG \
- ? "%{gdwarf-2*:--gdwarf2}%{!gdwarf-2*:%{g*:--gstabs}}" \
- : "%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}")
+# define ASM_DEBUG_SPEC \
+ (PREFERRED_DEBUGGING_TYPE == DBX_DEBUG \
+ ? "%{gdwarf-2*:--gdwarf2}%{!gdwarf-2*:%{g*:--gstabs}}" ASM_MAP \
+ : "%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}" ASM_MAP)
# else
# if defined(DBX_DEBUGGING_INFO) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
-# define ASM_DEBUG_SPEC "%{g*:--gstabs}"
+# define ASM_DEBUG_SPEC "%{g*:--gstabs}" ASM_MAP
# endif
# if defined(DWARF2_DEBUGGING_INFO) && defined(HAVE_AS_GDWARF2_DEBUG_FLAG)
-# define ASM_DEBUG_SPEC "%{g*:--gdwarf2}"
+# define ASM_DEBUG_SPEC "%{g*:--gdwarf2}" ASM_MAP
# endif
# endif
#endif
%(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
%{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
%{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
- %{fopenmp:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
+ %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
%{fprofile-arcs|fprofile-generate|coverage:-lgcov}\
%{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
%{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}"
%{MD:-MD %{!o:%b.d}%{o*:%.d%*}}\
%{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}}\
%{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*}\
- %{!E:%{!M:%{!MM:%{MD|MMD:%{o*:-MQ %*}}}}}\
+ %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}}\
%{remap} %{g3|ggdb3|gstabs3|gcoff3|gxcoff3|gvms3:-dD}\
%{H} %C %{D*&U*&A*} %{i*} %Z %i\
%{fmudflap:-D_MUDFLAP -include mf-runtime.h}\
%{coverage:-fprofile-arcs -ftest-coverage}";
static const char *asm_options =
+"%{--target-help:%:print-asm-header()} "
+#if HAVE_GNU_AS
+/* If GNU AS is used, then convert -w (no warnings), -I, and -v
+ to the assembler equivalents. */
+"%{v} %{w:-W} %{I*} "
+#endif
"%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}";
static const char *invoke_as =
/* Adding -fopenmp should imply pthreads. This is particularly important
for targets that use different start files and suchlike. */
#ifndef GOMP_SELF_SPECS
-#define GOMP_SELF_SPECS "%{fopenmp: -pthread}"
+#define GOMP_SELF_SPECS "%{fopenmp|ftree-parallelize-loops=*: -pthread}"
#endif
static const char *const driver_self_specs[] = {
{".s", "@assembler", 0, 1, 0},
{"@assembler",
"%{!M:%{!MM:%{!E:%{!S:as %(asm_debug) %(asm_options) %i %A }}}}", 0, 1, 0},
+ {".sx", "@assembler-with-cpp", 0, 1, 0},
{".S", "@assembler-with-cpp", 0, 1, 0},
{"@assembler-with-cpp",
#ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT
- "%(trad_capable_cpp) -lang-asm %(cpp_options)\
+ "%(trad_capable_cpp) -lang-asm %(cpp_options) -fno-directives-only\
%{E|M|MM:%(cpp_debug_options)}\
%{!M:%{!MM:%{!E:%{!S:-o %|.s |\n\
as %(asm_debug) %(asm_options) %|.s %A }}}}"
#else
- "%(trad_capable_cpp) -lang-asm %(cpp_options)\
+ "%(trad_capable_cpp) -lang-asm %(cpp_options) -fno-directives-only\
%{E|M|MM:%(cpp_debug_options)}\
%{!M:%{!MM:%{!E:%{!S:-o %|.s |\n\
as %(asm_debug) %(asm_options) %m.s %A }}}}"
{ "replace-outfile", replace_outfile_spec_function },
{ "version-compare", version_compare_spec_function },
{ "include", include_spec_function },
+ { "print-asm-header", print_asm_header_spec_function },
#ifdef EXTRA_SPEC_FUNCTIONS
EXTRA_SPEC_FUNCTIONS
#endif
}
#endif
- /* Initialize here, not in definition. The IRIX 6 O32 cc sometimes chokes
- on ?: in file-scope variable initializations. */
- asm_debug = ASM_DEBUG_SPEC;
-
for (i = ARRAY_SIZE (static_specs) - 1; i >= 0; i--)
{
sl = &static_specs[i];
/* Free the old spec. */
if (old_spec && sl->alloc_p)
- free ((void *) old_spec);
+ free (CONST_CAST(char *, old_spec));
sl->alloc_p = 1;
}
set_spec (p2, *(sl->ptr_spec));
if (sl->alloc_p)
- free ((void *) *(sl->ptr_spec));
+ free (CONST_CAST (char *, *(sl->ptr_spec)));
*(sl->ptr_spec) = "";
sl->alloc_p = 0;
Don't repeat any we have already seen. */
if (multi_dir)
{
- free ((char *) multi_dir);
+ free (CONST_CAST (char *, multi_dir));
multi_dir = NULL;
- free ((char *) multi_suffix);
+ free (CONST_CAST (char *, multi_suffix));
multi_suffix = machine_suffix;
- free ((char *) just_multi_suffix);
+ free (CONST_CAST (char *, just_multi_suffix));
just_multi_suffix = just_machine_suffix;
}
else
skip_multi_dir = true;
if (multi_os_dir)
{
- free ((char *) multi_os_dir);
+ free (CONST_CAST (char *, multi_os_dir));
multi_os_dir = NULL;
}
else
if (multi_dir)
{
- free ((char *) multi_dir);
- free ((char *) multi_suffix);
- free ((char *) just_multi_suffix);
+ free (CONST_CAST (char *, multi_dir));
+ free (CONST_CAST (char *, multi_suffix));
+ free (CONST_CAST (char *, just_multi_suffix));
}
if (multi_os_dir)
- free ((char *) multi_os_dir);
+ free (CONST_CAST (char *, multi_os_dir));
if (ret != path)
free (path);
return ret;
return NULL;
}
+/* Add or change the value of an environment variable, outputting the
+ change to standard error if in verbose mode. */
+static void
+xputenv (const char *string)
+{
+ if (verbose_flag)
+ notice ("%s\n", string);
+ putenv (CONST_CAST (char *, string));
+}
+
/* Build a list of search directories from PATHS.
PREFIX is a string to prepend to the list.
If CHECK_DIR_P is true we ensure the directory exists.
putenv_from_prefixes (const struct path_prefix *paths, const char *env_var,
bool do_multi)
{
- putenv (build_search_list (paths, env_var, true, do_multi));
+ xputenv (build_search_list (paths, env_var, true, do_multi));
}
\f
/* Check whether NAME can be accessed in MODE. This is like access,
errmsg = pex_run (pex,
((i + 1 == n_commands ? PEX_LAST : 0)
| (string == commands[i].prog ? PEX_SEARCH : 0)),
- string, (char * const *) commands[i].argv,
+ string, CONST_CAST (char **, commands[i].argv),
NULL, NULL, &err);
if (errmsg != NULL)
{
}
if (string != commands[i].prog)
- free ((void *) string);
+ free (CONST_CAST (char *, string));
}
execution_count++;
standard_bindir_prefix,
standard_libexec_prefix);
if (gcc_exec_prefix)
- putenv (concat ("GCC_EXEC_PREFIX=", gcc_exec_prefix, NULL));
+ xputenv (concat ("GCC_EXEC_PREFIX=", gcc_exec_prefix, NULL));
}
else
{
else if (strcmp (argv[i], "-fversion") == 0)
{
/* translate_options () has turned --version into -fversion. */
- printf (_("%s (GCC) %s\n"), programname, version_string);
+ printf (_("%s %s%s\n"), programname, pkgversion_string,
+ version_string);
printf ("Copyright %s 2007 Free Software Foundation, Inc.\n",
_("(C)"));
fputs (_("This is free software; see the source for copying conditions. There is NO\n\
switches[n_switches].live_cond = SWITCH_OK;
switches[n_switches].validated = 0;
switches[n_switches].ordering = 0;
- /* These are always valid, since gcc.c itself understands them. */
+ /* These are always valid, since gcc.c itself understands the
+ first four and gfortranspec.c understands -static-libgfortran. */
if (!strcmp (p, "save-temps")
|| !strcmp (p, "static-libgcc")
|| !strcmp (p, "shared-libgcc")
- || !strcmp (p, "pipe"))
+ || !strcmp (p, "pipe")
+ || !strcmp (p, "static-libgfortran"))
switches[n_switches].validated = 1;
else
{
}
}
obstack_grow (&collect_obstack, "\0", 1);
- putenv (XOBFINISH (&collect_obstack, char *));
+ xputenv (XOBFINISH (&collect_obstack, char *));
}
\f
/* Process a spec string, accumulating and running commands. */
arguments. */
static const char *suffix_subst;
+/* If there is an argument being accumulated, terminate it and store it. */
+
+static void
+end_going_arg (void)
+{
+ if (arg_going)
+ {
+ const char *string;
+
+ obstack_1grow (&obstack, 0);
+ string = XOBFINISH (&obstack, const char *);
+ if (this_is_library_file)
+ string = find_file (string);
+ store_arg (string, delete_this_arg, this_is_output_file);
+ if (this_is_output_file)
+ outfiles[input_file_number] = string;
+ arg_going = 0;
+ }
+}
+
/* Process the spec SPEC and run the commands specified therein.
Returns 0 if the spec is successfully processed; -1 if failed. */
static int
do_spec_2 (const char *spec)
{
- const char *string;
int result;
clear_args ();
result = do_spec_1 (spec, 0, NULL);
- /* End any pending argument. */
- if (arg_going)
- {
- obstack_1grow (&obstack, 0);
- string = XOBFINISH (&obstack, const char *);
- if (this_is_library_file)
- string = find_file (string);
- store_arg (string, delete_this_arg, this_is_output_file);
- if (this_is_output_file)
- outfiles[input_file_number] = string;
- arg_going = 0;
- }
+ end_going_arg ();
return result;
}
const char *p = spec;
int c;
int i;
- const char *string;
int value;
while ((c = *p++))
switch (inswitch ? 'a' : c)
{
case '\n':
- /* End of line: finish any pending argument,
- then run the pending command if one has been started. */
- if (arg_going)
- {
- obstack_1grow (&obstack, 0);
- string = XOBFINISH (&obstack, const char *);
- if (this_is_library_file)
- string = find_file (string);
- store_arg (string, delete_this_arg, this_is_output_file);
- if (this_is_output_file)
- outfiles[input_file_number] = string;
- }
- arg_going = 0;
+ end_going_arg ();
if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|"))
{
break;
case '|':
- /* End any pending argument. */
- if (arg_going)
- {
- obstack_1grow (&obstack, 0);
- string = XOBFINISH (&obstack, const char *);
- if (this_is_library_file)
- string = find_file (string);
- store_arg (string, delete_this_arg, this_is_output_file);
- if (this_is_output_file)
- outfiles[input_file_number] = string;
- }
+ end_going_arg ();
/* Use pipe */
obstack_1grow (&obstack, c);
case '\t':
case ' ':
- /* Space or tab ends an argument if one is pending. */
- if (arg_going)
- {
- obstack_1grow (&obstack, 0);
- string = XOBFINISH (&obstack, const char *);
- if (this_is_library_file)
- string = find_file (string);
- store_arg (string, delete_this_arg, this_is_output_file);
- if (this_is_output_file)
- outfiles[input_file_number] = string;
- }
+ end_going_arg ();
+
/* Reinitialize for a new argument. */
- arg_going = 0;
delete_this_arg = 0;
this_is_output_file = 0;
this_is_library_file = 0;
if (save_temps_flag)
{
+ char *tmp;
+
temp_filename_length = basename_length + suffix_length;
- temp_filename = alloca (temp_filename_length + 1);
- strncpy ((char *) temp_filename, input_basename, basename_length);
- strncpy ((char *) temp_filename + basename_length, suffix,
- suffix_length);
- *((char *) temp_filename + temp_filename_length) = '\0';
+ tmp = alloca (temp_filename_length + 1);
+ strncpy (tmp, input_basename, basename_length);
+ strncpy (tmp + basename_length, suffix, suffix_length);
+ tmp[temp_filename_length] = '\0';
+ temp_filename = tmp;
if (strcmp (temp_filename, input_filename) != 0)
{
#ifndef HOST_LACKS_INODE_NUMBERS
int max = n_infiles;
max += lang_specific_extra_outfiles;
- for (i = 0; i < max; i++)
- if (outfiles[i])
- store_arg (outfiles[i], 0, 0);
+ if (HAVE_GNU_LD && at_file_supplied)
+ {
+ /* We are going to expand `%o' to `@FILE', where FILE
+ is a newly-created temporary filename. The filenames
+ that would usually be expanded in place of %o will be
+ written to the temporary file. */
+
+ char *temp_file = make_temp_file ("");
+ char *at_argument;
+ char **argv;
+ int n_files, j, status;
+ FILE *f;
+
+ at_argument = concat ("@", temp_file, NULL);
+ store_arg (at_argument, 0, 0);
+
+ /* Convert OUTFILES into a form suitable for writeargv. */
+
+ /* Determine how many are non-NULL. */
+ for (n_files = 0, i = 0; i < max; i++)
+ n_files += outfiles[i] != NULL;
+
+ argv = alloca (sizeof (char *) * (n_files + 1));
+
+ /* Copy the strings over. */
+ for (i = 0, j = 0; i < max; i++)
+ if (outfiles[i])
+ {
+ argv[j] = CONST_CAST (char *, outfiles[i]);
+ j++;
+ }
+ argv[j] = NULL;
+
+ f = fopen (temp_file, "w");
+
+ if (f == NULL)
+ fatal ("could not open temporary response file %s",
+ temp_file);
+
+ status = writeargv (argv, f);
+
+ if (status)
+ fatal ("could not write to temporary response file %s",
+ temp_file);
+
+ status = fclose (f);
+
+ if (EOF == status)
+ fatal ("could not close temporary response file %s",
+ temp_file);
+
+ record_temp_file (temp_file, !save_temps_flag, !save_temps_flag);
+ }
+ else
+ for (i = 0; i < max; i++)
+ if (outfiles[i])
+ store_arg (outfiles[i], 0, 0);
break;
}
p = handle_braces (p + 1);
if (p == 0)
return -1;
- /* End any pending argument. */
- if (arg_going)
- {
- obstack_1grow (&obstack, 0);
- string = XOBFINISH (&obstack, const char *);
- if (this_is_library_file)
- string = find_file (string);
- store_arg (string, delete_this_arg, this_is_output_file);
- if (this_is_output_file)
- outfiles[input_file_number] = string;
- arg_going = 0;
- }
+ end_going_arg ();
/* If any args were output, mark the last one for deletion
on failure. */
if (argbuf_index != cur_index)
/* End of string. If we are processing a spec function, we need to
end any pending argument. */
- if (processing_spec_function && arg_going)
- {
- obstack_1grow (&obstack, 0);
- string = XOBFINISH (&obstack, const char *);
- if (this_is_library_file)
- string = find_file (string);
- store_arg (string, delete_this_arg, this_is_output_file);
- if (this_is_output_file)
- outfiles[input_file_number] = string;
- arg_going = 0;
- }
+ if (processing_spec_function)
+ end_going_arg ();
return 0;
}
while (length-- && !IS_DIR_SEPARATOR (arg[length]))
if (arg[length] == '.')
{
- ((char *)arg)[length] = 0;
+ (CONST_CAST(char *, arg))[length] = 0;
dot = 1;
break;
}
do_spec_1 (arg, 1, NULL);
if (dot)
- ((char *)arg)[length] = '.';
+ (CONST_CAST(char *, arg))[length] = '.';
do_spec_1 (suffix_subst, 1, NULL);
}
else
char *specs_file;
const char *p;
struct user_specs *uptr;
+ char **old_argv = argv;
+
+ /* Initialize here, not in definition. The IRIX 6 O32 cc sometimes chokes
+ on ?: in file-scope variable initializations. */
+ asm_debug = ASM_DEBUG_SPEC;
p = argv[0] + strlen (argv[0]);
while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
expandargv (&argc, &argv);
+ /* Determine if any expansions were made. */
+ if (argv != old_argv)
+ at_file_supplied = true;
+
prune_options (&argc, &argv);
#ifdef GCC_DRIVER_HOST_INITIALIZATION
obstack_init (&collect_obstack);
obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1);
obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1);
- putenv (XOBFINISH (&collect_obstack, char *));
+ xputenv (XOBFINISH (&collect_obstack, char *));
#ifdef INIT_ENVIRONMENT
/* Set up any other necessary machine specific environment variables. */
- putenv (INIT_ENVIRONMENT);
+ xputenv (INIT_ENVIRONMENT);
#endif
/* Make a table of what switches there are (switches, n_switches).
if (! strncmp (version_string, compiler_version, n)
&& compiler_version[n] == 0)
- notice ("gcc version %s\n", version_string);
+ notice ("gcc version %s %s\n", version_string, pkgversion_string);
else
- notice ("gcc driver version %s executing gcc version %s\n",
- version_string, compiler_version);
+ notice ("gcc driver version %s %sexecuting gcc version %s\n",
+ version_string, pkgversion_string, compiler_version);
if (n_infiles == 0)
return (0);
/* Run ld to link all the compiler output files. */
- if (num_linker_inputs > 0 && error_count == 0)
+ if (num_linker_inputs > 0 && error_count == 0 && print_subprocess_help < 2)
{
int tmp = execution_count;
putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH", false);
putenv_from_prefixes (&startfile_prefixes, LIBRARY_PATH_ENV, true);
+ if (print_subprocess_help == 1)
+ {
+ printf (_("\nLinker options\n==============\n\n"));
+ printf (_("Use \"-Wl,OPTION\" to pass \"OPTION\""
+ " to the linker.\n\n"));
+ fflush (stdout);
+ }
value = do_spec (link_command_spec);
if (value < 0)
error_count = 1;
if (! linker_was_run && error_count == 0)
for (i = 0; (int) i < n_infiles; i++)
- if (explicit_link_files[i])
+ if (explicit_link_files[i]
+ && !(infiles[i].language && infiles[i].language[0] == '*'))
error ("%s: linker input file unused because linking not done",
outfiles[i]);
if (multilib_dir == NULL && multilib_os_dir != NULL
&& strcmp (multilib_os_dir, ".") == 0)
{
- free ((char *) multilib_os_dir);
+ free (CONST_CAST (char *, multilib_os_dir));
multilib_os_dir = NULL;
}
else if (multilib_dir != NULL && multilib_os_dir == NULL)
getenv_spec_function (int argc, const char **argv)
{
char *value;
+ char *result;
+ char *ptr;
+ size_t len;
if (argc != 2)
return NULL;
if (!value)
fatal ("environment variable \"%s\" not defined", argv[0]);
- return concat (value, argv[1], NULL);
+ /* We have to escape every character of the environment variable so
+ they are not interpretted as active spec characters. A
+ particulaly painful case is when we are reading a variable
+ holding a windows path complete with \ separators. */
+ len = strlen (value) * 2 + strlen (argv[1]) + 1;
+ result = xmalloc (len);
+ for (ptr = result; *value; ptr += 2)
+ {
+ ptr[0] = '\\';
+ ptr[1] = *value++;
+ }
+
+ strcpy (ptr, argv[1]);
+
+ return result;
}
/* if-exists built-in spec function.
return NULL;
}
+
+/* %:print-asm-header spec function. Print a banner to say that the
+ following output is from the assembler. */
+
+static const char *
+print_asm_header_spec_function (int arg ATTRIBUTE_UNUSED,
+ const char **argv ATTRIBUTE_UNUSED)
+{
+ printf (_("Assembler options\n=================\n\n"));
+ printf (_("Use \"-Wa,OPTION\" to pass \"OPTION\" to the assembler.\n\n"));
+ fflush (stdout);
+ return NULL;
+}