diff options
author | dmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-08-25 20:25:05 +0000 |
---|---|---|
committer | dmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-08-25 20:25:05 +0000 |
commit | 26a4a13d0985e9752b704a41014d7d73baa50367 (patch) | |
tree | 2745652bd94e40ef40a21a22e1c88c4429fccab1 /gcc/gcc.c | |
parent | 159a52e9e5d92a2695166a5c2192655f3138d959 (diff) | |
download | gcc-26a4a13d0985e9752b704a41014d7d73baa50367.tar.gz |
Support embedding the driver in-process within libgccjit
gcc/ChangeLog:
* gcc-main.c (main): Add params to driver ctor.
* gcc.c (class env_manager): New.
(env): New global.
(env_manager::init): New.
(env_manager::get): New.
(env_manager::xput): New.
(env_manager::restore): New.
Poison getenv and putenv.
(DEFAULT_TARGET_SYSTEM_ROOT): New.
(target_system_root): Update initialization to use
DEFAULT_TARGET_SYSTEM_ROOT.
(struct spec_list): Add field "default_ptr".
(INIT_STATIC_SPEC): Initialize new field "default_ptr".
(init_spec): Likewise.
(set_spec): Clear field "default_ptr".
(read_specs): Free "spec" and "buffer".
(xputenv): Reimplement in terms of env_manager.
(process_command): Replace ::getenv calls with calls to the
env_manager singleton.
(process_brace_body): Free string in three places.
(driver::driver): New.
(driver::~driver): New.
(used_arg): Convert from a function to...
(class used_arg_t): ...this class, and...
(used_arg): ...this new global instance.
(used_arg_t::finalize): New function.
(getenv_spec_function): Add "const" to local "value". Replace
::getenv call with call to the env_manager singleton.
(path_prefix_reset): New function.
(driver::finalize): New function.
* gcc.h (driver::driver): New.
(driver::~driver): New.
(driver::finalize): New.
gcc/jit/ChangeLog:
* docs/cp/topics/contexts.rst
(gccjit::context::set_bool_use_external_driver): New.
* docs/internals/test-hello-world.exe.log.txt: Update.
* docs/topics/compatibility.rst (LIBGCCJIT_ABI_5): New.
* docs/topics/contexts.rst
(gcc_jit_context_set_bool_use_external_driver): New.
* jit-common.h (enum inner_bool_option): Add
INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER.
* jit-playback.c (gcc_driver_name): New global.
(gcc:jit::playback::context::invoke_driver): Split out second
half into...
(gcc::jit::playback::context::invoke_embedded_driver): ...this new
function, and...
(gcc::jit::playback::context::invoke_external_driver): ...this new
function.
* jit-playback.h
(gcc::jit::playback::context::get_inner_bool_option): New.
(gcc::jit::playback::context::invoke_embedded_driver): New.
(gcc::jit::playback::context::invoke_external_driver): New.
* jit-recording.c (inner_bool_option_reproducer_strings):
Add entry for INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER.
* libgccjit++.h
(gccjit::context::set_bool_use_external_driver): New.
* libgccjit.c (gcc_jit_context_set_bool_use_external_driver): New.
* libgccjit.h (gcc_jit_context_set_bool_use_external_driver): New.
(LIBGCCJIT_HAVE_gcc_jit_context_set_bool_use_external_driver):
New.
* libgccjit.map (LIBGCCJIT_ABI_5): New.
* notes.txt: Show invocation of embedded copy of driver.
* docs/internals/test-hello-world.exe.log.txt: Update
gcc/testsuite/ChangeLog:
* jit.dg/test-error-pr63969-missing-driver.c: Add call to
gcc_jit_context_set_bool_use_external_driver.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@227188 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/gcc.c')
-rw-r--r-- | gcc/gcc.c | 400 |
1 files changed, 379 insertions, 21 deletions
diff --git a/gcc/gcc.c b/gcc/gcc.c index 312bf04b47e..4c37edcedcc 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -43,6 +43,131 @@ compilation is specified by a string called a "spec". */ #include "params.h" #include "filenames.h" + + +/* Manage the manipulation of env vars. + + We poison "getenv" and "putenv", so that all enviroment-handling is + done through this class. Note that poisoning happens in the + preprocessor at the identifier level, and doesn't distinguish between + env.getenv (); + and + getenv (); + Hence we need to use "get" for the accessor method, not "getenv". */ + +class env_manager +{ + public: + void init (bool can_restore, bool debug); + const char *get (const char *name); + void xput (const char *string); + void restore (); + + private: + bool m_can_restore; + bool m_debug; + struct kv + { + char *m_key; + char *m_value; + }; + vec<kv> m_keys; + +}; + +/* The singleton instance of class env_manager. */ + +static env_manager env; + +/* Initializer for class env_manager. + + We can't do this as a constructor since we have a statically + allocated instance ("env" above). */ + +void +env_manager::init (bool can_restore, bool debug) +{ + m_can_restore = can_restore; + m_debug = debug; +} + +/* Get the value of NAME within the environment. Essentially + a wrapper for ::getenv, but adding logging, and the possibility + of caching results. */ + +const char * +env_manager::get (const char *name) +{ + const char *result = ::getenv (name); + if (m_debug) + fprintf (stderr, "env_manager::getenv (%s) -> %s\n", name, result); + return result; +} + +/* Put the given KEY=VALUE entry STRING into the environment. + If the env_manager was initialized with CAN_RESTORE set, then + also record the old value of KEY within the environment, so that it + can be later restored. */ + +void +env_manager::xput (const char *string) +{ + if (m_debug) + fprintf (stderr, "env_manager::xput (%s)\n", string); + if (verbose_flag) + fnotice (stderr, "%s\n", string); + + if (m_can_restore) + { + char *equals = strchr (const_cast <char *> (string), '='); + gcc_assert (equals); + + struct kv kv; + kv.m_key = strndup (string, equals - string); + const char *cur_value = ::getenv (kv.m_key); + if (m_debug) + fprintf (stderr, "saving old value: %s\n",cur_value); + kv.m_value = cur_value ? xstrdup (cur_value) : NULL; + m_keys.safe_push (kv); + } + + ::putenv (CONST_CAST (char *, string)); +} + +/* Undo any xputenv changes made since last restore. + Can only be called if the env_manager was initialized with + CAN_RESTORE enabled. */ + +void +env_manager::restore () +{ + unsigned int i; + struct kv *item; + + gcc_assert (m_can_restore); + + FOR_EACH_VEC_ELT_REVERSE (m_keys, i, item) + { + if (m_debug) + printf ("restoring saved key: %s value: %s\n", item->m_key, item->m_value); + if (item->m_value) + ::setenv (item->m_key, item->m_value, 1); + else + ::unsetenv (item->m_key); + free (item->m_key); + free (item->m_value); + } + + m_keys.truncate (0); +} + +/* Forbid other uses of getenv and putenv. */ +#if (GCC_VERSION >= 3000) +#pragma GCC poison getenv putenv +#endif + + + /* By default there is no special suffix for target executables. */ /* FIXME: when autoconf is fixed, remove the host check - dj */ #if defined(TARGET_EXECUTABLE_SUFFIX) && defined(HOST_EXECUTABLE_SUFFIX) @@ -115,10 +240,11 @@ FILE *report_times_to_file = NULL; and library files can be found in an alternate location. */ #ifdef TARGET_SYSTEM_ROOT -static const char *target_system_root = TARGET_SYSTEM_ROOT; +#define DEFAULT_TARGET_SYSTEM_ROOT (TARGET_SYSTEM_ROOT) #else -static const char *target_system_root = 0; +#define DEFAULT_TARGET_SYSTEM_ROOT (0) #endif +static const char *target_system_root = DEFAULT_TARGET_SYSTEM_ROOT; /* Nonzero means pass the updated target_system_root to the compiler. */ @@ -235,7 +361,6 @@ static const char *validate_switches (const char *, bool); static void validate_all_switches (void); static inline void validate_switches_from_spec (const char *, bool); static void give_switch (int, int); -static int used_arg (const char *, int); static int default_arg (const char *, int); static void set_multilib_dir (void); static void print_multilib_info (void); @@ -1395,10 +1520,12 @@ struct spec_list int name_len; /* length of the name */ bool user_p; /* whether string come from file spec. */ bool alloc_p; /* whether string was allocated */ + const char *default_ptr; /* The default value of *ptr_spec. */ }; #define INIT_STATIC_SPEC(NAME,PTR) \ - { NAME, NULL, PTR, (struct spec_list *) 0, sizeof (NAME) - 1, false, false } + { NAME, NULL, PTR, (struct spec_list *) 0, sizeof (NAME) - 1, false, false, \ + *PTR } /* List of statically defined specs. */ static struct spec_list static_specs[] = @@ -1566,6 +1693,8 @@ init_spec (void) sl->next = next; sl->name_len = strlen (sl->name); sl->ptr_spec = &sl->ptr; + gcc_assert (sl->ptr_spec != NULL); + sl->default_ptr = sl->ptr; next = sl; } #endif @@ -1740,6 +1869,7 @@ set_spec (const char *name, const char *spec, bool user_p) sl->alloc_p = 0; *(sl->ptr_spec) = ""; sl->next = specs; + sl->default_ptr = NULL; specs = sl; } @@ -2132,7 +2262,10 @@ read_specs (const char *filename, bool main_p, bool user_p) if (! strcmp (suffix, "*link_command")) link_command_spec = spec; else - set_spec (suffix + 1, spec, user_p); + { + set_spec (suffix + 1, spec, user_p); + free (spec); + } } else { @@ -2152,6 +2285,8 @@ read_specs (const char *filename, bool main_p, bool user_p) if (link_command_spec == 0) fatal_error (input_location, "spec file has no spec for linking"); + + XDELETEVEC (buffer); } /* Record the names of temporary files we tell compilers to write, @@ -2494,9 +2629,7 @@ add_to_obstack (char *path, void *data) static void xputenv (const char *string) { - if (verbose_flag) - fnotice (stderr, "%s\n", string); - putenv (CONST_CAST (char *, string)); + env.xput (string); } /* Build a list of search directories from PATHS. @@ -3970,7 +4103,7 @@ process_command (unsigned int decoded_options_count, struct cl_option_handlers handlers; unsigned int j; - gcc_exec_prefix = getenv ("GCC_EXEC_PREFIX"); + gcc_exec_prefix = env.get ("GCC_EXEC_PREFIX"); n_switches = 0; n_infiles = 0; @@ -4075,7 +4208,7 @@ process_command (unsigned int decoded_options_count, /* COMPILER_PATH and LIBRARY_PATH have values that are lists of directory names with colons. */ - temp = getenv ("COMPILER_PATH"); + temp = env.get ("COMPILER_PATH"); if (temp) { const char *startp, *endp; @@ -4109,7 +4242,7 @@ process_command (unsigned int decoded_options_count, } } - temp = getenv (LIBRARY_PATH_ENV); + temp = env.get (LIBRARY_PATH_ENV); if (temp && *cross_compile == '0') { const char *startp, *endp; @@ -4142,7 +4275,7 @@ process_command (unsigned int decoded_options_count, } /* Use LPATH like LIBRARY_PATH (for the CMU build program). */ - temp = getenv ("LPATH"); + temp = env.get ("LPATH"); if (temp && *cross_compile == '0') { const char *startp, *endp; @@ -4285,7 +4418,7 @@ process_command (unsigned int decoded_options_count, if (!compare_debug) { - const char *gcd = getenv ("GCC_COMPARE_DEBUG"); + const char *gcd = env.get ("GCC_COMPARE_DEBUG"); if (gcd && gcd[0] == '-') { @@ -6217,7 +6350,10 @@ process_brace_body (const char *p, const char *atom, const char *end_atom, if (!have_subst) { if (do_spec_1 (string, 0, NULL) < 0) - return 0; + { + free (string); + return 0; + } } else { @@ -6233,12 +6369,16 @@ process_brace_body (const char *p, const char *atom, const char *end_atom, { if (do_spec_1 (string, 0, &switches[i].part1[hard_match_len]) < 0) - return 0; + { + free (string); + return 0; + } /* Pass any arguments this switch has. */ give_switch (i, 1); suffix_subst = NULL; } } + free (string); } return p; @@ -6947,6 +7087,19 @@ compare_files (char *cmpfile[]) return ret; } +driver::driver (bool can_finalize, bool debug) : + explicit_link_files (NULL), + decoded_options (NULL) +{ + env.init (can_finalize, debug); +} + +driver::~driver () +{ + XDELETEVEC (explicit_link_files); + XDELETEVEC (decoded_options); +} + /* driver::main is implemented as a series of driver:: method calls. */ int @@ -8160,9 +8313,13 @@ static int n_mdswitches; /* Check whether a particular argument was used. The first time we canonicalize the switches to keep only the ones we care about. */ -static int -used_arg (const char *p, int len) +class used_arg_t { + public: + int operator () (const char *p, int len); + void finalize (); + + private: struct mswitchstr { const char *str; @@ -8171,8 +8328,16 @@ used_arg (const char *p, int len) int rep_len; }; - static struct mswitchstr *mswitches; - static int n_mswitches; + mswitchstr *mswitches; + int n_mswitches; + +}; + +used_arg_t used_arg; + +int +used_arg_t::operator () (const char *p, int len) +{ int i, j; if (!mswitches) @@ -8301,6 +8466,14 @@ used_arg (const char *p, int len) return 0; } +void used_arg_t::finalize () +{ + XDELETEVEC (mswitches); + mswitches = NULL; + n_mswitches = 0; +} + + static int default_arg (const char *p, int len) { @@ -8855,7 +9028,7 @@ print_multilib_info (void) static const char * getenv_spec_function (int argc, const char **argv) { - char *value; + const char *value; char *result; char *ptr; size_t len; @@ -8863,7 +9036,7 @@ getenv_spec_function (int argc, const char **argv) if (argc != 2) return NULL; - value = getenv (argv[0]); + value = env.get (argv[0]); if (!value) fatal_error (input_location, "environment variable %qs not defined", argv[0]); @@ -9526,6 +9699,191 @@ convert_white_space (char *orig) return orig; } +static void +path_prefix_reset (path_prefix *prefix) +{ + struct prefix_list *iter, *next; + iter = prefix->plist; + while (iter) + { + next = iter->next; + free (const_cast <char *> (iter->prefix)); + XDELETE (iter); + iter = next; + } + prefix->plist = 0; + prefix->max_len = 0; +} + +/* Restore all state within gcc.c to the initial state, so that the driver + code can be safely re-run in-process. + + Many const char * variables are referenced by static specs (see + INIT_STATIC_SPEC above). These variables are restored to their default + values by a simple loop over the static specs. + + For other variables, we directly restore them all to their initial + values (often implicitly 0). + + Free the various obstacks in this file, along with "opts_obstack" + from opts.c. + + This function also restores any environment variables that were changed. */ + +void +driver::finalize () +{ + env.restore (); + params_c_finalize (); + diagnostic_finish (global_dc); + + is_cpp_driver = 0; + at_file_supplied = 0; + print_help_list = 0; + print_version = 0; + verbose_only_flag = 0; + print_subprocess_help = 0; + use_ld = NULL; + report_times_to_file = NULL; + target_system_root = DEFAULT_TARGET_SYSTEM_ROOT; + target_system_root_changed = 0; + target_sysroot_suffix = 0; + target_sysroot_hdrs_suffix = 0; + save_temps_flag = SAVE_TEMPS_NONE; + save_temps_prefix = 0; + save_temps_length = 0; + spec_machine = DEFAULT_TARGET_MACHINE; + greatest_status = 1; + + finalize_options_struct (&global_options); + finalize_options_struct (&global_options_set); + + obstack_free (&obstack, NULL); + obstack_free (&opts_obstack, NULL); /* in opts.c */ + obstack_free (&collect_obstack, NULL); + + link_command_spec = LINK_COMMAND_SPEC; + + obstack_free (&multilib_obstack, NULL); + + user_specs_head = NULL; + user_specs_tail = NULL; + + /* Within the "compilers" vec, the fields "suffix" and "spec" were + statically allocated for the default compilers, but dynamically + allocated for additional compilers. Delete them for the latter. */ + for (int i = n_default_compilers; i < n_compilers; i++) + { + free (const_cast <char *> (compilers[i].suffix)); + free (const_cast <char *> (compilers[i].spec)); + } + XDELETEVEC (compilers); + compilers = NULL; + n_compilers = 0; + + linker_options.truncate (0); + assembler_options.truncate (0); + preprocessor_options.truncate (0); + + path_prefix_reset (&exec_prefixes); + path_prefix_reset (&startfile_prefixes); + path_prefix_reset (&include_prefixes); + + machine_suffix = 0; + just_machine_suffix = 0; + gcc_exec_prefix = 0; + gcc_libexec_prefix = 0; + md_exec_prefix = MD_EXEC_PREFIX; + md_startfile_prefix = MD_STARTFILE_PREFIX; + md_startfile_prefix_1 = MD_STARTFILE_PREFIX_1; + multilib_dir = 0; + multilib_os_dir = 0; + multiarch_dir = 0; + + XDELETEVEC (specs); + specs = 0; + for (unsigned i = 0; i < ARRAY_SIZE (static_specs); i++) + { + spec_list *sl = &static_specs[i]; + if (sl->alloc_p) + { + if (0) + free (const_cast <char *> (*(sl->ptr_spec))); + sl->alloc_p = false; + } + *(sl->ptr_spec) = sl->default_ptr; + } + extra_specs = NULL; + + processing_spec_function = 0; + + argbuf.truncate (0); + + have_c = 0; + have_o = 0; + + temp_names = NULL; + execution_count = 0; + signal_count = 0; + + temp_filename = NULL; + temp_filename_length = 0; + always_delete_queue = NULL; + failure_delete_queue = NULL; + + XDELETEVEC (switches); + switches = NULL; + n_switches = 0; + n_switches_alloc = 0; + + compare_debug = 0; + compare_debug_second = 0; + compare_debug_opt = NULL; + for (int i = 0; i < 2; i++) + { + switches_debug_check[i] = NULL; + n_switches_debug_check[i] = 0; + n_switches_alloc_debug_check[i] = 0; + debug_check_temp_file[i] = NULL; + } + + XDELETEVEC (infiles); + infiles = NULL; + n_infiles = 0; + n_infiles_alloc = 0; + + combine_inputs = false; + added_libraries = 0; + XDELETEVEC (outfiles); + outfiles = NULL; + spec_lang = 0; + last_language_n_infiles = 0; + gcc_input_filename = NULL; + input_file_number = 0; + input_filename_length = 0; + basename_length = 0; + suffixed_basename_length = 0; + input_basename = NULL; + input_suffix = NULL; + /* We don't need to purge "input_stat", just to unset "input_stat_set". */ + input_stat_set = 0; + input_file_compiler = NULL; + arg_going = 0; + delete_this_arg = 0; + this_is_output_file = 0; + this_is_library_file = 0; + this_is_linker_script = 0; + input_from_pipe = 0; + suffix_subst = NULL; + + mdswitches = NULL; + n_mdswitches = 0; + + debug_auxbase_opt = NULL; + + used_arg.finalize (); +} + /* PR jit/64810. Targets can provide configure-time default options in OPTION_DEFAULT_SPECS. The jit needs to access these, but |