[v2,17/21] libcc1: share the GCC interface code

Message ID 20210428010119.806184-18-tom@tromey.com
State New
Headers show
Series
  • C++11-based improvements for libcc1
Related show

Commit Message

Tom Tromey April 28, 2021, 1:01 a.m.
Both the C and C++ side of the GDB plugin in libcc1 share a lot of
code relating to the base GCC interface.  It was all copy-and-pasted,
but is essentially identical between the two.  This is by design, as
the base GCC API is intended to be shared.

This patch merges the implementations into base_gdb_plugin, which was
introduced earlier for this purpose.

libcc1/ChangeLog
2021-04-27  Tom Tromey  <tom@tromey.com>

	* libcp1.cc (libcp1): Change parameters.  Update.
	(libcp1_set_verbose, libcp1_set_arguments)
	(libcp1_set_triplet_regexp, libcp1_set_driver_filename)
	(libcp1_set_source_file, libcp1_set_print_callback, fork_exec)
	(libcp1_compile, libcp1_destroy, vtable): Remove.
	(libcp1::add_callbacks): New method, extracted from
	libcp1_compile.
	(gcc_c_fe_context): Update.
	* libcc1.cc (libcc1): Change parameters.  Update.
	(libcc1_set_verbose, libcc1_set_arguments)
	(libcc1_set_triplet_regexp, libcc1_set_driver_filename)
	(libcc1_set_source_file, libcc1_set_print_callback, fork_exec)
	(libcc1_compile, libcc1_destroy, vtable): Remove.
	(libcc1::add_callbacks): New method, extracted from
	libcc1_compile.
	(gcc_c_fe_context): Update.
	* gdbctx.hh (base_gdb_plugin): Change parameters.
	(~base_gdb_plugin): New.
	<add_callbacks>: New virtual method.
	<plugin_name, fe_version, compiler_name, vtable>: New members.
	(get_self, do_set_verbose, do_set_arguments)
	(do_set_triplet_regexp, do_set_driver_filename)
	(do_set_arguments_v0, do_set_source_file, do_set_print_callback)
	(fork_exec, do_compile, do_compile_v0, do_destroy): New methods.
---
 libcc1/ChangeLog |  27 +++++
 libcc1/gdbctx.hh | 253 ++++++++++++++++++++++++++++++++++++++++++++++-
 libcc1/libcc1.cc | 242 +++------------------------------------------
 libcc1/libcp1.cc | 246 +++------------------------------------------
 4 files changed, 304 insertions(+), 464 deletions(-)

-- 
2.26.2

Comments

Richard Biener via Gcc-patches April 30, 2021, 3:07 p.m. | #1
On 4/27/2021 7:01 PM, Tom Tromey wrote:
> Both the C and C++ side of the GDB plugin in libcc1 share a lot of

> code relating to the base GCC interface.  It was all copy-and-pasted,

> but is essentially identical between the two.  This is by design, as

> the base GCC API is intended to be shared.

>

> This patch merges the implementations into base_gdb_plugin, which was

> introduced earlier for this purpose.

>

> libcc1/ChangeLog

> 2021-04-27  Tom Tromey  <tom@tromey.com>

>

> 	* libcp1.cc (libcp1): Change parameters.  Update.

> 	(libcp1_set_verbose, libcp1_set_arguments)

> 	(libcp1_set_triplet_regexp, libcp1_set_driver_filename)

> 	(libcp1_set_source_file, libcp1_set_print_callback, fork_exec)

> 	(libcp1_compile, libcp1_destroy, vtable): Remove.

> 	(libcp1::add_callbacks): New method, extracted from

> 	libcp1_compile.

> 	(gcc_c_fe_context): Update.

> 	* libcc1.cc (libcc1): Change parameters.  Update.

> 	(libcc1_set_verbose, libcc1_set_arguments)

> 	(libcc1_set_triplet_regexp, libcc1_set_driver_filename)

