gcc.c: Split up the driver's "main" into smaller functions

gcc/ChangeLog:
	* gcc.c (class driver): New class.
	(main): Reimplement in terms of driver::main, moving most of the
	locals to be locals within individual methods of class driver.
	The remaining locals "explicit_link_files", "decoded_options" and
	"decoded_options_count" are used by multiple driver:: methods, and
	so become member data.  Doing so isolates the argc/argv reads and
	writes.  Replace "goto out" with a special exit code from
	new method driver::prepare_infiles.  Split out the old
	implementation of main into the following...
	(driver::main): New function, corresponding to the old "main"
	implementation.
	(driver::set_progname): New function, taken from the old
	"main" implementation.
	(driver::expand_at_files): Likewise.
	(driver::decode_argv): Likewise.
	(driver::global_initializations): Likewise.
	(driver::build_multilib_strings): Likewise.
	(driver::set_up_specs): Likewise.
	(driver::putenv_COLLECT_GCC): Likewise.
	(driver::maybe_putenv_COLLECT_LTO_WRAPPER): Likewise.
	(driver::handle_unrecognized_options): Likewise.
	(driver::maybe_print_and_exit): Likewise.
	(driver::prepare_infiles): Likewise.
	(driver::do_spec_on_infiles): Likewise.
	(driver::maybe_run_linker): Likewise.
	(driver::final_actions): Likewise.
	(driver::get_exit_code): Likewise.

From-SVN: r215861
This commit is contained in:
David Malcolm 2014-10-03 16:28:03 +00:00 committed by David Malcolm
parent 2bd8ca2100
commit 742a072ad0
2 changed files with 231 additions and 35 deletions

View File

@ -1,3 +1,33 @@
2014-10-03 David Malcolm <dmalcolm@redhat.com>
* gcc.c (class driver): New class.
(main): Reimplement in terms of driver::main, moving most of the
locals to be locals within individual methods of class driver.
The remaining locals "explicit_link_files", "decoded_options" and
"decoded_options_count" are used by multiple driver:: methods, and
so become member data. Doing so isolates the argc/argv reads and
writes. Replace "goto out" with a special exit code from
new method driver::prepare_infiles. Split out the old
implementation of main into the following...
(driver::main): New function, corresponding to the old "main"
implementation.
(driver::set_progname): New function, taken from the old
"main" implementation.
(driver::expand_at_files): Likewise.
(driver::decode_argv): Likewise.
(driver::global_initializations): Likewise.
(driver::build_multilib_strings): Likewise.
(driver::set_up_specs): Likewise.
(driver::putenv_COLLECT_GCC): Likewise.
(driver::maybe_putenv_COLLECT_LTO_WRAPPER): Likewise.
(driver::handle_unrecognized_options): Likewise.
(driver::maybe_print_and_exit): Likewise.
(driver::prepare_infiles): Likewise.
(driver::do_spec_on_infiles): Likewise.
(driver::maybe_run_linker): Likewise.
(driver::final_actions): Likewise.
(driver::get_exit_code): Likewise.
2014-10-03 Yury Gribov <y.gribov@samsung.com>
* asan.c (asan_finish_file): Disable __asan_init calls for KASan;

236
gcc/gcc.c
View File

