int
main (int argc, char **argv)
{
size_t i;
int value;
int linker_was_run = 0;
int lang_n_infiles = 0;
int num_linker_inputs = 0;
char *explicit_link_files;
char *specs_file;
char *lto_wrapper_file;
const char *p;
struct user_specs *uptr;
char **old_argv = argv;
struct cl_decoded_option *decoded_options;
unsigned int decoded_options_count;
/* 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]))
--p;
progname = p;
xmalloc_set_program_name (progname);//记录程序名称
expandargv (&argc, &argv);//展开@file
/* Determine if any expansions were made. 是否有对@file的展开 */
if (argv != old_argv)
at_file_supplied = true;
global_options = global_options_init;//?
//将命令行选项转换为数组存储
decode_cmdline_options_to_array (argc, CONST_CAST2 (const char **, char **,
argv),
CL_DRIVER,
&decoded_options, &decoded_options_count);
#ifdef GCC_DRIVER_HOST_INITIALIZATION
/* Perform host dependent initialization when needed. */
GCC_DRIVER_HOST_INITIALIZATION;
#endif
/* Unlock the stdio streams. 对标准输入输出解锁?*/
unlock_std_streams ();
gcc_init_libintl ();
diagnostic_initialize (global_dc, 0);
if (atexit (delete_temp_files) != 0)
fatal_error ("atexit failed");
if (signal (SIGINT, SIG_IGN) != SIG_IGN)
signal (SIGINT, fatal_signal);
#ifdef SIGHUP
if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
signal (SIGHUP, fatal_signal);
#endif
if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
signal (SIGTERM, fatal_signal);
#ifdef SIGPIPE
if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
signal (SIGPIPE, fatal_signal);
#endif
#ifdef SIGCHLD
/* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
receive the signal. A different setting is inheritable */
signal (SIGCHLD, SIG_DFL);
#endif
/* Allocate the argument vector. */
alloc_args ();
obstack_init (&obstack);
/* Build multilib_select, et. al from the separate lines that make up each
multilib selection. */
{
const char *const *q = multilib_raw;
int need_space;
obstack_init (&multilib_obstack);
while ((p = *q++) != (char *) 0)
obstack_grow (&multilib_obstack, p, strlen (p));
obstack_1grow (&multilib_obstack, 0);
multilib_select = XOBFINISH (&multilib_obstack, const char *);
q = multilib_matches_raw;
while ((p = *q++) != (char *) 0)
obstack_grow (&multilib_obstack, p, strlen (p));
obstack_1grow (&multilib_obstack, 0);
multilib_matches = XOBFINISH (&multilib_obstack, const char *);
q = multilib_exclusions_raw;
while ((p = *q++) != (char *) 0)
obstack_grow (&multilib_obstack, p, strlen (p));
obstack_1grow (&multilib_obstack, 0);
multilib_exclusions = XOBFINISH (&multilib_obstack, const char *);
need_space = FALSE;
for (i = 0; i < ARRAY_SIZE (multilib_defaults_raw); 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 = XOBFINISH (&multilib_obstack, const char *);
}
#ifdef INIT_ENVIRONMENT
/* Set up any other necessary machine specific environment variables. */
xputenv (INIT_ENVIRONMENT);
#endif
/* Make a table of what switches there are (switches, n_switches).
Make a table of specified input files (infiles, n_infiles).
Decode switches that are handled locally. */
process_command (decoded_options_count, decoded_options);
/* Initialize the vector of specs to just the default.
This means one element containing 0s, as a terminator. */
compilers = XNEWVAR (struct compiler, sizeof default_compilers);
memcpy (compilers, default_compilers, sizeof default_compilers);
n_compilers = n_default_compilers;
/* Read specs from a file if there is one. */
machine_suffix = concat (spec_machine, dir_separator_str,
spec_version, dir_separator_str, NULL);
just_machine_suffix = concat (spec_machine, dir_separator_str, NULL);
specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, true);
/* Read the specs file unless it is a default one. */
if (specs_file != 0 && strcmp (specs_file, "specs"))
read_specs (specs_file, TRUE);
else
init_spec ();
/* We need to check standard_exec_prefix/just_machine_suffix/specs
for any override of as, ld and libraries. */
specs_file = (char *) alloca (strlen (standard_exec_prefix)
+ strlen (just_machine_suffix) + sizeof ("specs"));
strcpy (specs_file, standard_exec_prefix);
strcat (specs_file, just_machine_suffix);
strcat (specs_file, "specs");
if (access (specs_file, R_OK) == 0)
read_specs (specs_file, TRUE);
/* Process any configure-time defaults specified for the command line
options, via OPTION_DEFAULT_SPECS. */
for (i = 0; i < ARRAY_SIZE (option_default_specs); i++)
do_option_spec (option_default_specs[i].name,
option_default_specs[i].spec);
/* Process DRIVER_SELF_SPECS, adding any new options to the end
of the command line. */
for (i = 0; i < ARRAY_SIZE (driver_self_specs); i++)
do_self_spec (driver_self_specs[i]);
if (compare_debug)
{
enum save_temps save;
if (!compare_debug_second)
{
n_switches_debug_check[1] = n_switches;
n_switches_alloc_debug_check[1] = n_switches_alloc;
switches_debug_check[1] = XDUPVEC (struct switchstr, switches,
n_switches_alloc);
do_self_spec ("%:compare-debug-self-opt()");
n_switches_debug_check[0] = n_switches;
n_switches_alloc_debug_check[0] = n_switches_alloc;
switches_debug_check[0] = switches;
n_switches = n_switches_debug_check[1];
n_switches_alloc = n_switches_alloc_debug_check[1];
switches = switches_debug_check[1];
}
/* Avoid crash when computing %j in this early. */
save = save_temps_flag;
save_temps_flag = SAVE_TEMPS_NONE;
compare_debug = -compare_debug;
do_self_spec ("%:compare-debug-self-opt()");
save_temps_flag = save;
if (!compare_debug_second)
{
n_switches_debug_check[1] = n_switches;
n_switches_alloc_debug_check[1] = n_switches_alloc;
switches_debug_check[1] = switches;
compare_debug = -compare_debug;
n_switches = n_switches_debug_check[0];
n_switches_alloc = n_switches_debug_check[0];
switches = switches_debug_check[0];
}
}
/* If not cross-compiling, look for executables in the standard
places. */
if (*cross_compile == '0')
{
if (*md_exec_prefix)
{
add_prefix (&exec_prefixes, md_exec_prefix, "GCC",
PREFIX_PRIORITY_LAST, 0, 0);
}
}
/* Process sysroot_suffix_spec. */
if (*sysroot_suffix_spec != 0
&& do_spec_2 (sysroot_suffix_spec) == 0)
{
if (VEC_length (const_char_p, argbuf) > 1)
error ("spec failure: more than one arg to SYSROOT_SUFFIX_SPEC");
else if (VEC_length (const_char_p, argbuf) == 1)
target_sysroot_suffix = xstrdup (VEC_last (const_char_p, argbuf));
}
#ifdef HAVE_LD_SYSROOT
/* Pass the --sysroot option to the linker, if it supports that. If
there is a sysroot_suffix_spec, it has already been processed by
this point, so target_system_root really is the system root we
should be using. */
if (target_system_root)
{
obstack_grow (&obstack, "%(sysroot_spec) ", strlen ("%(sysroot_spec) "));
obstack_grow0 (&obstack, link_spec, strlen (link_spec));
set_spec ("link", XOBFINISH (&obstack, const char *));
}
#endif
/* Process sysroot_hdrs_suffix_spec. */
if (*sysroot_hdrs_suffix_spec != 0
&& do_spec_2 (sysroot_hdrs_suffix_spec) == 0)
{
if (VEC_length (const_char_p, argbuf) > 1)
error ("spec failure: more than one arg to SYSROOT_HEADERS_SUFFIX_SPEC");
else if (VEC_length (const_char_p, argbuf) == 1)
target_sysroot_hdrs_suffix = xstrdup (VEC_last (const_char_p, argbuf));
}
/* Look for startfiles in the standard places. */
if (*startfile_prefix_spec != 0
&& do_spec_2 (startfile_prefix_spec) == 0
&& do_spec_1 (" ", 0, NULL) == 0)
{
const char *arg;
int ndx;
FOR_EACH_VEC_ELT (const_char_p, argbuf, ndx, arg)
add_sysrooted_prefix (&startfile_prefixes, arg, "BINUTILS",
PREFIX_PRIORITY_LAST, 0, 1);
}
/* We should eventually get rid of all these and stick to
startfile_prefix_spec exclusively. */
else if (*cross_compile == '0' || target_system_root)
{
if (*md_startfile_prefix)
add_sysrooted_prefix (&startfile_prefixes, md_startfile_prefix,
"GCC", PREFIX_PRIORITY_LAST, 0, 1);
if (*md_startfile_prefix_1)
add_sysrooted_prefix (&startfile_prefixes, md_startfile_prefix_1,
"GCC", PREFIX_PRIORITY_LAST, 0, 1);
/* If standard_startfile_prefix is relative, base it on
standard_exec_prefix. This lets us move the installed tree
as a unit. If GCC_EXEC_PREFIX is defined, base
standard_startfile_prefix on that as well.
If the prefix is relative, only search it for native compilers;
otherwise we will search a directory containing host libraries. */
if (IS_ABSOLUTE_PATH (standard_startfile_prefix))
add_sysrooted_prefix (&startfile_prefixes,
standard_startfile_prefix, "BINUTILS",
PREFIX_PRIORITY_LAST, 0, 1);
else if (*cross_compile == '0')
{
add_prefix (&startfile_prefixes,
concat (gcc_exec_prefix
? gcc_exec_prefix : standard_exec_prefix,
machine_suffix,
standard_startfile_prefix, NULL),
NULL, PREFIX_PRIORITY_LAST, 0, 1);
}
/* Sysrooted prefixes are relocated because target_system_root is
also relocated by gcc_exec_prefix. */
if (*standard_startfile_prefix_1)
add_sysrooted_prefix (&startfile_prefixes,
standard_startfile_prefix_1, "BINUTILS",
PREFIX_PRIORITY_LAST, 0, 1);
if (*standard_startfile_prefix_2)
add_sysrooted_prefix (&startfile_prefixes,
standard_startfile_prefix_2, "BINUTILS",
PREFIX_PRIORITY_LAST, 0, 1);
}
/* Process any user specified specs in the order given on the command
line. */
for (uptr = user_specs_head; uptr; uptr = uptr->next)
{
char *filename = find_a_file (&startfile_prefixes, uptr->filename,
R_OK, true);
read_specs (filename ? filename : uptr->filename, FALSE);
}
/* If we have a GCC_EXEC_PREFIX envvar, modify it for cpp's sake. */
if (gcc_exec_prefix)
gcc_exec_prefix = concat (gcc_exec_prefix, spec_machine, dir_separator_str,
spec_version, dir_separator_str, NULL);
/* Now we have the specs.
Set the `valid' bits for switches that match anything in any spec. */
validate_all_switches ();
/* Now that we have the switches and the specs, set
the subdirectory based on the options. */
set_multilib_dir ();
/* Set up to remember the pathname of gcc and any options
needed for collect. We use argv[0] instead of progname because
we need the complete pathname. */
obstack_init (&collect_obstack);
obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1);
obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1);
xputenv (XOBFINISH (&collect_obstack, char *));
/* Set up to remember the pathname of the lto wrapper. */
lto_wrapper_file = find_a_file (&exec_prefixes, "lto-wrapper", X_OK, false);
if (lto_wrapper_file)
{
lto_wrapper_spec = lto_wrapper_file;
obstack_init (&collect_obstack);
obstack_grow (&collect_obstack, "COLLECT_LTO_WRAPPER=",
sizeof ("COLLECT_LTO_WRAPPER=") - 1);
obstack_grow (&collect_obstack, lto_wrapper_spec,
strlen (lto_wrapper_spec) + 1);
xputenv (XOBFINISH (&collect_obstack, char *));
}
/* Warn about any switches that no pass was interested in. */
for (i = 0; (int) i < n_switches; i++)
if (! switches[i].validated)
error ("unrecognized option %<-%s%>", switches[i].part1);
/* Obey some of the options. */
if (print_search_dirs)
{
printf (_("install: %s%s\n"),
gcc_exec_prefix ? gcc_exec_prefix : standard_exec_prefix,
gcc_exec_prefix ? "" : machine_suffix);
printf (_("programs: %s\n"),
build_search_list (&exec_prefixes, "", false, false));
printf (_("libraries: %s\n"),
build_search_list (&startfile_prefixes, "", false, true));
return (0);
}
if (print_file_name)
{
printf ("%s\n", find_file (print_file_name));
return (0);
}
if (print_prog_name)
{
char *newname = find_a_file (&exec_prefixes, print_prog_name, X_OK, 0);
printf ("%s\n", (newname ? newname : print_prog_name));
return (0);
}
if (print_multi_lib)
{
print_multilib_info ();
return (0);
}
if (print_multi_directory)
{
if (multilib_dir == NULL)
printf (".\n");
else
printf ("%s\n", multilib_dir);
return (0);
}
if (print_sysroot)
{
if (target_system_root)
{
if (target_sysroot_suffix)
printf ("%s%s\n", target_system_root, target_sysroot_suffix);
else
printf ("%s\n", target_system_root);
}
return (0);
}
if (print_multi_os_directory)
{
if (multilib_os_dir == NULL)
printf (".\n");
else
printf ("%s\n", multilib_os_dir);
return (0);
}
if (print_sysroot_headers_suffix)
{
if (*sysroot_hdrs_suffix_spec)
{
printf("%s\n", (target_sysroot_hdrs_suffix
? target_sysroot_hdrs_suffix
: ""));
return (0);
}
else
/* The error status indicates that only one set of fixed
headers should be built. */
fatal_error ("not configured with sysroot headers suffix");
}
if (print_help_list)
{
display_help ();
if (! verbose_flag)
{
printf (_("\nFor bug reporting instructions, please see:\n"));
printf ("%s.\n", bug_report_url);
return (0);
}
/* We do not exit here. Instead we have created a fake input file
called 'help-dummy' which needs to be compiled, and we pass this
on the various sub-processes, along with the --help switch.
Ensure their output appears after ours. */
fputc ('\n', stdout);
fflush (stdout);
}
if (print_version)
{
printf (_("%s %s%s\n"), progname, pkgversion_string,
version_string);
printf ("Copyright %s 2011 Free Software Foundation, Inc.\n",
_("(C)"));
fputs (_("This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"),
stdout);
if (! verbose_flag)
return 0;
/* We do not exit here. We use the same mechanism of --help to print
the version of the sub-processes. */
fputc ('\n', stdout);
fflush (stdout);
}
if (verbose_flag)
{
int n;
const char *thrmod;
fnotice (stderr, "Target: %s\n", spec_machine);
fnotice (stderr, "Configured with: %s\n", configuration_arguments);
#ifdef THREAD_MODEL_SPEC
/* We could have defined THREAD_MODEL_SPEC to "%*" by default,
but there's no point in doing all this processing just to get
thread_model back. */
obstack_init (&obstack);
do_spec_1 (THREAD_MODEL_SPEC, 0, thread_model);
obstack_1grow (&obstack, '\0');
thrmod = XOBFINISH (&obstack, const char *);
#else
thrmod = thread_model;
#endif
fnotice (stderr, "Thread model: %s\n", thrmod);
/* compiler_version is truncated at the first space when initialized
from version string, so truncate version_string at the first space
before comparing. */
for (n = 0; version_string[n]; n++)
if (version_string[n] == ' ')
break;
if (! strncmp (version_string, compiler_version, n)
&& compiler_version[n] == 0)
fnotice (stderr, "gcc version %s %s\n", version_string,
pkgversion_string);
else
fnotice (stderr, "gcc driver version %s %sexecuting gcc version %s\n",
version_string, pkgversion_string, compiler_version);
if (n_infiles == 0)
return (0);
}
if (n_infiles == added_libraries)
fatal_error ("no input files");
if (seen_error ())
goto out;
/* Make a place to record the compiler output file names
that correspond to the input files. */
i = n_infiles;
i += lang_specific_extra_outfiles;
outfiles = XCNEWVEC (const char *, i);
/* Record which files were specified explicitly as link input. */
explicit_link_files = XCNEWVEC (char, n_infiles);
combine_inputs = have_o || flag_wpa;
for (i = 0; (int) i < n_infiles; i++)
{
const char *name = infiles[i].name;
struct compiler *compiler = lookup_compiler (name,
strlen (name),
infiles[i].language);
if (compiler && !(compiler->combinable))
combine_inputs = false;
if (lang_n_infiles > 0 && compiler != input_file_compiler
&& infiles[i].language && infiles[i].language[0] != '*')
infiles[i].incompiler = compiler;
else if (compiler)
{
lang_n_infiles++;
input_file_compiler = compiler;
infiles[i].incompiler = compiler;
}
else
{
/* Since there is no compiler for this input file, assume it is a
linker file. */
explicit_link_files[i] = 1;
infiles[i].incompiler = NULL;
}
infiles[i].compiled = false;
infiles[i].preprocessed = false;
}
if (!combine_inputs && have_c && have_o && lang_n_infiles > 1)
fatal_error ("cannot specify -o with -c, -S or -E with multiple files");
for (i = 0; (int) i < n_infiles; i++)
{
int this_file_error = 0;
/* Tell do_spec what to substitute for %i. */
input_file_number = i;
set_input (infiles[i].name);
if (infiles[i].compiled)
continue;
/* Use the same thing in %o, unless cp->spec says otherwise. */
outfiles[i] = gcc_input_filename;
/* Figure out which compiler from the file's suffix. */
input_file_compiler
= lookup_compiler (infiles[i].name, input_filename_length,
infiles[i].language);
if (input_file_compiler)
{
/* Ok, we found an applicable compiler. Run its spec. */
if (input_file_compiler->spec[0] == '#')
{
error ("%s: %s compiler not installed on this system",
gcc_input_filename, &input_file_compiler->spec[1]);
this_file_error = 1;
}
else
{
if (compare_debug)
{
if (debug_check_temp_file[0])
free (debug_check_temp_file[0]);
debug_check_temp_file[0] = NULL;
if (debug_check_temp_file[1])
free (debug_check_temp_file[1]);
debug_check_temp_file[1] = NULL;
}
value = do_spec (input_file_compiler->spec);
infiles[i].compiled = true;
if (value < 0)
this_file_error = 1;
else if (compare_debug && debug_check_temp_file[0])
{
if (verbose_flag)
inform (0, "recompiling with -fcompare-debug");
compare_debug = -compare_debug;
n_switches = n_switches_debug_check[1];
n_switches_alloc = n_switches_alloc_debug_check[1];
switches = switches_debug_check[1];
value = do_spec (input_file_compiler->spec);
compare_debug = -compare_debug;
n_switches = n_switches_debug_check[0];
n_switches_alloc = n_switches_alloc_debug_check[0];
switches = switches_debug_check[0];
if (value < 0)
{
error ("during -fcompare-debug recompilation");
this_file_error = 1;
}
gcc_assert (debug_check_temp_file[1]
&& strcmp (debug_check_temp_file[0],
debug_check_temp_file[1]));
if (verbose_flag)
inform (0, "comparing final insns dumps");
if (compare_files (debug_check_temp_file))
this_file_error = 1;
}
if (compare_debug)
{
if (debug_check_temp_file[0])
free (debug_check_temp_file[0]);
debug_check_temp_file[0] = NULL;
if (debug_check_temp_file[1])
free (debug_check_temp_file[1]);
debug_check_temp_file[1] = NULL;
}
}
}
/* If this file's name does not contain a recognized suffix,
record it as explicit linker input. */
else
explicit_link_files[i] = 1;
/* Clear the delete-on-failure queue, deleting the files in it
if this compilation failed. */
if (this_file_error)
{
delete_failure_queue ();
errorcount++;
}
/* If this compilation succeeded, don't delete those files later. */
clear_failure_queue ();
}
/* Reset the input file name to the first compile/object file name, for use
with %b in LINK_SPEC. We use the first input file that we can find
a compiler to compile it instead of using infiles.language since for
languages other than C we use aliases that we then lookup later. */
if (n_infiles > 0)
{
int i;
for (i = 0; i < n_infiles ; i++)
if (infiles[i].incompiler
|| (infiles[i].language && infiles[i].language[0] != '*'))
{
set_input (infiles[i].name);
break;
}
}
if (!seen_error ())
{
/* Make sure INPUT_FILE_NUMBER points to first available open
slot. */
input_file_number = n_infiles;
if (lang_specific_pre_link ())
errorcount++;
}
/* Determine if there are any linker input files. */
num_linker_inputs = 0;
for (i = 0; (int) i < n_infiles; i++)
if (explicit_link_files[i] || outfiles[i] != NULL)
num_linker_inputs++;
/* Run ld to link all the compiler output files. */
if (num_linker_inputs > 0 && !seen_error () && print_subprocess_help < 2)
{
int tmp = execution_count;
#ifdef HAVE_LTO_PLUGIN
const char *fno_use_linker_plugin = "fno-use-linker-plugin";
#else
const char *fuse_linker_plugin = "fuse-linker-plugin";
#endif
/* 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, false);
if (s == NULL)
linker_name_spec = "ld";
}
#ifdef HAVE_LTO_PLUGIN
if (!switch_matches (fno_use_linker_plugin,
fno_use_linker_plugin + strlen (fno_use_linker_plugin), 0))
#else
if (switch_matches (fuse_linker_plugin,
fuse_linker_plugin + strlen (fuse_linker_plugin), 0))
#endif
{
linker_plugin_file_spec = find_a_file (&exec_prefixes,
LTOPLUGINSONAME, R_OK,
false);
if (!linker_plugin_file_spec)
fatal_error ("-fuse-linker-plugin, but " LTOPLUGINSONAME " not found");
}
lto_gcc_spec = argv[0];
/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
for collect. */
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)
errorcount = 1;
linker_was_run = (tmp != execution_count);
}
/* If options said don't run linker,
complain about input files to be given to the linker. */
if (! linker_was_run && !seen_error ())
for (i = 0; (int) i < n_infiles; i++)
if (explicit_link_files[i]
&& !(infiles[i].language && infiles[i].language[0] == '*'))
warning (0, "%s: linker input file unused because linking not done",
outfiles[i]);
/* Delete some or all of the temporary files we made. */
if (seen_error ())
delete_failure_queue ();
delete_temp_files ();
if (print_help_list)
{
printf (("\nFor bug reporting instructions, please see:\n"));
printf ("%s\n", bug_report_url);
}
out:
return (signal_count != 0 ? 2
: seen_error () ? (pass_exit_codes ? greatest_status : 1)
: 0);
}
参考: http://code.woboq.org/gcc/gcc/gcc.c.html#6217