> 	(libcc1_set_source_file, libcc1_set_print_callback, fork_exec)

> 	(libcc1_compile, libcc1_destroy, vtable): Remove.

> 	(libcc1::add_callbacks): New method, extracted from

> 	libcc1_compile.

> 	(gcc_c_fe_context): Update.

> 	* gdbctx.hh (base_gdb_plugin): Change parameters.

> 	(~base_gdb_plugin): New.

> 	<add_callbacks>: New virtual method.

> 	<plugin_name, fe_version, compiler_name, vtable>: New members.

> 	(get_self, do_set_verbose, do_set_arguments)

> 	(do_set_triplet_regexp, do_set_driver_filename)

> 	(do_set_arguments_v0, do_set_source_file, do_set_print_callback)

> 	(fork_exec, do_compile, do_compile_v0, do_destroy): New methods.


OK

Jeff

Patch

diff --git a/libcc1/gdbctx.hh b/libcc1/gdbctx.hh
index 1c8d87dff021..4a48381f2b4a 100644
--- a/libcc1/gdbctx.hh
+++ b/libcc1/gdbctx.hh
@@ -23,16 +23,38 @@  along with GCC; see the file COPYING3.  If not see
 namespace cc1_plugin
 {
   // The compiler context that we hand back to our caller.
+  // Due to this, the entire implementation is in this header.
   template<typename T>
   struct base_gdb_plugin : public T
   {
-    explicit base_gdb_plugin (const gcc_base_vtable *v)
+    base_gdb_plugin (const char *plugin_name_, const char *base_name,
+		     int version)
       : verbose (false),
+	plugin_name (plugin_name_),
+	fe_version (version),
+	compiler_name (base_name),
 	compilerp (new compiler (verbose))
     {
-      this->base.ops = v;
+      vtable =
+	{
+	  GCC_FE_VERSION_1,
+	  do_set_arguments_v0,
+	  do_set_source_file,
+	  do_set_print_callback,
+	  do_compile_v0,
+	  do_destroy,
+	  do_set_verbose,
+	  do_compile,
+	  do_set_arguments,
+	  do_set_triplet_regexp,
+	  do_set_driver_filename,
+	};
+
+      this->base.ops = &vtable;
     }
 
+    virtual ~base_gdb_plugin () = default;
+
     // A convenience function to print something.
     void print (const char *str)
     {
@@ -53,6 +75,10 @@  namespace cc1_plugin
       connection.reset (new local_connection (fd, aux_fd, this));
     }
 
+    // This is called just before compilation begins.  It should set
+    // any needed callbacks on the connection.
+    virtual void add_callbacks () = 0;
+
     // A local subclass of connection that holds a back-pointer to the
     // context object that we provide to our caller.
     class local_connection : public cc1_plugin::connection
@@ -84,7 +110,230 @@  namespace cc1_plugin
     /* Non-zero as an equivalent to gcc driver option "-v".  */
     bool verbose;
 
+    const char *plugin_name;
+    int fe_version;
+
+    const char *compiler_name;
     std::unique_ptr<cc1_plugin::compiler> compilerp;
+
+  private:
+
+    struct gcc_base_vtable vtable;
+
+    static inline base_gdb_plugin<T> *
+    get_self (gcc_base_context *s)
+    {
+      T *sub = (T *) s;
+      return static_cast<base_gdb_plugin<T> *> (sub);
+    }
+
+    static void
+    do_set_verbose (struct gcc_base_context *s, int /* bool */ verbose)
+    {
+      base_gdb_plugin<T> *self = get_self (s);
+
+      self->set_verbose (verbose != 0);
+    }
+
+    static char *
+    do_set_arguments (struct gcc_base_context *s,
+		      int argc, char **argv)
+    {
+      base_gdb_plugin<T> *self = get_self (s);
+
+      std::string compiler;
+      char *errmsg = self->compilerp->find (self->compiler_name, compiler);
+      if (errmsg != NULL)
+	return errmsg;
+
+      self->args.push_back (compiler);
+
+      for (int i = 0; i < argc; ++i)
+	self->args.push_back (argv[i]);
+
+      return NULL;
+    }
+
+    static char *
+    do_set_triplet_regexp (struct gcc_base_context *s,
+			   const char *triplet_regexp)
+    {
+      base_gdb_plugin<T> *self = get_self (s);
+
+      self->compilerp.reset
+	(new cc1_plugin::compiler_triplet_regexp (self->verbose,
+						  triplet_regexp));
+      return NULL;
+    }
+
+    static char *
+    do_set_driver_filename (struct gcc_base_context *s,
+			    const char *driver_filename)
+    {
+      base_gdb_plugin<T> *self = get_self (s);
+
+      self->compilerp.reset
+	(new cc1_plugin::compiler_driver_filename (self->verbose,
+						   driver_filename));
+      return NULL;
+    }
+
+    static char *
+    do_set_arguments_v0 (struct gcc_base_context *s,
+			 const char *triplet_regexp,
+			 int argc, char **argv)
+    {
+      char *errmsg = do_set_triplet_regexp (s, triplet_regexp);
+      if (errmsg != NULL)
+	return errmsg;
+
+      return do_set_arguments (s, argc, argv);
+    }
+
+    static void
+    do_set_source_file (struct gcc_base_context *s,
+			const char *file)
+    {
+      base_gdb_plugin<T> *self = get_self (s);
+
+      self->source_file = file;
+    }
+
+    static void
+    do_set_print_callback (struct gcc_base_context *s,
+			   void (*print_function) (void *datum,
+						   const char *message),
+			   void *datum)
+    {
+      base_gdb_plugin<T> *self = get_self (s);
+
+      self->print_function = print_function;
+      self->print_datum = datum;
+    }
+
+    int fork_exec (char **argv, int spair_fds[2], int stderr_fds[2])
+    {
+      pid_t child_pid = fork ();
+
+      if (child_pid == -1)
+	{
+	  close (spair_fds[0]);
+	  close (spair_fds[1]);
+	  close (stderr_fds[0]);
+	  close (stderr_fds[1]);
+	  return 0;
+	}
+
+      if (child_pid == 0)
+	{
+	  // Child.
+	  dup2 (stderr_fds[1], 1);
+	  dup2 (stderr_fds[1], 2);
+	  close (stderr_fds[0]);
+	  close (stderr_fds[1]);
+	  close (spair_fds[0]);
+
+	  execvp (argv[0], argv);
+	  _exit (127);
+	}
+      else
+	{
+	  // Parent.
+	  close (spair_fds[1]);
+	  close (stderr_fds[1]);
+
+	  cc1_plugin::status result = cc1_plugin::FAIL;
+	  if (connection->send ('H')
+	      && ::cc1_plugin::marshall (connection.get (), fe_version))
+	    result = connection->wait_for_query ();
+
+	  close (spair_fds[0]);
+	  close (stderr_fds[0]);
+
+	  while (true)
+	    {
+	      int status;
+
+	      if (waitpid (child_pid, &status, 0) == -1)
+		{
+		  if (errno != EINTR)
+		    return 0;
+		}
+
+	      if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
+		return 0;
+	      break;
+	    }
+
+	  if (!result)
+	    return 0;
+	  return 1;
+	}
+    }
+
+    static int
+    do_compile (struct gcc_base_context *s,
+		const char *filename)
+    {
+      base_gdb_plugin<T> *self = get_self (s);
+
+      int fds[2];
+      if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) != 0)
+	{
+	  self->print ("could not create socketpair\n");
+	  return 0;
+	}
+
+      int stderr_fds[2];
+      if (pipe (stderr_fds) != 0)
+	{
+	  self->print ("could not create pipe\n");
+	  close (fds[0]);
+	  close (fds[1]);
+	  return 0;
+	}
+
+      self->args.push_back (std::string ("-fplugin=") + self->plugin_name);
+      self->args.push_back (std::string ("-fplugin-arg-") + self->plugin_name
+			    + "-fd=" + std::to_string (fds[1]));
+
+      self->args.push_back (self->source_file);
+      self->args.push_back ("-c");
+      self->args.push_back ("-o");
+      self->args.push_back (filename);
+      if (self->verbose)
+	self->args.push_back ("-v");
+
+      self->set_connection (fds[0], stderr_fds[0]);
+
+      self->add_callbacks ();
+
+      char **argv = new (std::nothrow) char *[self->args.size () + 1];
+      if (argv == NULL)
+	return 0;
+
+      for (unsigned int i = 0; i < self->args.size (); ++i)
+	argv[i] = const_cast<char *> (self->args[i].c_str ());
+      argv[self->args.size ()] = NULL;
+
+      return self->fork_exec (argv, fds, stderr_fds);
+    }
+
+    static int
+    do_compile_v0 (struct gcc_base_context *s, const char *filename,
+		   int verbose)
+    {
+      do_set_verbose (s, verbose);
+      return do_compile (s, filename);
+    }
+
+    static void
+    do_destroy (struct gcc_base_context *s)
+    {
+      base_gdb_plugin<T> *self = get_self (s);
+
+      delete self;
+    }
   };
 
   // Instances of this rpc<> template function are installed into the