@ -6724,49 +6724,132 @@ compare_files (char *cmpfile[])
return ret;
}
/* The top-level "main" within the driver would be ~1000 lines long.
This class breaks it up into smaller functions and contains some
state shared by them. */
class driver
{
public:
int main (int argc, char **argv);
private:
void set_progname (const char *argv0) const;
void expand_at_files (int *argc, char ***argv) const;
void decode_argv (int argc, const char **argv);
void global_initializations () const;
void build_multilib_strings () const;
void set_up_specs () const;
void putenv_COLLECT_GCC (const char *argv0) const;
void maybe_putenv_COLLECT_LTO_WRAPPER () const;
void handle_unrecognized_options () const;
int maybe_print_and_exit () const;
bool prepare_infiles ();
void do_spec_on_infiles () const;
void maybe_run_linker (const char *argv0) const;
void final_actions () const;
int get_exit_code () const;
private:
char *explicit_link_files;
struct cl_decoded_option *decoded_options;
unsigned int decoded_options_count;
};
/* Implement the top-level "main" within the driver in terms of
driver::main. */
extern int main (int, char **);
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;
driver d;
p = argv[0] + strlen (argv[0]);
while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
return d.main (argc, argv);
}
/* driver::main is implemented as a series of driver:: method calls. */
int
driver::main (int argc, char **argv)
{
bool early_exit;
set_progname (argv[0]);
expand_at_files (&argc, &argv);
decode_argv (argc, const_cast <const char **> (argv));
global_initializations ();
build_multilib_strings ();
set_up_specs ();
putenv_COLLECT_GCC (argv[0]);
maybe_putenv_COLLECT_LTO_WRAPPER ();
handle_unrecognized_options ();
if (!maybe_print_and_exit ())
return 0;
early_exit = prepare_infiles ();
if (early_exit)
return get_exit_code ();
do_spec_on_infiles ();
maybe_run_linker (argv[0]);
final_actions ();
return get_exit_code ();
}
/* Locate the final component of argv[0] after any leading path, and set
the program name accordingly. */
void
driver::set_progname (const char *argv0) const
{
const char *p = argv0 + strlen (argv0);
while (p != argv0 && !IS_DIR_SEPARATOR (p[-1]))
--p;
progname = p;
xmalloc_set_program_name (progname);
}
expandargv (&argc, &argv);
/* Expand any @ files within the command-line args,
setting at_file_supplied if any were expanded. */
void
driver::expand_at_files (int *argc, char ***argv) const
{
char **old_argv = *argv;
expandargv (argc, argv);
/* Determine if any expansions were made. */
if (argv != old_argv)
if (*argv != old_argv)
at_file_supplied = true;
}
/* Decode the command-line arguments from argc/argv into the
decoded_options array. */
void
driver::decode_argv (int argc, const char **argv)
{
/* Register the language-independent parameters. */
global_init_params ();
finish_params ();
init_options_struct (&global_options, &global_options_set);
decode_cmdline_options_to_array (argc, CONST_CAST2 (const char **, char **,
argv),
decode_cmdline_options_to_array (argc, argv,
CL_DRIVER,
&decoded_options, &decoded_options_count);
}
/* Perform various initializations and setup. */
void
driver::global_initializations () const
{
/* Unlock the stdio streams. */
unlock_std_streams ();
@ -6808,10 +6891,16 @@ main (int argc, char **argv)
alloc_args ();
obstack_init (&obstack);
}
/* Build multilib_select, et. al 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. */
void
driver::build_multilib_strings () const
{
{
const char *p;
const char *const *q = multilib_raw;
int need_space;
@ -6844,7 +6933,7 @@ main (int argc, char **argv)
multilib_reuse = XOBFINISH (&multilib_obstack, const char *);
need_space = FALSE;
for (i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
{
if (need_space)
obstack_1grow (&multilib_obstack, ' ');
@ -6857,6 +6946,15 @@ main (int argc, char **argv)
obstack_1grow (&multilib_obstack, 0);
multilib_defaults = XOBFINISH (&multilib_obstack, const char *);
}
}
/* Set up the spec-handling machinery. */
void
driver::set_up_specs () const
{
char *specs_file;
size_t i;
#ifdef INIT_ENVIRONMENT
/* Set up any other necessary machine specific environment variables. */
@ -7016,7 +7114,7 @@ main (int argc, char **argv)
/* Process any user specified specs in the order given on the command
line. */
for (uptr = user_specs_head; uptr; uptr = uptr->next)
for (struct user_specs *uptr = user_specs_head; uptr; uptr = uptr->next)
{
char *filename = find_a_file (&startfile_prefixes, uptr->filename,
R_OK, true);
@ -7088,16 +7186,27 @@ main (int argc, char **argv)
/* 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. */
/* 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. */
void
driver::putenv_COLLECT_GCC (const char *argv0) const
{
obstack_init (&collect_obstack);
obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1);
obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1);
obstack_grow (&collect_obstack, argv0, strlen (argv0) + 1);
xputenv (XOBFINISH (&collect_obstack, char *));
}
/* Set up to remember the pathname of the lto wrapper. */
/* Set up to remember the pathname of the lto wrapper. */
void
driver::maybe_putenv_COLLECT_LTO_WRAPPER () const
{
char *lto_wrapper_file;
if (have_c)
lto_wrapper_file = NULL;
@ -7116,14 +7225,24 @@ main (int argc, char **argv)
xputenv (XOBFINISH (&collect_obstack, char *));
}
/* Reject switches that no pass was interested in. */
}
for (i = 0; (int) i < n_switches; i++)
/* Reject switches that no pass was interested in. */
void
driver::handle_unrecognized_options () const
{
for (size_t i = 0; (int) i < n_switches; i++)
if (! switches[i].validated)
error ("unrecognized command line option %<-%s%>", switches[i].part1);
}
/* Obey some of the options. */
/* Handle the various -print-* options, returning 0 if the driver
should exit, or nonzero if the driver should continue. */
int
driver::maybe_print_and_exit () const
{
if (print_search_dirs)
{
printf (_("install: %s%s\n"),
@ -7286,11 +7405,24 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
return (0);
}
return 1;
}
/* Figure out what to do with each input file.
Return true if we need to exit early from "main", false otherwise. */
bool
driver::prepare_infiles ()
{
size_t i;
int lang_n_infiles = 0;
if (n_infiles == added_libraries)
fatal_error ("no input files");
if (seen_error ())
goto out;
/* Early exit needed from main. */
return true;
/* Make a place to record the compiler output file names
that correspond to the input files. */
@ -7338,6 +7470,17 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
if (!combine_inputs && have_c && have_o && lang_n_infiles > 1)
fatal_error ("cannot specify -o with -c, -S or -E with multiple files");
/* No early exit needed from main; we can continue. */
return false;
}
/* Run the spec machinery on each input file. */
void
driver::do_spec_on_infiles () const
{
size_t i;
for (i = 0; (int) i < n_infiles; i++)
{
int this_file_error = 0;
@ -7372,6 +7515,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
}
else
{
int value;
if (compare_debug)
{
free (debug_check_temp_file[0]);
@ -7473,6 +7618,16 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
if (lang_specific_pre_link ())
errorcount++;
}
}
/* If we have to run the linker, do it now. */
void
driver::maybe_run_linker (const char *argv0) const
{
size_t i;
int linker_was_run = 0;
int num_linker_inputs;
/* Determine if there are any linker input files. */
num_linker_inputs = 0;
@ -7524,7 +7679,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
linker_plugin_file_spec = convert_white_space (temp_spec);
}
#endif
lto_gcc_spec = argv[0];
lto_gcc_spec = argv0;
}
/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
@ -7539,7 +7694,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
" to the linker.\n\n"));
fflush (stdout);
}
value = do_spec (link_command_spec);
int value = do_spec (link_command_spec);
if (value < 0)
errorcount = 1;
linker_was_run = (tmp != execution_count);
@ -7554,7 +7709,13 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
&& !(infiles[i].language && infiles[i].language[0] == '*'))
warning (0, "%s: linker input file unused because linking not done",
outfiles[i]);
}
/* The end of "main". */
void
driver::final_actions () const
{
/* Delete some or all of the temporary files we made. */
if (seen_error ())
@ -7566,8 +7727,13 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
printf (("\nFor bug reporting instructions, please see:\n"));
printf ("%s\n", bug_report_url);
}
}
out:
/* Determine what the exit code of the driver should be. */
int
driver::get_exit_code () const
{
return (signal_count != 0 ? 2
: seen_error () ? (pass_exit_codes ? greatest_status : 1)
: 0);