[gnome-builder] meson: port meson plugin to C



commit 0859430ed62982d83eea86321316a49af5b7275e
Author: Christian Hergert <chergert redhat com>
Date:   Tue Oct 17 14:54:21 2017 -0700

    meson: port meson plugin to C
    
    This code is increasingly critical to Builder so I want to ensure that it
    is both in a statically typed language and properly implemenst the various
    async APIs we expect for interactivity.
    
    This also switches to using IdeCompileCommands to access the build args
    without having to advance the build pipeline. Doing so allows us to
    potentially avoid running the build machinery immediately upon reopening
    a given project. (Something that the Build Pipeline does not handle well
    on it's own, and users have been grumpy about).

 src/plugins/meson/gbp-meson-build-system.c   |  769 ++++++++++++++++++++++++++
 src/plugins/meson/gbp-meson-build-system.h   |   29 +
 src/plugins/meson/gbp-meson-build-target.c   |   95 ++++
 src/plugins/meson/gbp-meson-build-target.h   |   32 ++
 src/plugins/meson/gbp-meson-pipeline-addin.c |  200 +++++++
 src/plugins/meson/gbp-meson-pipeline-addin.h |   29 +
 src/plugins/meson/meson-plugin.c             |   30 +
 src/plugins/meson/meson.build                |   27 +-
 src/plugins/meson/meson.gresource.xml        |    6 +
 src/plugins/meson/meson.plugin               |    4 +-
 10 files changed, 1210 insertions(+), 11 deletions(-)
---
diff --git a/src/plugins/meson/gbp-meson-build-system.c b/src/plugins/meson/gbp-meson-build-system.c
new file mode 100644
index 0000000..4db6e27
--- /dev/null
+++ b/src/plugins/meson/gbp-meson-build-system.c
@@ -0,0 +1,769 @@
+/* gbp-meson-build-system.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gbp-meson-build-system"
+
+#include <glib/gi18n.h>
+#include <json-glib/json-glib.h>
+
+#include "gbp-meson-build-system.h"
+#include "gbp-meson-build-target.h"
+
+struct _GbpMesonBuildSystem
+{
+  IdeObject           parent_instance;
+  GFile              *project_file;
+  IdeCompileCommands *compile_commands;
+};
+
+static void async_initable_iface_init (GAsyncInitableIface     *iface);
+static void build_system_iface_init   (IdeBuildSystemInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GbpMesonBuildSystem, gbp_meson_build_system, IDE_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_BUILD_SYSTEM, build_system_iface_init))
+
+enum {
+  PROP_0,
+  PROP_PROJECT_FILE,
+  N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+gbp_meson_build_system_ensure_config_cb (GObject      *object,
+                                         GAsyncResult *result,
+                                         gpointer      user_data)
+{
+  IdeBuildManager *build_manager = (IdeBuildManager *)object;
+  g_autoptr(GTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  if (!ide_build_manager_execute_finish (build_manager, result, &error))
+    g_task_return_error (task, g_steal_pointer (&error));
+  else
+    g_task_return_boolean (task, TRUE);
+}
+
+static void
+gbp_meson_build_system_ensure_config_async (GbpMesonBuildSystem *self,
+                                            GCancellable        *cancellable,
+                                            GAsyncReadyCallback  callback,
+                                            gpointer             user_data)
+{
+  g_autoptr(GTask) task = NULL;
+  IdeBuildManager *build_manager;
+  IdeContext *context;
+
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, gbp_meson_build_system_ensure_config_async);
+  g_task_set_priority (task, G_PRIORITY_LOW);
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  build_manager = ide_context_get_build_manager (context);
+
+  ide_build_manager_execute_async (build_manager,
+                                   IDE_BUILD_PHASE_CONFIGURE,
+                                   cancellable,
+                                   gbp_meson_build_system_ensure_config_cb,
+                                   g_steal_pointer (&task));
+}
+
+static gboolean
+gbp_meson_build_system_ensure_config_finish (GbpMesonBuildSystem  *self,
+                                             GAsyncResult         *result,
+                                             GError              **error)
+{
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (self));
+  g_assert (G_IS_TASK (result));
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+gbp_meson_build_system_load_commands_load_cb (GObject      *object,
+                                              GAsyncResult *result,
+                                              gpointer      user_data)
+{
+  IdeCompileCommands *compile_commands = (IdeCompileCommands *)object;
+  GbpMesonBuildSystem *self;
+  g_autoptr(GTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (IDE_IS_COMPILE_COMMANDS (compile_commands));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  self = g_task_get_source_object (task);
+
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (self));
+
+  if (!ide_compile_commands_load_finish (compile_commands, result, &error))
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
+
+  g_set_object (&self->compile_commands, compile_commands);
+  g_task_return_pointer (task, g_object_ref (compile_commands), g_object_unref);
+}
+
+static void
+gbp_meson_build_system_load_commands_config_cb (GObject      *object,
+                                                GAsyncResult *result,
+                                                gpointer      user_data)
+{
+  GbpMesonBuildSystem *self = (GbpMesonBuildSystem *)object;
+  g_autoptr(IdeCompileCommands) compile_commands = NULL;
+  g_autoptr(GTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+  g_autoptr(GFile) file = NULL;
+  g_autofree gchar *path = NULL;
+  IdeBuildManager *build_manager;
+  IdeBuildPipeline *pipeline;
+  GCancellable *cancellable;
+  IdeContext *context;
+
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (self));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  if (!gbp_meson_build_system_ensure_config_finish (self, result, &error))
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  build_manager = ide_context_get_build_manager (context);
+  pipeline = ide_build_manager_get_pipeline (build_manager);
+
+  if (pipeline == NULL)
+    {
+      /* Unlikely, but possible */
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_FAILED,
+                               "No build pipeline is available");
+      return;
+    }
+
+  path = ide_build_pipeline_build_builddir_path (pipeline, "compile_commands.json", NULL);
+
+  if (!g_file_test (path, G_FILE_TEST_IS_REGULAR))
+    {
+      /* Unlikely, but possible */
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_NOT_FOUND,
+                               "Failed to locate compile_commands.json");
+      return;
+    }
+
+  compile_commands = ide_compile_commands_new ();
+  file = g_file_new_for_path (path);
+  cancellable = g_task_get_cancellable (task);
+
+  ide_compile_commands_load_async (compile_commands,
+                                   file,
+                                   cancellable,
+                                   gbp_meson_build_system_load_commands_load_cb,
+                                   g_steal_pointer (&task));
+}
+
+static void
+gbp_meson_build_system_load_commands_async (GbpMesonBuildSystem *self,
+                                            GCancellable        *cancellable,
+                                            GAsyncReadyCallback  callback,
+                                            gpointer             user_data)
+{
+  g_autoptr(GTask) task = NULL;
+  IdeBuildManager *build_manager;
+  IdeBuildPipeline *pipeline;
+  IdeContext *context;
+
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, gbp_meson_build_system_load_commands_async);
+  g_task_set_priority (task, G_PRIORITY_LOW);
+
+  /*
+   * If we've already load the compile commands database, use it and
+   * short circuit as early as we can to avoid progressing the build
+   * pipeline unnecessarily.
+   */
+
+  if (self->compile_commands != NULL)
+    {
+      g_task_return_pointer (task,
+                             g_object_ref (self->compile_commands),
+                             g_object_unref);
+      return;
+    }
+
+  /*
+   * If the build pipeline has been previously configured, we might
+   * already have a "compile_commands.json" file in the build directory
+   * that we can reuse.
+   */
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  build_manager = ide_context_get_build_manager (context);
+  pipeline = ide_build_manager_get_pipeline (build_manager);
+
+  if (pipeline != NULL)
+    {
+      g_autofree gchar *path = NULL;
+
+      path = ide_build_pipeline_build_builddir_path (pipeline, "compile_commands.json", NULL);
+
+      if (g_file_test (path, G_FILE_TEST_IS_REGULAR))
+        {
+          g_autoptr(IdeCompileCommands) compile_commands = NULL;
+          g_autoptr(GFile) file = NULL;
+
+          compile_commands = ide_compile_commands_new ();
+          file = g_file_new_for_path (path);
+
+          ide_compile_commands_load_async (compile_commands,
+                                           file,
+                                           cancellable,
+                                           gbp_meson_build_system_load_commands_load_cb,
+                                           g_steal_pointer (&task));
+          return;
+        }
+    }
+
+  /*
+   * It looks like we need to ensure the build pipeline advances to the the
+   * CONFIGURE phase so that meson has generated a new compile_commands.json
+   * that we can load.
+   */
+
+  gbp_meson_build_system_ensure_config_async (self,
+                                              cancellable,
+                                              gbp_meson_build_system_load_commands_config_cb,
+                                              g_steal_pointer (&task));
+}
+
+static IdeCompileCommands *
+gbp_meson_build_system_load_commands_finish (GbpMesonBuildSystem  *self,
+                                             GAsyncResult         *result,
+                                             GError              **error)
+{
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (self));
+  g_assert (G_IS_TASK (result));
+
+  return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+static void
+gbp_meson_build_system_finalize (GObject *object)
+{
+  GbpMesonBuildSystem *self = (GbpMesonBuildSystem *)object;
+
+  g_clear_object (&self->project_file);
+
+  G_OBJECT_CLASS (gbp_meson_build_system_parent_class)->finalize (object);
+}
+
+static void
+gbp_meson_build_system_get_property (GObject    *object,
+                                     guint       prop_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
+{
+  GbpMesonBuildSystem *self = GBP_MESON_BUILD_SYSTEM (object);
+
+  switch (prop_id)
+    {
+    case PROP_PROJECT_FILE:
+      g_value_set_object (value, self->project_file);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_meson_build_system_set_property (GObject      *object,
+                                     guint         prop_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
+{
+  GbpMesonBuildSystem *self = GBP_MESON_BUILD_SYSTEM (object);
+
+  switch (prop_id)
+    {
+    case PROP_PROJECT_FILE:
+      self->project_file = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_meson_build_system_class_init (GbpMesonBuildSystemClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gbp_meson_build_system_finalize;
+  object_class->get_property = gbp_meson_build_system_get_property;
+  object_class->set_property = gbp_meson_build_system_set_property;
+
+  properties [PROP_PROJECT_FILE] =
+    g_param_spec_object ("project-file",
+                         "Project File",
+                         "The primary meson.build for the project",
+                         G_TYPE_FILE,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gbp_meson_build_system_init (GbpMesonBuildSystem *self)
+{
+}
+
+static gchar *
+gbp_meson_build_system_get_id (IdeBuildSystem *build_system)
+{
+  return g_strdup ("meson");
+}
+
+static gchar *
+gbp_meson_build_system_get_display_name (IdeBuildSystem *build_system)
+{
+  return g_strdup (_("Meson"));
+}
+
+static gint
+gbp_meson_build_system_get_priority (IdeBuildSystem *build_system)
+{
+  return 100;
+}
+
+static void
+gbp_meson_build_system_get_build_flags_cb (GObject      *object,
+                                           GAsyncResult *result,
+                                           gpointer      user_data)
+{
+  GbpMesonBuildSystem *self = (GbpMesonBuildSystem *)object;
+  g_autoptr(IdeCompileCommands) compile_commands = NULL;
+  g_autoptr(GTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+  g_autoptr(GFile) directory = NULL;
+  g_auto(GStrv) ret = NULL;
+  GFile *file;
+
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (self));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  compile_commands = gbp_meson_build_system_load_commands_finish (self, result, &error);
+
+  if (compile_commands == NULL)
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
+
+  file = g_task_get_task_data (task);
+
+  g_assert (G_IS_FILE (file));
+
+  ret = ide_compile_commands_lookup (compile_commands, file, &directory, &error);
+
+  if (ret == NULL)
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
+
+  g_task_return_pointer (task, g_steal_pointer (&ret), (GDestroyNotify)g_strfreev);
+}
+
+static void
+gbp_meson_build_system_get_build_flags_async (IdeBuildSystem      *build_system,
+                                              IdeFile             *file,
+                                              GCancellable        *cancellable,
+                                              GAsyncReadyCallback  callback,
+                                              gpointer             user_data)
+{
+  GbpMesonBuildSystem *self = (GbpMesonBuildSystem *)build_system;
+  g_autoptr(GTask) task = NULL;
+  GFile *gfile;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (self));
+  g_assert (IDE_IS_FILE (file));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  gfile = ide_file_get_file (file);
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_priority (task, G_PRIORITY_LOW);
+  g_task_set_source_tag (task, gbp_meson_build_system_get_build_flags_async);
+  g_task_set_task_data (task, g_object_ref (gfile), g_object_unref);
+
+  gbp_meson_build_system_load_commands_async (self,
+                                              cancellable,
+                                              gbp_meson_build_system_get_build_flags_cb,
+                                              g_steal_pointer (&task));
+
+  IDE_EXIT;
+}
+
+static gchar **
+gbp_meson_build_system_get_build_flags_finish (IdeBuildSystem  *build_system,
+                                               GAsyncResult    *result,
+                                               GError         **error)
+{
+  GbpMesonBuildSystem *self = (GbpMesonBuildSystem *)build_system;
+  gchar **ret;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (self));
+  g_assert (G_IS_TASK (result));
+
+  ret = g_task_propagate_pointer (G_TASK (result), error);
+
+  IDE_RETURN (ret);
+}
+
+static void
+gbp_meson_build_system_get_build_targets_communciate_cb (GObject      *object,
+                                                         GAsyncResult *result,
+                                                         gpointer      user_data)
+{
+  IdeSubprocess *subprocess = (IdeSubprocess *)object;
+  g_autoptr(GTask) task = user_data;
+  g_autoptr(JsonParser) parser = NULL;
+  g_autoptr(GError) error = NULL;
+  g_autofree gchar *stdout_buf = NULL;
+  g_autoptr(GPtrArray) ret = NULL;
+  JsonArray *array;
+  JsonNode *root;
+  guint len;
+
+  g_assert (IDE_IS_SUBPROCESS (subprocess));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  if (!ide_subprocess_communicate_utf8_finish (subprocess, result, &stdout_buf, NULL, &error))
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
+
+  /*
+   * The output from meson introspect --targets is a JSON formatted array
+   * of objects containing target information.
+   */
+
+  parser = json_parser_new ();
+
+  if (!json_parser_load_from_data (parser, stdout_buf, -1, &error))
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
+
+  if (NULL == (root = json_parser_get_root (parser)) ||
+      !JSON_NODE_HOLDS_ARRAY (root) ||
+      NULL == (array = json_node_get_array (root)))
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_INVALID_DATA,
+                               "Invalid JSON received from meson introspect");
+      return;
+    }
+
+  len = json_array_get_length (array);
+  ret = g_ptr_array_new_with_free_func (g_object_unref);
+
+  for (guint i = 0; i < len; i++)
+    {
+      JsonNode *element = json_array_get_element (array, i);
+      const gchar *name;
+      const gchar *filename;
+      JsonObject *obj;
+      JsonNode *member;
+
+      if (JSON_NODE_HOLDS_OBJECT (element) &&
+          NULL != (obj = json_node_get_object (element)) &&
+          NULL != (member = json_object_get_member (obj, "name")) &&
+          JSON_NODE_HOLDS_VALUE (member) &&
+          NULL != (name = json_node_get_string (member)) &&
+          NULL != (member = json_object_get_member (obj, "install_filename")) &&
+          JSON_NODE_HOLDS_VALUE (member) &&
+          NULL != (filename = json_node_get_string (member)))
+        {
+          g_autofree gchar *install_dir = NULL;
+          g_autofree gchar *base = NULL;
+          g_autofree gchar *name_of_dir = NULL;
+          g_autoptr(GFile) dir = NULL;
+
+          install_dir = g_path_get_dirname (filename);
+          name_of_dir = g_path_get_basename (install_dir);
+
+          /* ignore things not in bin */
+          if (!ide_str_equal0 (name_of_dir, "bin"))
+            continue;
+
+          g_debug ("Found target %s", name);
+
+          base = g_path_get_basename (filename);
+          dir = g_file_new_for_path (install_dir);
+
+          g_ptr_array_add (ret, gbp_meson_build_target_new (dir, base));
+        }
+    }
+
+  g_task_return_pointer (task, g_steal_pointer (&ret), (GDestroyNotify)g_ptr_array_unref);
+}
+
+static void
+gbp_meson_build_system_get_build_targets_ensure_cb (GObject      *object,
+                                                    GAsyncResult *result,
+                                                    gpointer      user_data)
+{
+  GbpMesonBuildSystem *self = (GbpMesonBuildSystem *)object;
+  g_autoptr(IdeSubprocessLauncher) launcher = NULL;
+  g_autoptr(IdeSubprocess) subprocess = NULL;
+  g_autoptr(GTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+  IdeBuildPipeline *pipeline;
+  IdeBuildManager *build_manager;
+  GCancellable *cancellable;
+  IdeContext *context;
+
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (self));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  if (!gbp_meson_build_system_ensure_config_finish (self, result, &error))
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
+
+  cancellable = g_task_get_cancellable (task);
+  context = ide_object_get_context (IDE_OBJECT (self));
+  build_manager = ide_context_get_build_manager (context);
+  pipeline = ide_build_manager_get_pipeline (build_manager);
+
+  if (pipeline == NULL)
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_FAILED,
+                               "Build pipeline is not ready, cannot extract targets");
+      return;
+    }
+
+  if (NULL == (launcher = ide_build_pipeline_create_launcher (pipeline, &error)))
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
+
+  ide_subprocess_launcher_push_argv (launcher, "meson");
+  ide_subprocess_launcher_push_argv (launcher, "introspect");
+  ide_subprocess_launcher_push_argv (launcher, "--targets");
+
+  if (NULL == (subprocess = ide_subprocess_launcher_spawn (launcher, cancellable, &error)))
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
+
+  ide_subprocess_communicate_utf8_async (subprocess,
+                                         NULL,
+                                         cancellable,
+                                         gbp_meson_build_system_get_build_targets_communciate_cb,
+                                         g_steal_pointer (&task));
+}
+
+static void
+gbp_meson_build_system_get_build_targets_async (IdeBuildSystem      *build_system,
+                                                GCancellable        *cancellable,
+                                                GAsyncReadyCallback  callback,
+                                                gpointer             user_data)
+{
+  GbpMesonBuildSystem *self = (GbpMesonBuildSystem *)build_system;
+  g_autoptr(GTask) task = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_priority (task, G_PRIORITY_LOW);
+  g_task_set_source_tag (task, gbp_meson_build_system_get_build_targets_async);
+
+  gbp_meson_build_system_ensure_config_async (self,
+                                              cancellable,
+                                              gbp_meson_build_system_get_build_targets_ensure_cb,
+                                              g_steal_pointer (&task));
+
+  IDE_EXIT;
+}
+
+static GPtrArray *
+gbp_meson_build_system_get_build_targets_finish (IdeBuildSystem  *build_system,
+                                                 GAsyncResult    *result,
+                                                 GError         **error)
+{
+  GbpMesonBuildSystem *self = (GbpMesonBuildSystem *)build_system;
+  GPtrArray *ret;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (self));
+  g_assert (G_IS_TASK (result));
+
+  ret = g_task_propagate_pointer (G_TASK (result), error);
+
+  IDE_RETURN (ret);
+}
+
+static void
+build_system_iface_init (IdeBuildSystemInterface *iface)
+{
+  iface->get_id = gbp_meson_build_system_get_id;
+  iface->get_display_name = gbp_meson_build_system_get_display_name;
+  iface->get_priority = gbp_meson_build_system_get_priority;
+  iface->get_build_flags_async = gbp_meson_build_system_get_build_flags_async;
+  iface->get_build_flags_finish = gbp_meson_build_system_get_build_flags_finish;
+  iface->get_build_targets_async = gbp_meson_build_system_get_build_targets_async;
+  iface->get_build_targets_finish = gbp_meson_build_system_get_build_targets_finish;
+}
+
+static void
+gbp_meson_build_system_init_worker (GTask        *task,
+                                    gpointer      source_object,
+                                    gpointer      task_data,
+                                    GCancellable *cancellable)
+{
+  GFile *project_file = task_data;
+  g_autofree gchar *name = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (source_object));
+  g_assert (G_IS_FILE (project_file));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  name = g_file_get_basename (project_file);
+
+  if (ide_str_equal0 (name, "meson.build"))
+    {
+      g_task_return_pointer (task, g_object_ref (project_file), g_object_unref);
+      IDE_EXIT;
+    }
+
+  if (g_file_query_file_type (project_file, 0, cancellable) == G_FILE_TYPE_DIRECTORY)
+    {
+      g_autoptr(GFile) meson_build = g_file_get_child (project_file, "meson.build");
+
+      if (g_file_query_exists (meson_build, cancellable))
+        {
+          g_task_return_pointer (task, g_object_ref (meson_build), g_object_unref);
+          IDE_EXIT;
+        }
+    }
+
+  g_task_return_new_error (task,
+                           G_IO_ERROR,
+                           G_IO_ERROR_NOT_SUPPORTED,
+                           "%s is not supported by the meson plugin",
+                           name);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_meson_build_system_init_async (GAsyncInitable      *initable,
+                                   gint                 io_priority,
+                                   GCancellable        *cancellable,
+                                   GAsyncReadyCallback  callback,
+                                   gpointer             user_data)
+{
+  GbpMesonBuildSystem *self = (GbpMesonBuildSystem *)initable;
+  g_autoptr(GTask) task = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (self));
+  g_assert (G_IS_FILE (self->project_file));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, gbp_meson_build_system_init_async);
+  g_task_set_priority (task, io_priority);
+  g_task_set_task_data (task, g_object_ref (self->project_file), g_object_unref);
+  g_task_run_in_thread (task, gbp_meson_build_system_init_worker);
+
+  IDE_EXIT;
+}
+
+static gboolean
+gbp_meson_build_system_init_finish (GAsyncInitable  *initable,
+                                    GAsyncResult    *result,
+                                    GError         **error)
+{
+  GbpMesonBuildSystem *self = (GbpMesonBuildSystem *)initable;
+  g_autoptr(GFile) project_file = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_MESON_BUILD_SYSTEM (self));
+  g_assert (G_IS_TASK (result));
+
+  project_file = g_task_propagate_pointer (G_TASK (result), error);
+  if (g_set_object (&self->project_file, project_file))
+    g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PROJECT_FILE]);
+
+  IDE_RETURN (project_file != NULL);
+}
+
+static void
+async_initable_iface_init (GAsyncInitableIface *iface)
+{
+  iface->init_async = gbp_meson_build_system_init_async;
+  iface->init_finish = gbp_meson_build_system_init_finish;
+}
diff --git a/src/plugins/meson/gbp-meson-build-system.h b/src/plugins/meson/gbp-meson-build-system.h
new file mode 100644
index 0000000..b07d81a
--- /dev/null
+++ b/src/plugins/meson/gbp-meson-build-system.h
@@ -0,0 +1,29 @@
+/* gbp-meson-build-system.h
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_MESON_BUILD_SYSTEM (gbp_meson_build_system_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpMesonBuildSystem, gbp_meson_build_system, GBP, MESON_BUILD_SYSTEM, IdeObject)
+
+G_END_DECLS
diff --git a/src/plugins/meson/gbp-meson-build-target.c b/src/plugins/meson/gbp-meson-build-target.c
new file mode 100644
index 0000000..b88968d
--- /dev/null
+++ b/src/plugins/meson/gbp-meson-build-target.c
@@ -0,0 +1,95 @@
+/* gbp-meson-build-target.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gbp-meson-build-target"
+
+#include "gbp-meson-build-target.h"
+
+struct _GbpMesonBuildTarget
+{
+  IdeObject parent_instance;
+
+  GFile *install_directory;
+  gchar *name;
+};
+
+static GFile *
+gbp_meson_build_target_get_install_directory (IdeBuildTarget *build_target)
+{
+  GbpMesonBuildTarget *self = (GbpMesonBuildTarget *)build_target;
+
+  g_assert (GBP_IS_MESON_BUILD_TARGET (self));
+
+  return self->install_directory ? g_object_ref (self->install_directory) : NULL;
+}
+
+static gchar *
+gbp_meson_build_target_get_name (IdeBuildTarget *build_target)
+{
+  GbpMesonBuildTarget *self = (GbpMesonBuildTarget *)build_target;
+
+  g_assert (GBP_IS_MESON_BUILD_TARGET (self));
+
+  return self->name ? g_strdup (self->name) : NULL;
+}
+
+static void
+build_target_iface_init (IdeBuildTargetInterface *iface)
+{
+  iface->get_install_directory = gbp_meson_build_target_get_install_directory;
+  iface->get_name = gbp_meson_build_target_get_name;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpMesonBuildTarget, gbp_meson_build_target, IDE_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_BUILD_TARGET, build_target_iface_init))
+
+static void
+gbp_meson_build_target_finalize (GObject *object)
+{
+  GbpMesonBuildTarget *self = (GbpMesonBuildTarget *)object;
+
+  g_clear_object (&self->install_directory);
+  g_clear_pointer (&self->name, g_free);
+
+  G_OBJECT_CLASS (gbp_meson_build_target_parent_class)->finalize (object);
+}
+
+static void
+gbp_meson_build_target_class_init (GbpMesonBuildTargetClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gbp_meson_build_target_finalize;
+}
+
+static void
+gbp_meson_build_target_init (GbpMesonBuildTarget *self)
+{
+}
+
+IdeBuildTarget *
+gbp_meson_build_target_new (GFile *install_directory,
+                            gchar *name)
+{
+  GbpMesonBuildTarget *self = g_object_new (GBP_TYPE_MESON_BUILD_TARGET, NULL);
+
+  g_set_object (&self->install_directory, install_directory);
+  self->name = g_strdup (name);
+
+  return IDE_BUILD_TARGET (self);
+}
diff --git a/src/plugins/meson/gbp-meson-build-target.h b/src/plugins/meson/gbp-meson-build-target.h
new file mode 100644
index 0000000..4fc4668
--- /dev/null
+++ b/src/plugins/meson/gbp-meson-build-target.h
@@ -0,0 +1,32 @@
+/* gbp-meson-build-target.h
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_MESON_BUILD_TARGET (gbp_meson_build_target_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpMesonBuildTarget, gbp_meson_build_target, GBP, MESON_BUILD_TARGET, IdeObject)
+
+IdeBuildTarget *gbp_meson_build_target_new (GFile *install_directory,
+                                            gchar *name);
+
+G_END_DECLS
diff --git a/src/plugins/meson/gbp-meson-pipeline-addin.c b/src/plugins/meson/gbp-meson-pipeline-addin.c
new file mode 100644
index 0000000..d1f748b
--- /dev/null
+++ b/src/plugins/meson/gbp-meson-pipeline-addin.c
@@ -0,0 +1,200 @@
+/* gbp-meson-pipeline-addin.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gbp-meson-pipeline-addin"
+
+#include "gbp-meson-build-system.h"
+#include "gbp-meson-pipeline-addin.h"
+
+struct _GbpMesonPipelineAddin
+{
+  IdeObject parent_instance;
+};
+
+static const gchar *ninja_names[] = { "ninja-build", "ninja" };
+
+static void
+on_stage_query (IdeBuildStage    *stage,
+                IdeBuildPipeline *pipeline,
+                GCancellable     *cancellable)
+{
+  g_assert (IDE_IS_BUILD_STAGE (stage));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  /* Defer to ninja to determine completed status */
+  ide_build_stage_set_completed (stage, FALSE);
+}
+
+static void
+gbp_meson_pipeline_addin_load (IdeBuildPipelineAddin *addin,
+                               IdeBuildPipeline      *pipeline)
+{
+  GbpMesonPipelineAddin *self = (GbpMesonPipelineAddin *)addin;
+  g_autoptr(IdeSubprocessLauncher) config_launcher = NULL;
+  g_autoptr(IdeSubprocessLauncher) build_launcher = NULL;
+  g_autoptr(IdeSubprocessLauncher) clean_launcher = NULL;
+  g_autoptr(IdeSubprocessLauncher) install_launcher = NULL;
+  g_autoptr(IdeBuildStage) build_stage = NULL;
+  g_autoptr(IdeBuildStage) config_stage = NULL;
+  g_autoptr(IdeBuildStage) install_stage = NULL;
+  g_autoptr(GError) error = NULL;
+  g_autofree gchar *build_ninja = NULL;
+  IdeBuildSystem *build_system;
+  IdeConfiguration *config;
+  IdeContext *context;
+  IdeRuntime *runtime;
+  const gchar *config_opts;
+  const gchar *ninja = NULL;
+  const gchar *prefix;
+  const gchar *srcdir;
+  guint id;
+  gint parallel;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_MESON_PIPELINE_ADDIN (self));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+
+  build_system = ide_context_get_build_system (context);
+  if (!GBP_IS_MESON_BUILD_SYSTEM (build_system))
+    IDE_GOTO (failure);
+
+  config = ide_build_pipeline_get_configuration (pipeline);
+  runtime = ide_build_pipeline_get_runtime (pipeline);
+  srcdir = ide_build_pipeline_get_srcdir (pipeline);
+
+  g_assert (IDE_IS_CONFIGURATION (config));
+  g_assert (IDE_IS_RUNTIME (runtime));
+  g_assert (srcdir != NULL);
+
+  for (guint i = 0; i < G_N_ELEMENTS (ninja_names); i++)
+    {
+      if (ide_runtime_contains_program_in_path (runtime, ninja_names[i], NULL))
+        {
+          ninja = ninja_names[i];
+          break;
+        }
+    }
+
+  if (ninja == NULL)
+    {
+      g_debug ("Failed to locate ninja. Meson building is disabled.");
+      IDE_EXIT;
+    }
+
+  /* Create all our launchers up front */
+  if (NULL == (config_launcher = ide_build_pipeline_create_launcher (pipeline, &error)) ||
+      NULL == (build_launcher = ide_build_pipeline_create_launcher (pipeline, &error)) ||
+      NULL == (clean_launcher = ide_build_pipeline_create_launcher (pipeline, &error)) ||
+      NULL == (install_launcher = ide_build_pipeline_create_launcher (pipeline, &error)))
+    IDE_GOTO (failure);
+
+  prefix = ide_configuration_get_prefix (config);
+  config_opts = ide_configuration_get_config_opts (config);
+  parallel = ide_configuration_get_parallelism (config);
+
+  /* Setup our meson configure stage. */
+
+  ide_subprocess_launcher_push_argv (config_launcher, "meson");
+  ide_subprocess_launcher_push_argv (config_launcher, srcdir);
+  ide_subprocess_launcher_push_argv (config_launcher, ".");
+  ide_subprocess_launcher_push_argv (config_launcher, "--prefix");
+  ide_subprocess_launcher_push_argv (config_launcher, prefix);
+
+  if (config_opts != NULL)
+    {
+      g_auto(GStrv) argv = NULL;
+      gint argc;
+
+      if (!g_shell_parse_argv (config_opts, &argc, &argv, &error))
+        IDE_GOTO (failure);
+
+      ide_subprocess_launcher_push_args (config_launcher, (const gchar * const *)argv);
+    }
+
+  config_stage = ide_build_stage_launcher_new (context, config_launcher);
+  build_ninja = ide_build_pipeline_build_builddir_path (pipeline, "build.ninja", NULL);
+  if (g_file_test (build_ninja, G_FILE_TEST_IS_REGULAR))
+    ide_build_stage_set_completed (config_stage, TRUE);
+
+  id = ide_build_pipeline_connect (pipeline, IDE_BUILD_PHASE_CONFIGURE, 0, config_stage);
+  ide_build_pipeline_addin_track (addin, id);
+
+  /*
+   * Register the build launcher which will perform the incremental
+   * build of the project when the IDE_BUILD_PHASE_BUILD phase is
+   * requested of the pipeline.
+   */
+  ide_subprocess_launcher_push_argv (build_launcher, ninja);
+  ide_subprocess_launcher_push_argv (clean_launcher, ninja);
+
+  if (parallel > 0)
+    {
+      g_autofree gchar *j = g_strdup_printf ("-j%u", parallel);
+
+      ide_subprocess_launcher_push_argv (build_launcher, j);
+      ide_subprocess_launcher_push_argv (clean_launcher, j);
+    }
+
+  ide_subprocess_launcher_push_argv (clean_launcher, "clean");
+
+  build_stage = ide_build_stage_launcher_new (context, build_launcher);
+  ide_build_stage_launcher_set_clean_launcher (IDE_BUILD_STAGE_LAUNCHER (build_stage), clean_launcher);
+  ide_build_stage_set_check_stdout (build_stage, TRUE);
+  g_signal_connect (build_stage, "query", G_CALLBACK (on_stage_query), NULL);
+
+  id = ide_build_pipeline_connect (pipeline, IDE_BUILD_PHASE_BUILD, 0, build_stage);
+  ide_build_pipeline_addin_track (addin, id);
+
+  /* Setup our install stage */
+  ide_subprocess_launcher_push_argv (install_launcher, ninja);
+  ide_subprocess_launcher_push_argv (install_launcher, "install");
+  install_stage = ide_build_stage_launcher_new (context, install_launcher);
+  g_signal_connect (install_stage, "query", G_CALLBACK (on_stage_query), NULL);
+  id = ide_build_pipeline_connect (pipeline, IDE_BUILD_PHASE_INSTALL, 0, install_stage);
+  ide_build_pipeline_addin_track (addin, id);
+
+  IDE_EXIT;
+
+failure:
+  if (error != NULL)
+    g_warning ("Failed to setup meson build pipeline: %s", error->message);
+}
+
+static void
+build_pipeline_addin_iface_init (IdeBuildPipelineAddinInterface *iface)
+{
+  iface->load = gbp_meson_pipeline_addin_load;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpMesonPipelineAddin, gbp_meson_pipeline_addin, IDE_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_BUILD_PIPELINE_ADDIN,
+                                                build_pipeline_addin_iface_init))
+
+static void
+gbp_meson_pipeline_addin_class_init (GbpMesonPipelineAddinClass *klass)
+{
+}
+
+static void
+gbp_meson_pipeline_addin_init (GbpMesonPipelineAddin *self)
+{
+}
diff --git a/src/plugins/meson/gbp-meson-pipeline-addin.h b/src/plugins/meson/gbp-meson-pipeline-addin.h
new file mode 100644
index 0000000..79bb9ad
--- /dev/null
+++ b/src/plugins/meson/gbp-meson-pipeline-addin.h
@@ -0,0 +1,29 @@
+/* gbp-meson-pipeline-addin.h
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_MESON_PIPELINE_ADDIN (gbp_meson_pipeline_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpMesonPipelineAddin, gbp_meson_pipeline_addin, GBP, MESON_PIPELINE_ADDIN, IdeObject)
+
+G_END_DECLS
diff --git a/src/plugins/meson/meson-plugin.c b/src/plugins/meson/meson-plugin.c
new file mode 100644
index 0000000..36bd525
--- /dev/null
+++ b/src/plugins/meson/meson-plugin.c
@@ -0,0 +1,30 @@
+/* meson-plugin.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libpeas/peas.h>
+#include <ide.h>
+
+#include "gbp-meson-build-system.h"
+#include "gbp-meson-pipeline-addin.h"
+
+void
+gbp_meson_register_types (PeasObjectModule *module)
+{
+  peas_object_module_register_extension_type (module, IDE_TYPE_BUILD_PIPELINE_ADDIN, 
GBP_TYPE_MESON_PIPELINE_ADDIN);
+  peas_object_module_register_extension_type (module, IDE_TYPE_BUILD_SYSTEM, GBP_TYPE_MESON_BUILD_SYSTEM);
+}
diff --git a/src/plugins/meson/meson.build b/src/plugins/meson/meson.build
index e3dc432..763ab8e 100644
--- a/src/plugins/meson/meson.build
+++ b/src/plugins/meson/meson.build
@@ -1,13 +1,22 @@
 if get_option('with_meson')
 
-install_data('meson_plugin.py', install_dir: plugindir)
-
-configure_file(
-          input: 'meson.plugin',
-         output: 'meson.plugin',
-  configuration: configuration_data(),
-        install: true,
-    install_dir: plugindir,
-)
+meson_resources = gnome.compile_resources(    
+  'gbp-meson-resources',                      
+  'meson.gresource.xml',                      
+  c_name: 'gbp_meson',                        
+)                                           
+
+meson_sources = [
+  'meson-plugin.c',
+  'gbp-meson-build-system.c',
+  'gbp-meson-build-system.h',
+  'gbp-meson-build-target.c',
+  'gbp-meson-build-target.h',
+  'gbp-meson-pipeline-addin.c',
+  'gbp-meson-pipeline-addin.h',
+]
+
+gnome_builder_plugins_sources += files(meson_sources)       
+gnome_builder_plugins_sources += meson_resources[0]         
 
 endif
diff --git a/src/plugins/meson/meson.gresource.xml b/src/plugins/meson/meson.gresource.xml
new file mode 100644
index 0000000..f9a72e6
--- /dev/null
+++ b/src/plugins/meson/meson.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/builder/plugins">
+    <file>meson.plugin</file>
+  </gresource>
+</gresources>
diff --git a/src/plugins/meson/meson.plugin b/src/plugins/meson/meson.plugin
index ce3d191..04941e4 100644
--- a/src/plugins/meson/meson.plugin
+++ b/src/plugins/meson/meson.plugin
@@ -1,6 +1,5 @@
 [Plugin]
-Module=meson_plugin
-Loader=python3
+Module=meson-plugin
 Name=Meson
 Description=Provides integration with the Meson build system
 Authors=Patrick Griffis <tingping tingping se>
@@ -8,3 +7,4 @@ Copyright=Copyright © 2016 Patrick Griffis
 Builtin=true
 X-Project-File-Filter-Pattern=meson.build
 X-Project-File-Filter-Name=Meson Project (meson.build)
+Embedded=gbp_meson_register_types



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]