diff --git a/libcc1/libcc1.cc b/libcc1/libcc1.cc
index b9f1eb343aaf..cbc54ee0a044 100644
--- a/libcc1/libcc1.cc
+++ b/libcc1/libcc1.cc
@@ -42,15 +42,19 @@  along with GCC; see the file COPYING3.  If not see
 // The C compiler context that we hand back to our caller.
 struct libcc1 : public cc1_plugin::base_gdb_plugin<gcc_c_context>
 {
-  libcc1 (const gcc_base_vtable *, const gcc_c_fe_vtable *);
+  explicit libcc1 (const gcc_c_fe_vtable *);
+
+  void add_callbacks () override;
 
   gcc_c_oracle_function *binding_oracle = nullptr;
   gcc_c_symbol_address_function *address_oracle = nullptr;
   void *oracle_datum = nullptr;
 };
 
-libcc1::libcc1 (const gcc_base_vtable *v, const gcc_c_fe_vtable *cv)
-  : cc1_plugin::base_gdb_plugin<gcc_c_context> (v)
+libcc1::libcc1 (const gcc_c_fe_vtable *cv)
+  : cc1_plugin::base_gdb_plugin<gcc_c_context> ("libcc1plugin",
+						C_COMPILER_NAME,
+						GCC_C_FE_VERSION_1)
 {
   c_ops = cv;
 }
