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



commit 9d685dae24dc9bbadc6ec21e5e04c22f636c55d2
Author: Martin Blanchard <tchaik gmx com>
Date:   Mon Oct 23 16:03:06 2017 +0200

    cmake: port cmake plugin to C
    
    Rewrite the build system plugin in statically typed language and try
    to properly implement async APIs:
    * Build flags extraction is done using IdeCompileCommands and thus
    should be availabe right after configure, no need for running a build.
    * Targets extraction isn't implemented yet. Best option would be to
    switch to a cmake-server based implementation. Still looking for a
    cheap bypass...
    * Async initialisation.
    
    This new version is heavily based on the meson plugin code.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=751761

 src/plugins/cmake/cmake-plugin.c             |   30 +
 src/plugins/cmake/cmake.gresource.xml        |    6 +
 src/plugins/cmake/cmake.plugin               |    9 +-
 src/plugins/cmake/cmake_plugin.py            |  151 ------
 src/plugins/cmake/gbp-cmake-build-system.c   |  727 ++++++++++++++++++++++++++
 src/plugins/cmake/gbp-cmake-build-system.h   |   30 +
 src/plugins/cmake/gbp-cmake-build-target.c   |  105 ++++
 src/plugins/cmake/gbp-cmake-build-target.h   |   34 ++
 src/plugins/cmake/gbp-cmake-pipeline-addin.c |  218 ++++++++
 src/plugins/cmake/gbp-cmake-pipeline-addin.h |   30 +
 src/plugins/cmake/meson.build                |   25 +-
 11 files changed, 1201 insertions(+), 164 deletions(-)
