Support embedding the driver in-process within libgccjit
authorDavid Malcolm <dmalcolm@redhat.com>
Tue, 25 Aug 2015 20:25:05 +0000 (20:25 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Tue, 25 Aug 2015 20:25:05 +0000 (20:25 +0000)
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

20 files changed:
gcc/ChangeLog
gcc/gcc-main.c
gcc/gcc.c
gcc/gcc.h
gcc/jit/ChangeLog
gcc/jit/docs/cp/topics/contexts.rst
gcc/jit/docs/internals/test-hello-world.exe.log.txt
gcc/jit/docs/topics/compatibility.rst
gcc/jit/docs/topics/contexts.rst
gcc/jit/jit-common.h
gcc/jit/jit-playback.c
gcc/jit/jit-playback.h
gcc/jit/jit-recording.c
gcc/jit/libgccjit++.h
gcc/jit/libgccjit.c
gcc/jit/libgccjit.h
gcc/jit/libgccjit.map
gcc/jit/notes.txt
gcc/testsuite/ChangeLog
gcc/testsuite/jit.dg/test-error-pr63969-missing-driver.c

index 8cb2aeb7633dbc4e2ce71c0902ee6bbec5c3d05b..c79fb4870f7db963da74732ca5e370cd0a5e6b45 100644 (file)
@@ -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
index 230ba4846cd46c60d3c4b8fa8d943687200cfb43..a0aaa3c7fc71a560953e5558113f79ece3252843 100644 (file)
@@ -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);
 }
index 312bf04b47e8e26652e83fb12f9eeb8af8dac30b..4c37edcedcc2cf93919d626ef6338a4d93d80db5 100644 (file)
--- 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"
 
+\f
+
+/* 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
+
+\f
+
 /* 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);
 }
 \f
 /* 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
index f10a103cd5b264555a2cb845716de37e42392c5a..e1abe43b15f86643aa1d0ae402496255a6d9553e 100644 (file)
--- 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;
index efa0d8892036bfd767ea31c1ee93141d63b83e7d..fae643686f773b8387fe8e6474a9b9833fa336cb 100644 (file)
@@ -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
index 162e4aec8f397f9a601782e22bd61f8f37e7185e..05ce2308624797de8ba3f78d8d779a62bb69e6a3 100644 (file)
@@ -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
 ***************
 
index d82038be864743ea28238d262c7baa39b95d4f20..0bab86c25d71d80df37046e5c10005a4581d7c1f 100644 (file)
@@ -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()
index 0a4b4533f7ebe9a9c7fcdda27d66e4ef4bacf524..e947cad4320223b9c6a4a1410d5538e853e80bd2 100644 (file)
@@ -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`
index 1aa319a9a3f4f1d199332379b05686d96f802592..53ceffb6dedb9a53b4bc34d9779eeb4af9173ec6 100644 (file)
@@ -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
 ***************
 
index e6fc132c6c223b06e81388cf2d200cd285b958f9..6400f307d4bd6e57088d3aca9b573085bbfbf00a 100644 (file)
@@ -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
 };
index 01cfd4baf13ec09acbd0dc7d67852ee77d3212cd..44c3ce00d98b5254a33d220763893e46c687e209 100644 (file)
@@ -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
index 52e402f9eec72d8bbe5d067dd932a7740183f5bc..d99db542021597daf4340ef7d5ae443fc5bc3c7f 100644 (file)
@@ -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;
 
index 811d7c0354436fa75d4dfb8866c09916e8c8b7fe..70bd171a892024a1bd86f2b53adbbbff34fc56b1 100644 (file)
@@ -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).  */
index d7e491bbfdccd0810a7b55d09980ee67c74f6b9f..ef9bef1af4780d9249a95da328389344ac1a1c6b 100644 (file)
@@ -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);
 
@@ -665,6 +666,13 @@ context::set_bool_allow_unreachable_blocks (int bool_value)
                                                     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)
 {
index eb9200cef5f846b8883bb43e4e73e9dfdbaac4dd..55cda6bf890f3509b26572ca48d46b4b0ba26318 100644 (file)
@@ -2608,6 +2608,23 @@ gcc_jit_context_set_bool_allow_unreachable_blocks (gcc_jit_context *ctxt,
     bool_value);
 }
 
+/* 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
index 88e4ff31a2886df184100b825ffa953ae2fb47a9..442ad0a62aca0127467dadaa54d17791a43f6318 100644 (file)
@@ -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
index e4302c6d379c37da27abc608f251954fd0665343..a3ced26a562b01c4160d2d00674924a09944c177 100644 (file)
@@ -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;
index e92c6651f00001a4157f36ed6e6232764badb28d..36e05cb7f237d931f97ab7d355e06bb949076dc8 100644 (file)
@@ -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")
               .           .      │   .               .
index 9b0f9c03f6b031822f37d879314d64a7f706fa27..7deb14776ca993b48b293eb4ad6ce6c35f1acb18 100644 (file)
@@ -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.
index 13f5e3b5b83ba1123e9691233c4c99675946842f..733522310debfcdd7a11f4f67deb2ae38251a3d7 100644 (file)
@@ -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.  */