@@ -135,244 +139,22 @@  static const struct gcc_c_fe_vtable c_vtable =
 
 
 
-static void
-libcc1_set_verbose (struct gcc_base_context *s, int /* bool */ verbose)
-{
-  libcc1 *self = (libcc1 *) s;
-
-  self->set_verbose (verbose != 0);
-}
-
-static char *
-libcc1_set_arguments (struct gcc_base_context *s,
-		      int argc, char **argv)
-{
-  libcc1 *self = (libcc1 *) s;
-
-  std::string compiler;
-  char *errmsg = self->compilerp->find (C_COMPILER_NAME, compiler);
-  if (errmsg != NULL)
-    return errmsg;
-
-  self->args.push_back (compiler);
-
-  for (int i = 0; i < argc; ++i)
-    self->args.push_back (argv[i]);
-
-  return NULL;
-}
-
-static char *
-libcc1_set_triplet_regexp (struct gcc_base_context *s,
-			   const char *triplet_regexp)
-{
-  libcc1 *self = (libcc1 *) s;
-
-  self->compilerp.reset
-    (new cc1_plugin::compiler_triplet_regexp (self->verbose,
-					      triplet_regexp));
-  return NULL;
-}
-
-static char *
-libcc1_set_driver_filename (struct gcc_base_context *s,
-			    const char *driver_filename)
-{
-  libcc1 *self = (libcc1 *) s;
-
-  self->compilerp.reset
-    (new cc1_plugin::compiler_driver_filename (self->verbose,
-					       driver_filename));
-  return NULL;
-}
-
-static char *
-libcc1_set_arguments_v0 (struct gcc_base_context *s,
-			 const char *triplet_regexp,
-			 int argc, char **argv)
+void
+libcc1::add_callbacks ()
 {
-  char *errmsg = libcc1_set_triplet_regexp (s, triplet_regexp);
-  if (errmsg != NULL)
-    return errmsg;
-
-  return libcc1_set_arguments (s, argc, argv);
-}
-
-static void
-libcc1_set_source_file (struct gcc_base_context *s,
-			const char *file)
-{
-  libcc1 *self = (libcc1 *) s;
-
-  self->source_file = file;
-}
-
-static void
-libcc1_set_print_callback (struct gcc_base_context *s,
-			   void (*print_function) (void *datum,
-						   const char *message),
-			   void *datum)
-{
-  libcc1 *self = (libcc1 *) s;
-
-  self->print_function = print_function;
-  self->print_datum = datum;
-}
-
-static int
-fork_exec (libcc1 *self, char **argv, int spair_fds[2], int stderr_fds[2])
-{
-  pid_t child_pid = fork ();
-
-  if (child_pid == -1)
-    {
-      close (spair_fds[0]);
-      close (spair_fds[1]);
-      close (stderr_fds[0]);
-      close (stderr_fds[1]);
-      return 0;
-    }
-
-  if (child_pid == 0)
-    {
-      // Child.
-      dup2 (stderr_fds[1], 1);
-      dup2 (stderr_fds[1], 2);
-      close (stderr_fds[0]);
-      close (stderr_fds[1]);
-      close (spair_fds[0]);
-
-      execvp (argv[0], argv);
-      _exit (127);
-    }
-  else
-    {
-      // Parent.
-      close (spair_fds[1]);
-      close (stderr_fds[1]);
-
-      cc1_plugin::status result = cc1_plugin::FAIL;
-      if (self->connection->send ('H')
-	  && ::cc1_plugin::marshall (self->connection.get (),
-				     GCC_C_FE_VERSION_1))
-	result = self->connection->wait_for_query ();
-
-      close (spair_fds[0]);
-      close (stderr_fds[0]);
-
-      while (true)
-	{
-	  int status;
-
-	  if (waitpid (child_pid, &status, 0) == -1)
-	    {
-	      if (errno != EINTR)
-		return 0;
-	    }
-
-	  if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
-	    return 0;
-	  break;
-	}
-
-      if (!result)
-	return 0;
-      return 1;
-    }
-}
-
-static int
-libcc1_compile (struct gcc_base_context *s,
-		const char *filename)
-{
-  libcc1 *self = (libcc1 *) s;
-
-  int fds[2];
-  if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) != 0)
-    {
-      self->print ("could not create socketpair\n");
-      return 0;
-    }
-
-  int stderr_fds[2];
-  if (pipe (stderr_fds) != 0)
-    {
-      self->print ("could not create pipe\n");
-      close (fds[0]);
-      close (fds[1]);
-      return 0;
-    }
-
-  self->args.push_back ("-fplugin=libcc1plugin");
-  char buf[100];
-  if (snprintf (buf, sizeof (buf), "-fplugin-arg-libcc1plugin-fd=%d", fds[1])
-      >= (long) sizeof (buf))
-    abort ();
-  self->args.push_back (buf);
-
-  self->args.push_back (self->source_file);
-  self->args.push_back ("-c");
-  self->args.push_back ("-o");
-  self->args.push_back (filename);
-  if (self->verbose)
-    self->args.push_back ("-v");
-
-  self->set_connection (fds[0], stderr_fds[0]);
-
   cc1_plugin::callback_ftype *fun
     = cc1_plugin::callback<int,
 			   enum gcc_c_oracle_request,
 			   const char *,
 			   c_call_binding_oracle>;
