aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2015-08-25 20:25:05 +0000
committerDavid Malcolm <dmalcolm@gcc.gnu.org>2015-08-25 20:25:05 +0000
commit9376dd63e6a2d94823f6faf8212c9f37bef5a656 (patch)
tree2745652bd94e40ef40a21a22e1c88c4429fccab1 /gcc
parent25c65938c8794115531d09a37e17d3bc469f6269 (diff)
downloadgcc-9376dd63e6a2d94823f6faf8212c9f37bef5a656.zip
gcc-9376dd63e6a2d94823f6faf8212c9f37bef5a656.tar.gz
gcc-9376dd63e6a2d94823f6faf8212c9f37bef5a656.tar.bz2
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. From-SVN: r227188
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog36
-rw-r--r--gcc/gcc-main.c3
-rw-r--r--gcc/gcc.c400
-rw-r--r--gcc/gcc.h3
-rw-r--r--gcc/jit/ChangeLog33
-rw-r--r--gcc/jit/docs/cp/topics/contexts.rst20
-rw-r--r--gcc/jit/docs/internals/test-hello-world.exe.log.txt6
-rw-r--r--gcc/jit/docs/topics/compatibility.rst7
-rw-r--r--gcc/jit/docs/topics/contexts.rst20
-rw-r--r--gcc/jit/jit-common.h1
-rw-r--r--gcc/jit/jit-playback.c52
-rw-r--r--gcc/jit/jit-playback.h14
-rw-r--r--gcc/jit/jit-recording.c3
-rw-r--r--gcc/jit/libgccjit++.h8
-rw-r--r--gcc/jit/libgccjit.c17
-rw-r--r--gcc/jit/libgccjit.h24
-rw-r--r--gcc/jit/libgccjit.map5
-rw-r--r--gcc/jit/notes.txt8
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/jit.dg/test-error-pr63969-missing-driver.c4
20 files changed, 635 insertions, 34 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8cb2aeb..c79fb48 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,39 @@
+2015-08-25 David Malcolm <dmalcolm@redhat.com>
+
+ * 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.
+
2015-08-25 Nathan Sidwell <nathan@acm.org>
* optabs.c (emit_indirect_jump): Don't try an emit a jump if the
diff --git a/gcc/gcc-main.c b/gcc/gcc-main.c
index 230ba48..a0aaa3c 100644
--- a/gcc/gcc-main.c
+++ b/gcc/gcc-main.c
@@ -40,7 +40,8 @@ extern int main (int, char **);
int
main (int argc, char **argv)
{
- driver d;
+ driver d (false, /* can_finalize */
+ false); /* debug */
return d.main (argc, argv);
}
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 312bf04..4c37edc 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
diff --git a/gcc/gcc.h b/gcc/gcc.h
index f10a103..e1abe43 100644
--- a/gcc/gcc.h
+++ b/gcc/gcc.h
@@ -30,7 +30,10 @@ along with GCC; see the file COPYING3. If not see
class driver
{
public:
+ driver (bool can_finalize, bool debug);
+ ~driver ();
int main (int argc, char **argv);
+ void finalize ();
private:
void set_progname (const char *argv0) const;
diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog
index efa0d88..fae6436 100644
--- a/gcc/jit/ChangeLog
+++ b/gcc/jit/ChangeLog
@@ -1,3 +1,36 @@
+2015-08-25 David Malcolm <dmalcolm@redhat.com>
+
+ * 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
+
2015-08-13 David Malcolm <dmalcolm@redhat.com>
* jit-playback.c (invoke_driver): On OS X, add
diff --git a/gcc/jit/docs/cp/topics/contexts.rst b/gcc/jit/docs/cp/topics/contexts.rst
index 162e4ae..05ce230 100644
--- a/gcc/jit/docs/cp/topics/contexts.rst
+++ b/gcc/jit/docs/cp/topics/contexts.rst
@@ -201,6 +201,26 @@ Boolean options
#ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_allow_unreachable_blocks
+.. function:: void \
+ gccjit::context::set_bool_use_external_driver (int bool_value)
+
+ libgccjit internally generates assembler, and uses "driver" code
+ for converting it to other formats (e.g. shared libraries).
+
+ By default, libgccjit will use an embedded copy of the driver
+ code.
+
+ This option can be used to instead invoke an external driver executable
+ as a subprocess; it is a thin wrapper around the C API
+ :c:func:`gcc_jit_context_set_bool_use_external_driver`.
+
+ This entrypoint was added in :ref:`LIBGCCJIT_ABI_5`; you can test for
+ its presence using
+
+ .. code-block:: c
+
+ #ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_use_external_driver
+
Integer options
***************
diff --git a/gcc/jit/docs/internals/test-hello-world.exe.log.txt b/gcc/jit/docs/internals/test-hello-world.exe.log.txt
index d82038b..0bab86c 100644
--- a/gcc/jit/docs/internals/test-hello-world.exe.log.txt
+++ b/gcc/jit/docs/internals/test-hello-world.exe.log.txt
@@ -1,4 +1,4 @@
-JIT: libgccjit (GCC) version 6.0.0 20150723 (experimental) (x86_64-unknown-linux-gnu)
+JIT: libgccjit (GCC) version 6.0.0 20150803 (experimental) (x86_64-pc-linux-gnu)
JIT: compiled by GNU C version 4.8.3 20140911 (Red Hat 4.8.3-7), GMP version 5.1.2, MPFR version 3.1.2, MPC version 1.0.1
JIT: entering: gcc_jit_context_set_str_option
JIT: GCC_JIT_STR_OPTION_PROGNAME: "./test-hello-world.c.exe"
@@ -65,6 +65,7 @@ JIT: GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING: false
JIT: GCC_JIT_BOOL_OPTION_SELFCHECK_GC: true
JIT: GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES: false
JIT: gcc_jit_context_set_bool_allow_unreachable_blocks: false
+JIT: gcc_jit_context_set_bool_use_external_driver: false
JIT: entering: void gcc::jit::recording::context::validate()
JIT: exiting: void gcc::jit::recording::context::validate()
JIT: entering: gcc::jit::playback::context::context(gcc::jit::recording::context*)
@@ -133,7 +134,8 @@ JIT: argv[3]: /tmp/libgccjit-CKq1M9/fake.s
JIT: argv[4]: -o
JIT: argv[5]: /tmp/libgccjit-CKq1M9/fake.so
JIT: argv[6]: -fno-use-linker-plugin
-JIT: argv[7]: (null)
+JIT: entering: void gcc::jit::playback::context::invoke_embedded_driver(const vec<char*>*)
+JIT: exiting: void gcc::jit::playback::context::invoke_embedded_driver(const vec<char*>*)
JIT: exiting: void gcc::jit::playback::context::invoke_driver(const char*, const char*, const char*, timevar_id_t, bool, bool)
JIT: exiting: void gcc::jit::playback::context::convert_to_dso(const char*)
JIT: entering: gcc::jit::result* gcc::jit::playback::context::dlopen_built_dso()
diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst
index 0a4b453..e947cad 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -128,3 +128,10 @@ entrypoints:
* :func:`gcc_jit_timer_pop`
* :func:`gcc_jit_timer_print`
+
+.. _LIBGCCJIT_ABI_5:
+
+``LIBGCCJIT_ABI_5``
+-------------------
+``LIBGCCJIT_ABI_5`` covers the addition of
+:func:`gcc_jit_context_set_bool_use_external_driver`
diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst
index 1aa319a..53ceffb 100644
--- a/gcc/jit/docs/topics/contexts.rst
+++ b/gcc/jit/docs/topics/contexts.rst
@@ -469,6 +469,26 @@ Boolean options
#ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_allow_unreachable_blocks
+.. function:: void \
+ gcc_jit_context_set_bool_use_external_driver (gcc_jit_context *ctxt, \
+ int bool_value)
+
+ libgccjit internally generates assembler, and uses "driver" code
+ for converting it to other formats (e.g. shared libraries).
+
+ By default, libgccjit will use an embedded copy of the driver
+ code.
+
+ This option can be used to instead invoke an external driver executable
+ as a subprocess.
+
+ This entrypoint was added in :ref:`LIBGCCJIT_ABI_5`; you can test for
+ its presence using
+
+ .. code-block:: c
+
+ #ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_use_external_driver
+
Integer options
***************
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
index e6fc132..6400f30 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -191,6 +191,7 @@ private:
enum inner_bool_option
{
INNER_BOOL_OPTION_ALLOW_UNREACHABLE_BLOCKS,
+ INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER,
NUM_INNER_BOOL_OPTIONS
};
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index 01cfd4b..44c3ce0 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -2373,6 +2373,8 @@ convert_to_dso (const char *ctxt_progname)
true);/* bool run_linker */
}
+static const char * const gcc_driver_name = GCC_DRIVER_NAME;
+
void
playback::context::
invoke_driver (const char *ctxt_progname,
@@ -2383,15 +2385,15 @@ invoke_driver (const char *ctxt_progname,
bool run_linker)
{
JIT_LOG_SCOPE (get_logger ());
+
+ bool embedded_driver
+ = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
+
/* Currently this lumps together both assembling and linking into
TV_ASSEMBLE. */
auto_timevar assemble_timevar (get_timer (), tv_id);
- const char *errmsg;
auto_argvec argvec;
#define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
- int exit_status = 0;
- int err = 0;
- const char *gcc_driver_name = GCC_DRIVER_NAME;
ADD_ARG (gcc_driver_name);
@@ -2425,8 +2427,10 @@ invoke_driver (const char *ctxt_progname,
ADD_ARG ("-Wl,-undefined,dynamic_lookup");
#endif
- /* pex argv arrays are NULL-terminated. */
- argvec.safe_push (NULL);
+ if (0)
+ ADD_ARG ("-v");
+
+#undef ADD_ARG
/* pex_one's error-handling requires pname to be non-NULL. */
gcc_assert (ctxt_progname);
@@ -2435,9 +2439,42 @@ invoke_driver (const char *ctxt_progname,
for (unsigned i = 0; i < argvec.length (); i++)
get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
+ if (embedded_driver)
+ invoke_embedded_driver (&argvec);
+ else
+ invoke_external_driver (ctxt_progname, &argvec);
+}
+
+void
+playback::context::
+invoke_embedded_driver (const vec <char *> *argvec)
+{
+ JIT_LOG_SCOPE (get_logger ());
+ driver d (true, /* can_finalize */
+ false); /* debug */
+ int result = d.main (argvec->length (),
+ const_cast <char **> (argvec->address ()));
+ d.finalize ();
+ if (result)
+ add_error (NULL, "error invoking gcc driver");
+}
+
+void
+playback::context::
+invoke_external_driver (const char *ctxt_progname,
+ vec <char *> *argvec)
+{
+ JIT_LOG_SCOPE (get_logger ());
+ const char *errmsg;
+ int exit_status = 0;
+ int err = 0;
+
+ /* pex argv arrays are NULL-terminated. */
+ argvec->safe_push (NULL);
+
errmsg = pex_one (PEX_SEARCH, /* int flags, */
gcc_driver_name,
- const_cast <char *const *> (argvec.address ()),
+ const_cast <char *const *> (argvec->address ()),
ctxt_progname, /* const char *pname */
NULL, /* const char *outname */
NULL, /* const char *errname */
@@ -2464,7 +2501,6 @@ invoke_driver (const char *ctxt_progname,
getenv ("PATH"));
return;
}
-#undef ADD_ARG
}
/* Extract the target-specific MULTILIB_DEFAULTS to
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 52e402f..d99db54 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -177,6 +177,12 @@ public:
return m_recording_ctxt->get_bool_option (opt);
}
+ int
+ get_inner_bool_option (enum inner_bool_option opt) const
+ {
+ return m_recording_ctxt->get_inner_bool_option (opt);
+ }
+
builtins_manager *get_builtins_manager () const
{
return m_recording_ctxt->get_builtins_manager ();
@@ -280,6 +286,14 @@ protected:
result *
dlopen_built_dso ();
+ private:
+ void
+ invoke_embedded_driver (const vec <char *> *argvec);
+
+ void
+ invoke_external_driver (const char *ctxt_progname,
+ vec <char *> *argvec);
+
private:
::gcc::jit::recording::context *m_recording_ctxt;
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 811d7c0..70bd171 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -1452,7 +1452,8 @@ static const char * const
static const char * const
inner_bool_option_reproducer_strings[NUM_INNER_BOOL_OPTIONS] = {
- "gcc_jit_context_set_bool_allow_unreachable_blocks"
+ "gcc_jit_context_set_bool_allow_unreachable_blocks",
+ "gcc_jit_context_set_bool_use_external_driver"
};
/* Write the current value of all options to the log file (if any). */
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index d7e491b..ef9bef1 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -124,6 +124,7 @@ namespace gccjit
int value);
void set_bool_allow_unreachable_blocks (int bool_value);
+ void set_bool_use_external_driver (int bool_value);
void add_command_line_option (const char *optname);
@@ -666,6 +667,13 @@ context::set_bool_allow_unreachable_blocks (int bool_value)
}
inline void
+context::set_bool_use_external_driver (int bool_value)
+{
+ gcc_jit_context_set_bool_use_external_driver (m_inner_ctxt,
+ bool_value);
+}
+
+inline void
context::add_command_line_option (const char *optname)
{
gcc_jit_context_add_command_line_option (m_inner_ctxt, optname);
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index eb9200c..55cda6b 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -2611,6 +2611,23 @@ gcc_jit_context_set_bool_allow_unreachable_blocks (gcc_jit_context *ctxt,
/* Public entrypoint. See description in libgccjit.h.
After error-checking, the real work is done by the
+ gcc::jit::recording::context::set_inner_bool_option method in
+ jit-recording.c. */
+
+extern void
+gcc_jit_context_set_bool_use_external_driver (gcc_jit_context *ctxt,
+ int bool_value)
+{
+ RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+ JIT_LOG_FUNC (ctxt->get_logger ());
+ ctxt->set_inner_bool_option (
+ gcc::jit::INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER,
+ bool_value);
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
gcc::jit::recording::context::add_command_line_option method in
jit-recording.c. */
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 88e4ff3..442ad0a 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -278,6 +278,30 @@ gcc_jit_context_set_bool_allow_unreachable_blocks (gcc_jit_context *ctxt,
tested for with #ifdef. */
#define LIBGCCJIT_HAVE_gcc_jit_context_set_bool_allow_unreachable_blocks
+/* Implementation detail:
+ libgccjit internally generates assembler, and uses "driver" code
+ for converting it to other formats (e.g. shared libraries).
+
+ By default, libgccjit will use an embedded copy of the driver
+ code.
+
+ This option can be used to instead invoke an external driver executable
+ as a subprocess.
+
+ This entrypoint was added in LIBGCCJIT_ABI_5; you can test for
+ its presence using
+ #ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_use_external_driver
+*/
+
+extern void
+gcc_jit_context_set_bool_use_external_driver (gcc_jit_context *ctxt,
+ int bool_value);
+
+/* Pre-canned feature macro to indicate the presence of
+ gcc_jit_context_set_bool_use_external_driver. This can be
+ tested for with #ifdef. */
+#define LIBGCCJIT_HAVE_gcc_jit_context_set_bool_use_external_driver
+
/* Add an arbitrary gcc command-line option to the context.
The context takes a copy of the string, so the
(const char *) optname is not needed anymore after the call
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index e4302c6..a3ced26 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -140,3 +140,8 @@ LIBGCCJIT_ABI_4 {
gcc_jit_timer_pop;
gcc_jit_timer_print;
};
+
+LIBGCCJIT_ABI_5 {
+ global:
+ gcc_jit_context_set_bool_use_external_driver;
+} LIBGCCJIT_ABI_4;
diff --git a/gcc/jit/notes.txt b/gcc/jit/notes.txt
index e92c665..36e05cb 100644
--- a/gcc/jit/notes.txt
+++ b/gcc/jit/notes.txt
@@ -78,7 +78,13 @@ Client Code . Generated . libgccjit.so
. . │ . .
. . │ (assuming an in-memory compile):
. . │ . .
- . . │ . Convert assembler to DSO ("fake.so")
+ . . --> Convert assembler to DSO, via embedded
+ . . copy of driver:
+ . . driver::main ()
+ . . invocation of "as"
+ . . invocation of "ld"
+ . . driver::finalize ()
+ . . <----
. . │ . .
. . │ . Load DSO (dlopen "fake.so")
. . │ . .
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 9b0f9c0..7deb147 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2015-08-25 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-error-pr63969-missing-driver.c: Add call to
+ gcc_jit_context_set_bool_use_external_driver.
+
2015-08-25 Nathan Sidwell <nathan@acm.org>
* gcc.c-torture/execute/builtins/20010124-1.x: New.
diff --git a/gcc/testsuite/jit.dg/test-error-pr63969-missing-driver.c b/gcc/testsuite/jit.dg/test-error-pr63969-missing-driver.c
index 13f5e3b..7335223 100644
--- a/gcc/testsuite/jit.dg/test-error-pr63969-missing-driver.c
+++ b/gcc/testsuite/jit.dg/test-error-pr63969-missing-driver.c
@@ -21,6 +21,10 @@ create_code (gcc_jit_context *ctxt, void *user_data)
Unset it. */
gcc_jit_context_set_str_option (ctxt, GCC_JIT_STR_OPTION_PROGNAME, NULL);
+ /* By default, we use an embedded copy of the driver.
+ Opt-in to using an external copy of the driver. */
+ gcc_jit_context_set_bool_use_external_driver (ctxt, 1);
+
/* Break PATH, so that the driver can't be found
by gcc::jit::playback::context::compile ()
within gcc_jit_context_compile. */