---
diff --git a/src/plugins/cmake/cmake-plugin.c b/src/plugins/cmake/cmake-plugin.c
new file mode 100644
index 0000000..a4eae84
--- /dev/null
+++ b/src/plugins/cmake/cmake-plugin.c
@@ -0,0 +1,30 @@
+/* cmake-plugin.c
+ *
+ * Copyright (C) 2016 Martin Blanchard <tchaik gmx 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-cmake-build-system.h"
+#include "gbp-cmake-pipeline-addin.h"
+
+void
+gbp_cmake_register_types (PeasObjectModule *module)
+{
+  peas_object_module_register_extension_type (module, IDE_TYPE_BUILD_PIPELINE_ADDIN, 
GBP_TYPE_CMAKE_PIPELINE_ADDIN);
+  peas_object_module_register_extension_type (module, IDE_TYPE_BUILD_SYSTEM, GBP_TYPE_CMAKE_BUILD_SYSTEM);
+}
diff --git a/src/plugins/cmake/cmake.gresource.xml b/src/plugins/cmake/cmake.gresource.xml
new file mode 100644
index 0000000..13ed9b0
--- /dev/null
+++ b/src/plugins/cmake/cmake.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/builder/plugins">
+    <file>cmake.plugin</file>
+  </gresource>
+</gresources>
diff --git a/src/plugins/cmake/cmake.plugin b/src/plugins/cmake/cmake.plugin
index 6588d36..e668d2c 100644
--- a/src/plugins/cmake/cmake.plugin
+++ b/src/plugins/cmake/cmake.plugin
@@ -1,11 +1,10 @@
 [Plugin]
-Module=cmake_plugin
-Loader=python3
+Module=cmake-plugin
 Name=CMake
 Description=Provides integration with the CMake build system
-Authors=Christian Hergert <chergert redhat com>
-Copyright=Copyright © 2016 Christian Hergert
+Authors=Martin Blanchard <tchaik gmx com>
+Copyright=Copyright © 2016 Martin Blanchard
 Builtin=true
-Hidden=false
 X-Project-File-Filter-Pattern=CMakeLists.txt
 X-Project-File-Filter-Name=CMake Project (CMakeLists.txt)
+Embedded=gbp_cmake_register_types
diff --git a/src/plugins/cmake/gbp-cmake-build-system.c b/src/plugins/cmake/gbp-cmake-build-system.c
new file mode 100644
index 0000000..2755bf8
--- /dev/null
+++ b/src/plugins/cmake/gbp-cmake-build-system.c
@@ -0,0 +1,727 @@
+/* gbp-cmake-build-system.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ * Copyright (C) 2016 Martin Blanchard <tchaik gmx 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-cmake-build-system"
+
+#include <glib/gi18n.h>
+
+#include "gbp-cmake-build-system.h"
+#include "gbp-cmake-build-target.h"
+
+struct _GbpCMakeBuildSystem
+{
+  IdeObject           parent_instance;
+
+  GFile              *project_file;
+  IdeCompileCommands *compile_commands;
+  GFileMonitor       *monitor;
+};
+
+static void async_initable_iface_init (GAsyncInitableIface     *iface);
+static void build_system_iface_init   (IdeBuildSystemInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GbpCMakeBuildSystem, gbp_cmake_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_cmake_build_system_commands_file_changed (GbpCMakeBuildSystem *self,
+                                              GFile               *file,
+                                              GFile               *other_file,
+                                              GFileMonitorEvent    event,
+                                              GFileMonitor        *monitor)
+{
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CMAKE_BUILD_SYSTEM (self));
+  g_assert (!file || G_IS_FILE (file));
+  g_assert (!other_file || G_IS_FILE (other_file));
+  g_assert (G_IS_FILE_MONITOR (monitor));
+
+  g_clear_object (&self->compile_commands);
+
+  g_file_monitor_cancel (monitor);
+  g_clear_object (&self->monitor);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_cmake_build_system_monitor_commands_file (GbpCMakeBuildSystem *self,
+                                              GFile               *file)
+{
+  g_autoptr(GFileMonitor) monitor = NULL;
+
+  g_assert (GBP_IS_CMAKE_BUILD_SYSTEM (self));
+  g_assert (G_IS_FILE (file));
+
+  monitor = g_file_monitor_file (file,
+                                 G_FILE_MONITOR_NONE,
+                                 NULL,
+                                 NULL);
+
+  g_signal_connect_object (monitor,
+                           "changed",
+                           G_CALLBACK (gbp_cmake_build_system_commands_file_changed),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_set_object (&self->monitor, monitor);
+}
+
+static void
+gbp_cmake_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_cmake_build_system_ensure_config_async (GbpCMakeBuildSystem *self,
+                                            GCancellable        *cancellable,
+                                            GAsyncReadyCallback  callback,
+                                            gpointer             user_data)
+{
+  g_autoptr(GTask) task = NULL;
+  IdeBuildManager *build_manager;
+  IdeContext *context;
+
+  g_assert (GBP_IS_CMAKE_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_cmake_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_cmake_build_system_ensure_config_cb,
+                                   g_steal_pointer (&task));
+}
+
+static gboolean
+gbp_cmake_build_system_ensure_config_finish (GbpCMakeBuildSystem  *self,
+                                             GAsyncResult         *result,
+                                             GError              **error)
+{
+  g_assert (GBP_IS_CMAKE_BUILD_SYSTEM (self));
+  g_assert (G_IS_TASK (result));
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+gbp_cmake_build_system_load_commands_load_cb (GObject      *object,
+                                              GAsyncResult *result,
+                                              gpointer      user_data)
+{
+  IdeCompileCommands *compile_commands = (IdeCompileCommands *)object;
+  GbpCMakeBuildSystem *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_CMAKE_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_cmake_build_system_load_commands_config_cb (GObject      *object,
+                                                GAsyncResult *result,
+                                                gpointer      user_data)
+{
+  GbpCMakeBuildSystem *self = (GbpCMakeBuildSystem *)object;
+  g_autoptr(IdeCompileCommands) compile_commands = NULL;
+  g_autoptr(GTask) task = user_data;
+  g_autoptr(GFileMonitor) monitor = NULL;
+  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_CMAKE_BUILD_SYSTEM (self));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  if (!gbp_cmake_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_cmake_build_system_load_commands_load_cb,
+                                   g_steal_pointer (&task));
+
+  gbp_cmake_build_system_monitor_commands_file (self, file);
+}
+
+static void
+gbp_cmake_build_system_load_commands_async (GbpCMakeBuildSystem *self,
+                                            GCancellable        *cancellable,
+                                            GAsyncReadyCallback  callback,
+                                            gpointer             user_data)
+{
+  g_autoptr(GTask) task = NULL;
+  IdeBuildManager *build_manager;
+  IdeBuildPipeline *pipeline;
+  IdeContext *context;
+
+  g_assert (GBP_IS_CMAKE_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_cmake_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_cmake_build_system_load_commands_load_cb,
+                                           g_steal_pointer (&task));
+
+          gbp_cmake_build_system_monitor_commands_file (self, file);
+
+          return;
+        }
+    }
+
+  /*
+   * It looks like we need to ensure the build pipeline advances to the the
+   * CONFIGURE phase so that cmake has generated a new compile_commands.json
+   * that we can load.
+   */
+
+  gbp_cmake_build_system_ensure_config_async (self,
+                                              cancellable,
+                                              gbp_cmake_build_system_load_commands_config_cb,
+                                              g_steal_pointer (&task));
+}
+
+static IdeCompileCommands *
+gbp_cmake_build_system_load_commands_finish (GbpCMakeBuildSystem  *self,
+                                             GAsyncResult         *result,
+                                             GError              **error)
+{
+  g_assert (GBP_IS_CMAKE_BUILD_SYSTEM (self));
+  g_assert (G_IS_TASK (result));
+
+  return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+static void
+gbp_cmake_build_system_finalize (GObject *object)
+{
+  GbpCMakeBuildSystem *self = (GbpCMakeBuildSystem *)object;
+
+  g_clear_object (&self->project_file);
+  g_clear_object (&self->compile_commands);
+  g_clear_object (&self->monitor);
+
+  G_OBJECT_CLASS (gbp_cmake_build_system_parent_class)->finalize (object);
+}
+
+static void
+gbp_cmake_build_system_get_property (GObject    *object,
+                                     guint       prop_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
+{
+  GbpCMakeBuildSystem *self = GBP_CMAKE_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_cmake_build_system_set_property (GObject      *object,
+                                     guint         prop_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
+{
+  GbpCMakeBuildSystem *self = GBP_CMAKE_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_cmake_build_system_class_init (GbpCMakeBuildSystemClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gbp_cmake_build_system_finalize;
+  object_class->get_property = gbp_cmake_build_system_get_property;
+  object_class->set_property = gbp_cmake_build_system_set_property;
+
+  properties [PROP_PROJECT_FILE] =
+    g_param_spec_object ("project-file",
+                         "Project File",
+                         "The primary CMakeLists.txt 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_cmake_build_system_init (GbpCMakeBuildSystem *self)
+{
+}
+
+static gchar *
+gbp_cmake_build_system_get_id (IdeBuildSystem *build_system)
+{
+  return g_strdup ("cmake");
+}
+
+static gchar *
+gbp_cmake_build_system_get_display_name (IdeBuildSystem *build_system)
+{
+  return g_strdup (_("CMake"));
+}
+
+static gint
+gbp_cmake_build_system_get_priority (IdeBuildSystem *build_system)
+{
+  return 100;
+}
+
+static void
+gbp_cmake_build_system_get_build_flags_cb (GObject      *object,
+                                           GAsyncResult *result,
+                                           gpointer      user_data)
+{
+  GbpCMakeBuildSystem *self = (GbpCMakeBuildSystem *)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) build_flags = NULL;
+  GFile *file;
+
+  g_assert (GBP_IS_CMAKE_BUILD_SYSTEM (self));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  compile_commands = gbp_cmake_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));
+
+  build_flags = ide_compile_commands_lookup (compile_commands, file, &directory, &error);
+
+  if (build_flags == NULL)
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
+
+  g_task_return_pointer (task, g_steal_pointer (&build_flags), (GDestroyNotify)g_strfreev);
+}
+
+static void
+gbp_cmake_build_system_get_build_flags_async (IdeBuildSystem      *build_system,
+                                              IdeFile             *file,
+                                              GCancellable        *cancellable,
+                                              GAsyncReadyCallback  callback,
+                                              gpointer             user_data)
+{
+  GbpCMakeBuildSystem *self = (GbpCMakeBuildSystem *)build_system;
+  g_autoptr(GTask) task = NULL;
+  GFile *gfile;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CMAKE_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_cmake_build_system_get_build_flags_async);
+  g_task_set_task_data (task, g_object_ref (gfile), g_object_unref);
+
+  gbp_cmake_build_system_load_commands_async (self,
+                                              cancellable,
+                                              gbp_cmake_build_system_get_build_flags_cb,
+                                              g_steal_pointer (&task));
+
+  IDE_EXIT;
+}
+
+static gchar **
+gbp_cmake_build_system_get_build_flags_finish (IdeBuildSystem  *build_system,
+                                               GAsyncResult    *result,
+                                               GError         **error)
+{
+  GbpCMakeBuildSystem *self = (GbpCMakeBuildSystem *)build_system;
+  gchar **build_flags;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CMAKE_BUILD_SYSTEM (self));
+  g_assert (G_IS_TASK (result));
+
+  build_flags = g_task_propagate_pointer (G_TASK (result), error);
+
+  IDE_RETURN (build_flags);
+}
+
+static void
+gbp_cmake_build_system_get_build_targets_async (IdeBuildSystem      *build_system,
+                                                GCancellable        *cancellable,
+                                                GAsyncReadyCallback  callback,
+                                                gpointer             user_data)
+{
+  GbpCMakeBuildSystem *self = (GbpCMakeBuildSystem *)build_system;
+  g_autoptr(GTask) task = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CMAKE_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_cmake_build_system_get_build_targets_async);
+
+  /* Not implemented yet, still looking for the best option... */
+  g_task_return_error (task,
+                       g_error_new (G_IO_ERROR,
+                                    G_IO_ERROR_NOT_SUPPORTED,
+                                    "Extracting targets from CMake projects isn't supported yet…"));
+
+  IDE_EXIT;
+}
+
+static GPtrArray *
+gbp_cmake_build_system_get_build_targets_finish (IdeBuildSystem  *build_system,
+                                                 GAsyncResult    *result,
+                                                 GError         **error)
+{
+  GbpCMakeBuildSystem *self = (GbpCMakeBuildSystem *)build_system;
+  GPtrArray *build_targets;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CMAKE_BUILD_SYSTEM (self));
+  g_assert (G_IS_TASK (result));
+
+  build_targets = g_task_propagate_pointer (G_TASK (result), error);
+
+#ifdef IDE_ENABLE_TRACE
+  if (build_targets != NULL)
+    {
+      IDE_TRACE_MSG ("Discovered %u targets", build_targets->len);
+
+      for (guint i = 0; i < build_targets->len; i++)
+        {
+          IdeBuildTarget *target = g_ptr_array_index (build_targets, i);
+          g_autofree gchar *name = NULL;
+
+          g_assert (GBP_IS_CMAKE_BUILD_TARGET (target));
+          g_assert (IDE_IS_BUILD_TARGET (target));
+
+          name = ide_build_target_get_name (target);
+          IDE_TRACE_MSG ("[%u]: %s", i, name);
+        }
+    }
+#endif
+
+  IDE_RETURN (build_targets);
+}
+
+static void
+build_system_iface_init (IdeBuildSystemInterface *iface)
+{
+  iface->get_id = gbp_cmake_build_system_get_id;
+  iface->get_display_name = gbp_cmake_build_system_get_display_name;
+  iface->get_priority = gbp_cmake_build_system_get_priority;
+  iface->get_build_flags_async = gbp_cmake_build_system_get_build_flags_async;
+  iface->get_build_flags_finish = gbp_cmake_build_system_get_build_flags_finish;
+  iface->get_build_targets_async = gbp_cmake_build_system_get_build_targets_async;
+  iface->get_build_targets_finish = gbp_cmake_build_system_get_build_targets_finish;
+}
+
+static void
+gbp_cmake_build_system_notify_pipeline (GbpCMakeBuildSystem *self,
+                                        GParamSpec          *pspec,
+                                        IdeBuildManager     *build_manager)
+{
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CMAKE_BUILD_SYSTEM (self));
+  g_assert (pspec != NULL);
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  /*
+   * We need to regenerate compile commands when the build pipeline
+   * changes so that we get the updated commands.
+   */
+  g_clear_object (&self->compile_commands);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_cmake_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_CMAKE_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, "CMakeLists.txt"))
+    {
+      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) cmake_file = g_file_get_child (project_file, "CMakeLists.txt");
+
+      if (g_file_query_exists (cmake_file, cancellable))
+        {
+          g_task_return_pointer (task, g_object_ref (cmake_file), 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 cmake plugin",
+                           name);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_cmake_build_system_init_async (GAsyncInitable      *initable,
+                                   gint                 io_priority,
+                                   GCancellable        *cancellable,
+                                   GAsyncReadyCallback  callback,
+                                   gpointer             user_data)
+{
+  GbpCMakeBuildSystem *self = (GbpCMakeBuildSystem *)initable;
+  g_autoptr(GTask) task = NULL;
+  IdeBuildManager *build_manager;
+  IdeContext *context;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CMAKE_BUILD_SYSTEM (self));
+  g_assert (G_IS_FILE (self->project_file));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  g_assert (IDE_IS_CONTEXT (context));
+
+  build_manager = ide_context_get_build_manager (context);
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, gbp_cmake_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);
+
+  /*
+   * We want to be notified of any changes to the current build manager.
+   * This will let us invalidate our compile_commands.json when it changes.
+   */
+  g_signal_connect_object (build_manager,
+                           "notify::pipeline",
+                           G_CALLBACK (gbp_cmake_build_system_notify_pipeline),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_task_run_in_thread (task, gbp_cmake_build_system_init_worker);
+
+  IDE_EXIT;
+}
+
+static gboolean
+gbp_cmake_build_system_init_finish (GAsyncInitable  *initable,
+                                    GAsyncResult    *result,
+                                    GError         **error)
+{
+  GbpCMakeBuildSystem *self = (GbpCMakeBuildSystem *)initable;
+  g_autoptr(GFile) project_file = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CMAKE_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_cmake_build_system_init_async;
+  iface->init_finish = gbp_cmake_build_system_init_finish;
+}
diff --git a/src/plugins/cmake/gbp-cmake-build-system.h b/src/plugins/cmake/gbp-cmake-build-system.h
new file mode 100644
index 0000000..7aad12d
--- /dev/null
+++ b/src/plugins/cmake/gbp-cmake-build-system.h
@@ -0,0 +1,30 @@
+/* gbp-cmake-build-system.h
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ * Copyright (C) 2016 Martin Blanchard <tchaik gmx 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_CMAKE_BUILD_SYSTEM (gbp_cmake_build_system_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpCMakeBuildSystem, gbp_cmake_build_system, GBP, CMAKE_BUILD_SYSTEM, IdeObject)
+
+G_END_DECLS
diff --git a/src/plugins/cmake/gbp-cmake-build-target.c b/src/plugins/cmake/gbp-cmake-build-target.c
new file mode 100644
index 0000000..e52eba5
--- /dev/null
+++ b/src/plugins/cmake/gbp-cmake-build-target.c
@@ -0,0 +1,105 @@
+/* gbp-cmake-build-target.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ * Copyright (C) 2016 Martin Blanchard <tchaik gmx 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-cmake-build-target"
+
+#include "gbp-cmake-build-target.h"
+
+struct _GbpCMakeBuildTarget
+{
+  IdeObject parent_instance;
+
+  GFile    *install_directory;
+  gchar    *name;
+};
+
+static GFile *
+gbp_cmake_build_target_get_install_directory (IdeBuildTarget *build_target)
+{
+  GbpCMakeBuildTarget *self = (GbpCMakeBuildTarget *)build_target;
+
+  g_assert (GBP_IS_CMAKE_BUILD_TARGET (self));
+
+  return self->install_directory ? g_object_ref (self->install_directory) : NULL;
+}
+
+static gchar *
+gbp_cmake_build_target_get_name (IdeBuildTarget *build_target)
+{
+  GbpCMakeBuildTarget *self = (GbpCMakeBuildTarget *)build_target;
+
+  g_assert (GBP_IS_CMAKE_BUILD_TARGET (self));
+
+  return self->name ? g_strdup (self->name) : NULL;
+}
+
+static void
+build_target_iface_init (IdeBuildTargetInterface *iface)
+{
+  iface->get_install_directory = gbp_cmake_build_target_get_install_directory;
+  iface->get_name = gbp_cmake_build_target_get_name;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpCMakeBuildTarget, gbp_cmake_build_target, IDE_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_BUILD_TARGET, build_target_iface_init))
+
+static void
+gbp_cmake_build_target_finalize (GObject *object)
+{
+  GbpCMakeBuildTarget *self = (GbpCMakeBuildTarget *)object;
+
+  g_clear_object (&self->install_directory);
+  g_clear_pointer (&self->name, g_free);
+
+  G_OBJECT_CLASS (gbp_cmake_build_target_parent_class)->finalize (object);
+}
+
+static void
+gbp_cmake_build_target_class_init (GbpCMakeBuildTargetClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gbp_cmake_build_target_finalize;
+}
+
+static void
+gbp_cmake_build_target_init (GbpCMakeBuildTarget *self)
+{
+}
+
+IdeBuildTarget *
+gbp_cmake_build_target_new (IdeContext *context,
+                            GFile      *install_directory,
+                            gchar      *name)
+{
+  GbpCMakeBuildTarget *self;
+
+  g_return_val_if_fail (!context || IDE_IS_CONTEXT (context), NULL);
+  g_return_val_if_fail (G_IS_FILE (install_directory), NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+
+  self = g_object_new (GBP_TYPE_CMAKE_BUILD_TARGET,
+                       "context", context,
+                       NULL);
+
+  g_set_object (&self->install_directory, install_directory);
+  self->name = g_strdup (name);
+
+  return IDE_BUILD_TARGET (self);
+}
diff --git a/src/plugins/cmake/gbp-cmake-build-target.h b/src/plugins/cmake/gbp-cmake-build-target.h
new file mode 100644
index 0000000..662a0b1
--- /dev/null
+++ b/src/plugins/cmake/gbp-cmake-build-target.h
@@ -0,0 +1,34 @@
+/* gbp-cmake-build-target.h
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ * Copyright (C) 2016 Martin Blanchard <tchaik gmx 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_CMAKE_BUILD_TARGET (gbp_cmake_build_target_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpCMakeBuildTarget, gbp_cmake_build_target, GBP, CMAKE_BUILD_TARGET, IdeObject)
+
+IdeBuildTarget *gbp_cmake_build_target_new (IdeContext *context,
+                                            GFile      *install_directory,
+                                            gchar      *name);
+
+G_END_DECLS
diff --git a/src/plugins/cmake/gbp-cmake-pipeline-addin.c b/src/plugins/cmake/gbp-cmake-pipeline-addin.c
new file mode 100644
index 0000000..316e86f
--- /dev/null
+++ b/src/plugins/cmake/gbp-cmake-pipeline-addin.c
@@ -0,0 +1,218 @@
+/* gbp-cmake-pipeline-addin.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ * Copyright (C) 2016 Martin Blanchard <tchaik gmx 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-cmake-pipeline-addin"
+
+#include "gbp-cmake-build-system.h"
+#include "gbp-cmake-pipeline-addin.h"
+
+struct _GbpCMakePipelineAddin
+{
+  IdeObject parent_instance;
+};
+
+static const gchar *ninja_names[] = { "ninja-build", "ninja" };
+
+static void build_pipeline_addin_iface_init (IdeBuildPipelineAddinInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GbpCMakePipelineAddin, gbp_cmake_pipeline_addin, IDE_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_BUILD_PIPELINE_ADDIN, 
build_pipeline_addin_iface_init))
+
+static void
+gbp_cmake_pipeline_addin_class_init (GbpCMakePipelineAddinClass *klass)
+{
+}
+
+static void
+gbp_cmake_pipeline_addin_init (GbpCMakePipelineAddin *self)
+{
+}
+
+static void
+gbp_cmake_pipeline_addin_stage_query_cb (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_cmake_pipeline_addin_load (IdeBuildPipelineAddin *addin,
+                               IdeBuildPipeline      *pipeline)
+{
+  GbpCMakePipelineAddin *self = (GbpCMakePipelineAddin *)addin;
+  g_autoptr(IdeSubprocessLauncher) configure_launcher = NULL;
+  g_autoptr(IdeSubprocessLauncher) build_launcher = NULL;
+  g_autoptr(IdeSubprocessLauncher) install_launcher = NULL;
+  g_autoptr(IdeSubprocessLauncher) clean_launcher = NULL;
+  g_autoptr(IdeBuildStage) configure_stage = NULL;
+  g_autoptr(IdeBuildStage) build_stage = NULL;
+  g_autoptr(IdeBuildStage) install_stage = NULL;
+  g_autoptr(GError) error = NULL;
+  g_autofree gchar *prefix_option = NULL;
+  g_autofree gchar *build_ninja = NULL;
+  IdeBuildSystem *build_system;
+  IdeConfiguration *configuration;
+  IdeContext *context;
+  IdeRuntime *runtime;
+  const gchar *ninja = NULL;
+  const gchar *config_opts;
+  const gchar *prefix;
+  const gchar *srcdir;
+  guint id;
+  gint parallelism;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CMAKE_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_CMAKE_BUILD_SYSTEM (build_system))
+    IDE_GOTO (failure);
+
+  configuration = 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 (configuration));
+  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. CMake building is disabled.");
+      IDE_EXIT;
+    }
+
+  if (NULL == (configure_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 (configuration);
+  config_opts = ide_configuration_get_config_opts (configuration);
+  parallelism = ide_configuration_get_parallelism (configuration);
+
+  /* Setup our configure stage. */
+
+  prefix_option = g_strdup_printf ("-DCMAKE_INSTALL_PREFIX=%s", prefix);
+
+  ide_subprocess_launcher_push_argv (configure_launcher, "cmake");
+  ide_subprocess_launcher_push_argv (configure_launcher, "-G");
+  ide_subprocess_launcher_push_argv (configure_launcher, "Ninja");
+  ide_subprocess_launcher_push_argv (configure_launcher, ".");
+  ide_subprocess_launcher_push_argv (configure_launcher, srcdir);
+  ide_subprocess_launcher_push_argv (configure_launcher, "-DCMAKE_EXPORT_COMPILE_COMMANDS=1");
+  ide_subprocess_launcher_push_argv (configure_launcher, "-DCMAKE_BUILD_TYPE=RelWithDebInfo");
+  ide_subprocess_launcher_push_argv (configure_launcher, prefix_option);
+
+  if (!ide_str_empty0 (config_opts))
+    {
+      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 (configure_launcher, (const gchar * const *)argv);
+    }
+
+  configure_stage = ide_build_stage_launcher_new (context, configure_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 (configure_stage, TRUE);
+
+  id = ide_build_pipeline_connect (pipeline, IDE_BUILD_PHASE_CONFIGURE, 0, configure_stage);
+  ide_build_pipeline_addin_track (addin, id);
+
+  /* Setup our build stage */
+
+  ide_subprocess_launcher_push_argv (build_launcher, ninja);
+  ide_subprocess_launcher_push_argv (clean_launcher, ninja);
+
+  if (parallelism > 0)
+    {
+      g_autofree gchar *j = g_strdup_printf ("-j%u", parallelism);
+
+      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 (gbp_cmake_pipeline_addin_stage_query_cb),
+                    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 (gbp_cmake_pipeline_addin_stage_query_cb),
+                    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 cmake build pipeline: %s", error->message);
+}
+
+static void
+build_pipeline_addin_iface_init (IdeBuildPipelineAddinInterface *iface)
+{
+  iface->load = gbp_cmake_pipeline_addin_load;
+}
+
diff --git a/src/plugins/cmake/gbp-cmake-pipeline-addin.h b/src/plugins/cmake/gbp-cmake-pipeline-addin.h
new file mode 100644
index 0000000..b0a55c5
--- /dev/null
+++ b/src/plugins/cmake/gbp-cmake-pipeline-addin.h
@@ -0,0 +1,30 @@
+/* gbp-cmake-pipeline-addin.h
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ * Copyright (C) 2016 Martin Blanchard <tchaik gmx 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_CMAKE_PIPELINE_ADDIN (gbp_cmake_pipeline_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpCMakePipelineAddin, gbp_cmake_pipeline_addin, GBP, CMAKE_PIPELINE_ADDIN, IdeObject)
+
+G_END_DECLS
diff --git a/src/plugins/cmake/meson.build b/src/plugins/cmake/meson.build
index 559066d..97ae3a2 100644
--- a/src/plugins/cmake/meson.build
+++ b/src/plugins/cmake/meson.build
@@ -1,13 +1,22 @@
 if get_option('with_cmake')
 
-install_data('cmake_plugin.py', install_dir: plugindir)
-
-configure_file(
-          input: 'cmake.plugin',
-         output: 'cmake.plugin',
-  configuration: configuration_data(),
-        install: true,
-    install_dir: plugindir,
+cmake_resources = gnome.compile_resources(
+  'gbp-cmake-resources',
+  'cmake.gresource.xml',
+  c_name: 'gbp_cmake',
 )
 
+cmake_sources = [
+  'cmake-plugin.c',
+  'gbp-cmake-build-system.c',
+  'gbp-cmake-build-system.h',
+  'gbp-cmake-build-target.c',
+  'gbp-cmake-build-target.h',
+  'gbp-cmake-pipeline-addin.c',
+  'gbp-cmake-pipeline-addin.h',
+]
+
+gnome_builder_plugins_sources += files(cmake_sources)
+gnome_builder_plugins_sources += cmake_resources[0]
+
 endif



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