-  self->connection->add_callback ("binding_oracle", fun);
+  connection->add_callback ("binding_oracle", fun);
 
   fun = cc1_plugin::callback<gcc_address,
 			     const char *,
 			     c_call_symbol_address>;
-  self->connection->add_callback ("address_oracle", fun);
-
-  char **argv = new (std::nothrow) char *[self->args.size () + 1];
-  if (argv == NULL)
-    return 0;
-
-  for (unsigned int i = 0; i < self->args.size (); ++i)
-    argv[i] = const_cast<char *> (self->args[i].c_str ());
-  argv[self->args.size ()] = NULL;
-
-  return fork_exec (self, argv, fds, stderr_fds);
-}
-
-static int
-libcc1_compile_v0 (struct gcc_base_context *s, const char *filename,
-		   int verbose)
-{
-  libcc1_set_verbose (s, verbose);
-  return libcc1_compile (s, filename);
+  connection->add_callback ("address_oracle", fun);
 }
 
-static void
-libcc1_destroy (struct gcc_base_context *s)
-{
-  libcc1 *self = (libcc1 *) s;
-
-  delete self;
-}
-
-static const struct gcc_base_vtable vtable =
-{
-  GCC_FE_VERSION_1,
-  libcc1_set_arguments_v0,
-  libcc1_set_source_file,
-  libcc1_set_print_callback,
-  libcc1_compile_v0,
-  libcc1_destroy,
-  libcc1_set_verbose,
-  libcc1_compile,
-  libcc1_set_arguments,
-  libcc1_set_triplet_regexp,
-  libcc1_set_driver_filename,
-};
-
 extern "C" gcc_c_fe_context_function gcc_c_fe_context;
 
 #ifdef __GNUC__
@@ -388,5 +170,5 @@  gcc_c_fe_context (enum gcc_base_api_version base_version,
       || (c_version != GCC_C_FE_VERSION_0 && c_version != GCC_C_FE_VERSION_1))
     return NULL;
 
-  return new libcc1 (&vtable, &c_vtable);
+  return new libcc1 (&c_vtable);
 }
diff --git a/libcc1/libcp1.cc b/libcc1/libcp1.cc
index 65e9770205c0..d22d9dc6af8c 100644
--- a/libcc1/libcp1.cc
+++ b/libcc1/libcp1.cc
@@ -41,7 +41,9 @@  along with GCC; see the file COPYING3.  If not see
 // The C compiler context that we hand back to our caller.
 struct libcp1 : public cc1_plugin::base_gdb_plugin<gcc_cp_context>
 {
-  libcp1 (const gcc_base_vtable *, const gcc_cp_fe_vtable *);
+  explicit libcp1 (const gcc_cp_fe_vtable *);
+
+  void add_callbacks () override;
 
   gcc_cp_oracle_function *binding_oracle = nullptr;
   gcc_cp_symbol_address_function *address_oracle = nullptr;
@@ -50,8 +52,10 @@  struct libcp1 : public cc1_plugin::base_gdb_plugin<gcc_cp_context>
   void *oracle_datum = nullptr;
 };
 
-libcp1::libcp1 (const gcc_base_vtable *v, const gcc_cp_fe_vtable *cv)
-  : cc1_plugin::base_gdb_plugin<gcc_cp_context> (v)
+libcp1::libcp1 (const gcc_cp_fe_vtable *cv)
+  : cc1_plugin::base_gdb_plugin<gcc_cp_context> ("libcp1plugin",
+						 CP_COMPILER_NAME,
+						 GCC_CP_FE_VERSION_0)
 {
   cp_ops = cv;
 }
@@ -158,252 +162,30 @@  static const struct gcc_cp_fe_vtable cp_vtable =
 
 
 
-static void
-libcp1_set_verbose (struct gcc_base_context *s, int /* bool */ verbose)
-{
-  libcp1 *self = (libcp1 *) s;
-
-  self->set_verbose (verbose != 0);
-}
-
-static char *
-libcp1_set_arguments (struct gcc_base_context *s,
-		      int argc, char **argv)
-{
-  libcp1 *self = (libcp1 *) s;
-
-  std::string compiler;
-  char *errmsg = self->compilerp->find (CP_COMPILER_NAME, compiler);
-  if (errmsg != NULL)
-    return errmsg;
-
-  self->args.push_back (compiler);
-
-  for (int i = 0; i < argc; ++i)
-    self->args.push_back (argv[i]);
-
-  return NULL;
-}
-
-static char *
-libcp1_set_triplet_regexp (struct gcc_base_context *s,
-			   const char *triplet_regexp)
-{
-  libcp1 *self = (libcp1 *) s;
-
-  self->compilerp.reset
-    (new cc1_plugin::compiler_triplet_regexp (self->verbose,
-					      triplet_regexp));
-  return NULL;
-}
-
-static char *
-libcp1_set_driver_filename (struct gcc_base_context *s,
-			    const char *driver_filename)
-{
-  libcp1 *self = (libcp1 *) s;
-
-  self->compilerp.reset
-    (new cc1_plugin::compiler_driver_filename (self->verbose,
-					       driver_filename));
-  return NULL;
-}
-
-static char *
-libcp1_set_arguments_v0 (struct gcc_base_context *s,
-			 const char *triplet_regexp,
-			 int argc, char **argv)
-{
-  char *errmsg = libcp1_set_triplet_regexp (s, triplet_regexp);
-  if (errmsg != NULL)
-    return errmsg;
-
-  return libcp1_set_arguments (s, argc, argv);
-}
-
-static void
-libcp1_set_source_file (struct gcc_base_context *s,
-			 const char *file)
-{
-  libcp1 *self = (libcp1 *) s;
-
-  self->source_file = file;
-}
-
-static void
-libcp1_set_print_callback (struct gcc_base_context *s,
-			    void (*print_function) (void *datum,
-						    const char *message),
-			    void *datum)
-{
-  libcp1 *self = (libcp1 *) s;
-
-  self->print_function = print_function;
-  self->print_datum = datum;
-}
-
-static int
-fork_exec (libcp1 *self, char **argv, int spair_fds[2], int stderr_fds[2])
-{
-  pid_t child_pid = fork ();
-
-  if (child_pid == -1)
-    {
-      close (spair_fds[0]);
-      close (spair_fds[1]);
-      close (stderr_fds[0]);
-      close (stderr_fds[1]);
-      return 0;
-    }
-
-  if (child_pid == 0)
-    {
-      // Child.
-      dup2 (stderr_fds[1], 1);
-      dup2 (stderr_fds[1], 2);
-      close (stderr_fds[0]);
-      close (stderr_fds[1]);
-      close (spair_fds[0]);
-
-      execvp (argv[0], argv);
-      _exit (127);
-    }
-  else
-    {
-      // Parent.
-      close (spair_fds[1]);
-      close (stderr_fds[1]);
-
-      cc1_plugin::status result = cc1_plugin::FAIL;
-      if (self->connection->send ('H')
-	  && ::cc1_plugin::marshall (self->connection.get (),
-				     GCC_CP_FE_VERSION_0))
-	result = self->connection->wait_for_query ();
-
-      close (spair_fds[0]);
-      close (stderr_fds[0]);
-
-      while (true)
-	{
-	  int status;
-
-	  if (waitpid (child_pid, &status, 0) == -1)
-	    {
-	      if (errno != EINTR)
-		return 0;
-	    }
-
-	  if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
-	    return 0;
-	  break;
-	}
-
-      if (!result)
-	return 0;
-      return 1;
-    }
-}
-
-static int
-libcp1_compile (struct gcc_base_context *s,
-		const char *filename)
+void
+libcp1::add_callbacks ()
 {
-  libcp1 *self = (libcp1 *) s;
-
-  int fds[2];
-  if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) != 0)
-    {
-      self->print ("could not create socketpair\n");
-      return 0;
-    }
-
-  int stderr_fds[2];
-  if (pipe (stderr_fds) != 0)
-    {
-      self->print ("could not create pipe\n");
-      close (fds[0]);
-      close (fds[1]);
-      return 0;
-    }
-
-  self->args.push_back ("-fplugin=libcp1plugin");
-  char buf[100];
-  if (snprintf (buf, sizeof (buf), "-fplugin-arg-libcp1plugin-fd=%d", fds[1])
-      >= (long) sizeof (buf))
-    abort ();
-  self->args.push_back (buf);
-
-  self->args.push_back (self->source_file);
-  self->args.push_back ("-c");
-  self->args.push_back ("-o");
-  self->args.push_back (filename);
-  if (self->verbose)
-    self->args.push_back ("-v");
-
-  self->set_connection (fds[0], stderr_fds[0]);
-
   cc1_plugin::callback_ftype *fun
     = cc1_plugin::callback<int,
 			   enum gcc_cp_oracle_request,
 			   const char *,
 			   cp_call_binding_oracle>;
-  self->connection->add_callback ("binding_oracle", fun);
+  connection->add_callback ("binding_oracle", fun);
 
   fun = cc1_plugin::callback<gcc_address,
 			     const char *,
 			     cp_call_symbol_address>;
-  self->connection->add_callback ("address_oracle", fun);
+  connection->add_callback ("address_oracle", fun);
 
   fun = cc1_plugin::callback<int,
 			     cp_call_enter_scope>;
-  self->connection->add_callback ("enter_scope", fun);
+  connection->add_callback ("enter_scope", fun);
 
   fun = cc1_plugin::callback<int,
 			     cp_call_leave_scope>;
-  self->connection->add_callback ("leave_scope", fun);
-
-  char **argv = new (std::nothrow) char *[self->args.size () + 1];
-  if (argv == NULL)
-    return 0;
-
-  for (unsigned int i = 0; i < self->args.size (); ++i)
-    argv[i] = const_cast<char *> (self->args[i].c_str ());
-  argv[self->args.size ()] = NULL;
-
-  return fork_exec (self, argv, fds, stderr_fds);
-}
-
-static int
-libcp1_compile_v0 (struct gcc_base_context *s, const char *filename,
-		   int verbose)
-{
-  libcp1_set_verbose (s, verbose);
-  return libcp1_compile (s, filename);
+  connection->add_callback ("leave_scope", fun);
 }
 
-static void
-libcp1_destroy (struct gcc_base_context *s)
-{
-  libcp1 *self = (libcp1 *) s;
-
-  delete self;
-}
-
-static const struct gcc_base_vtable vtable =
-{
-  GCC_FE_VERSION_1,
-  libcp1_set_arguments_v0,
-  libcp1_set_source_file,
-  libcp1_set_print_callback,
-  libcp1_compile_v0,
-  libcp1_destroy,
-  libcp1_set_verbose,
-  libcp1_compile,
-  libcp1_set_arguments,
-  libcp1_set_triplet_regexp,
-  libcp1_set_driver_filename,
-};
-
 extern "C" gcc_cp_fe_context_function gcc_cp_fe_context;
 
 #ifdef __GNUC__
@@ -419,5 +201,5 @@  gcc_cp_fe_context (enum gcc_base_api_version base_version,
       || cp_version != GCC_CP_FE_VERSION_0)
     return NULL;
 
-  return new libcp1 (&vtable, &cp_vtable);
+  return new libcp1 (&cp_vtable);
 }