[gnome-builder/wip/chergert/runtimes] more wip



commit 1ae0be8cd49697fe3799e1769a47d0809fc2ccd6
Author: Christian Hergert <chergert redhat com>
Date:   Tue Feb 2 21:19:49 2016 +0100

    more wip

 Makefile.am                                     |    8 +-
 libide/Makefile.am                              |   22 +-
 libide/ide-build-system.c                       |    1 +
 libide/ide-build-system.h                       |    1 -
 libide/ide-configuration-manager.c              |  314 ++++++++++++++++
 libide/ide-configuration-manager.h              |   39 ++
 libide/ide-configuration.c                      |  432 +++++++++++++++++------
 libide/ide-configuration.h                      |   21 +-
 libide/ide-context.c                            |   86 +++++
 libide/ide-context.h                            |   94 +++---
 libide/ide-device.h                             |    1 +
 libide/ide-environ.c                            |  184 ++++++++++
 libide/ide-environ.h                            |   41 +++
 libide/ide-runtime.c                            |    3 +-
 libide/ide-types.h                              |    4 +-
 libide/ide.h                                    |    4 +
 plugins/autotools/ide-autotools-build-system.c  |   91 +++--
 plugins/autotools/ide-autotools-build-task.c    |  112 ++----
 plugins/autotools/ide-autotools-build-task.h    |    9 +-
 plugins/build-tools/gbp-build-tool.c            |   20 +-
 plugins/build-tools/gbp-build-workbench-addin.c |   10 +-
 plugins/xdg-app/gbp-xdg-runtime-provider.c      |    2 +-
 plugins/xdg-app/gbp-xdg-runtime.c               |    2 +-
 23 files changed, 1213 insertions(+), 288 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 913bfe6..7300a6e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -72,7 +72,7 @@ run:
        GB_IN_TREE_PLUGINS=1 \
        GB_IN_TREE_FONTS=1 \
        GB_IN_TREE_STYLE_SCHEMES=1 \
-       GI_TYPELIB_PATH="libide:contrib/tmpl:$(GI_TYPELIB_PATH)" \
+       GI_TYPELIB_PATH="libide:contrib/egg:contrib/tmpl:$(GI_TYPELIB_PATH)" \
        GOBJECT_DEBUG=instance-count \
        PATH=$(top_builddir)/src:${PATH} \
        $(LIBTOOL) --mode=execute gdb -ex run --args src/gnome-builder -vvvv -s
@@ -82,7 +82,7 @@ strace:
        GB_IN_TREE_PLUGINS=1 \
        GB_IN_TREE_FONTS=1 \
        GB_IN_TREE_STYLE_SCHEMES=1 \
-       GI_TYPELIB_PATH="libide:contrib/tmpl:$(GI_TYPELIB_PATH)" \
+       GI_TYPELIB_PATH="libide:contrib/egg:contrib/tmpl:$(GI_TYPELIB_PATH)" \
        GOBJECT_DEBUG=instance-count \
        PATH=$(top_builddir)/src:${PATH} \
        $(LIBTOOL) --mode=execute strace -T src/gnome-builder -vvvv -s
@@ -92,7 +92,7 @@ debug:
        GB_IN_TREE_PLUGINS=1 \
        GB_IN_TREE_FONTS=1 \
        GB_IN_TREE_STYLE_SCHEMES=1 \
-       GI_TYPELIB_PATH="libide:contrib/tmpl:$(GI_TYPELIB_PATH)" \
+       GI_TYPELIB_PATH="libide:contrib/egg:contrib/tmpl:$(GI_TYPELIB_PATH)" \
        G_DEBUG=fatal-criticals \
        GOBJECT_DEBUG=instance-count \
        PATH=$(top_builddir)/src:${PATH} \
@@ -103,7 +103,7 @@ valgrind:
        GB_IN_TREE_PLUGINS=1 \
        GB_IN_TREE_FONTS=1 \
        GB_IN_TREE_STYLE_SCHEMES=1 \
-       GI_TYPELIB_PATH="libide:contrib/tmpl:$(GI_TYPELIB_PATH)" \
+       GI_TYPELIB_PATH="libide:contrib/egg:contrib/tmpl:$(GI_TYPELIB_PATH)" \
        G_DEBUG=fatal-criticals \
        G_SLICE=always-malloc \
        PATH=$(top_builddir)/src:${PATH} \
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 2564a10..1e16983 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -63,6 +63,8 @@ libide_1_0_la_public_sources = \
        ide-completion-results.h \
        ide-configuration.c \
        ide-configuration.h \
+       ide-configuration-manager.c \
+       ide-configuration-manager.h \
        ide-context.c \
        ide-context.h \
        ide-debugger.c \
@@ -301,6 +303,8 @@ libide_1_0_la_SOURCES = \
        ide-css-provider.c \
        ide-css-provider.h \
        ide-debug.h \
+       ide-environ.c \
+       ide-environ.h \
        ide-extension-util.c \
        ide-extension-util.h \
        ide-internal.h \
@@ -549,6 +553,7 @@ INTROSPECTION_GIRS =
 INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) --warn-all
 INTROSPECTION_COMPILER_ARGS = \
        --includedir=$(srcdir) \
+       --includedir=$(top_builddir)/contrib/egg \
        --includedir=$(top_builddir)/contrib/tmpl
 
 introspection_sources = \
@@ -564,6 +569,7 @@ Ide_1_0_gir_LIBS = \
        $(top_builddir)/contrib/tmpl/libtemplate-glib-1.0.la
 Ide_1_0_gir_FILES = $(introspection_sources)
 Ide_1_0_gir_SCANNERFLAGS = \
+       --include-uninstalled=$(top_builddir)/contrib/egg/Egg-1.0.gir \
        --include-uninstalled=$(top_builddir)/contrib/tmpl/Template-1.0.gir \
        --c-include="ide.h" \
        -n Ide \
@@ -587,11 +593,21 @@ libide-1.0.vapi: Ide-1.0.gir
 
 VAPIGEN_VAPIS = libide-1.0.vapi
 
-libide_1_0_vapi_DEPS = gio-2.0 gtk+-3.0 gtksourceview-3.0 libpeas-1.0 template-glib-1.0
+libide_1_0_vapi_DEPS = \
+       gio-2.0 \
+       gtk+-3.0 \
+       gtksourceview-3.0 \
+       libpeas-1.0 \
+       template-glib-1.0 \
+       egg-private
 libide_1_0_vapi_METADATADIRS = $(srcdir)
 libide_1_0_vapi_FILES = Ide-1.0.gir
-libide_1_0_vapi_VAPIDIRS = $(top_builddir)/contrib/tmpl
-libide_1_0_vapi_GIRDIRS = $(top_builddir)/contrib/tmpl
+libide_1_0_vapi_VAPIDIRS = \
+       $(top_builddir)/contrib/egg \
+       $(top_builddir)/contrib/tmpl
+libide_1_0_vapi_GIRDIRS = \
+       $(top_builddir)/contrib/egg \
+       $(top_builddir)/contrib/tmpl
 
 libide-1.0.deps: Makefile
        $(AM_V_GEN) echo $(libide_1_0_vapi_DEPS) | tr ' ' '\n' > $@
diff --git a/libide/ide-build-system.c b/libide/ide-build-system.c
index fb9c2fb..e2cf3b3 100644
--- a/libide/ide-build-system.c
+++ b/libide/ide-build-system.c
@@ -19,6 +19,7 @@
 #include <glib/gi18n.h>
 
 #include "ide-build-system.h"
+#include "ide-configuration.h"
 #include "ide-context.h"
 #include "ide-device.h"
 #include "ide-device-manager.h"
diff --git a/libide/ide-build-system.h b/libide/ide-build-system.h
index bd8bf7f..3cb9e98 100644
--- a/libide/ide-build-system.h
+++ b/libide/ide-build-system.h
@@ -21,7 +21,6 @@
 
 #include <gio/gio.h>
 
-#include "ide-configuration.h"
 #include "ide-object.h"
 
 G_BEGIN_DECLS
diff --git a/libide/ide-configuration-manager.c b/libide/ide-configuration-manager.c
new file mode 100644
index 0000000..5535f94
--- /dev/null
+++ b/libide/ide-configuration-manager.c
@@ -0,0 +1,314 @@
+/* ide-configuration-manager.c
+ *
+ * Copyright (C) 2016 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 "ide-configuration-manager"
+
+#include "ide-configuration.h"
+#include "ide-configuration-manager.h"
+#include "ide-context.h"
+#include "ide-vcs.h"
+
+struct _IdeConfigurationManager
+{
+  GObject           parent_instance;
+
+  GPtrArray        *configurations;
+  IdeConfiguration *current;
+};
+
+static void async_initable_iface_init (GAsyncInitableIface *iface);
+static void list_model_iface_init     (GListModelInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (IdeConfigurationManager, ide_configuration_manager, IDE_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init)
+                        G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init))
+
+enum {
+  PROP_0,
+  PROP_CURRENT,
+  LAST_PROP
+};
+
+static GParamSpec *properties [LAST_PROP];
+
+/**
+ * ide_configuration_manager_get_configuration:
+ * @self: An #IdeConfigurationManager
+ * @id: The string identifier of the configuration
+ *
+ * Gets the #IdeConfiguration by id. See ide_configuration_get_id().
+ *
+ * Returns: (transfer none) (nullable): An #IdeConfiguration
+ */
+IdeConfiguration *
+ide_configuration_manager_get_configuration (IdeConfigurationManager *self,
+                                             const gchar             *id)
+{
+  g_return_val_if_fail (IDE_IS_CONFIGURATION_MANAGER (self), NULL);
+  g_return_val_if_fail (id != NULL, NULL);
+
+  for (guint i = 0; i < self->configurations->len; i++)
+    {
+      IdeConfiguration *configuration = g_ptr_array_index (self->configurations, i);
+
+      if (g_strcmp0 (id, ide_configuration_get_id (configuration)) == 0)
+        return configuration;
+    }
+
+  return NULL;
+}
+
+static void
+ide_configuration_manager_finalize (GObject *object)
+{
+  IdeConfigurationManager *self = (IdeConfigurationManager *)object;
+
+  g_clear_pointer (&self->configurations, g_ptr_array_unref);
+  g_clear_object (&self->current);
+
+  G_OBJECT_CLASS (ide_configuration_manager_parent_class)->finalize (object);
+}
+
+static void
+ide_configuration_manager_get_property (GObject    *object,
+                                        guint       prop_id,
+                                        GValue     *value,
+                                        GParamSpec *pspec)
+{
+  IdeConfigurationManager *self = IDE_CONFIGURATION_MANAGER (object);
+
+  switch (prop_id)
+    {
+    case PROP_CURRENT:
+      g_value_set_object (value, ide_configuration_manager_get_current (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    }
+}
+
+static void
+ide_configuration_manager_set_property (GObject      *object,
+                                        guint         prop_id,
+                                        const GValue *value,
+                                        GParamSpec   *pspec)
+{
+  IdeConfigurationManager *self = IDE_CONFIGURATION_MANAGER (object);
+
+  switch (prop_id)
+    {
+    case PROP_CURRENT:
+      ide_configuration_manager_set_current (self, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    }
+}
+
+static void
+ide_configuration_manager_class_init (IdeConfigurationManagerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = ide_configuration_manager_finalize;
+  object_class->get_property = ide_configuration_manager_get_property;
+  object_class->set_property = ide_configuration_manager_set_property;
+
+  properties [PROP_CURRENT] =
+    g_param_spec_object ("current",
+                         "Current",
+                         "The current configuration for the context",
+                         IDE_TYPE_CONFIGURATION,
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, LAST_PROP, properties);
+}
+
+static void
+ide_configuration_manager_init (IdeConfigurationManager *self)
+{
+  self->configurations = g_ptr_array_new_with_free_func (g_object_unref);
+}
+
+static GType
+ide_configuration_manager_get_item_type (GListModel *model)
+{
+  return IDE_TYPE_CONFIGURATION;
+}
+
+static guint
+ide_configuration_manager_get_n_items (GListModel *model)
+{
+  IdeConfigurationManager *self = (IdeConfigurationManager *)model;
+
+  g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
+
+  return self->configurations->len;
+}
+
+static gpointer
+ide_configuration_manager_get_item (GListModel *model,
+                                    guint       position)
+{
+  IdeConfigurationManager *self = (IdeConfigurationManager *)model;
+
+  g_return_val_if_fail (IDE_IS_CONFIGURATION_MANAGER (self), NULL);
+  g_return_val_if_fail (position < self->configurations->len, NULL);
+
+  return g_object_ref (g_ptr_array_index (self->configurations, 0));
+}
+
+static void
+list_model_iface_init (GListModelInterface *iface)
+{
+  iface->get_item_type = ide_configuration_manager_get_item_type;
+  iface->get_n_items = ide_configuration_manager_get_n_items;
+  iface->get_item = ide_configuration_manager_get_item;
+}
+
+static void
+ide_configuration_manager_init_worker (GTask        *task,
+                                       gpointer      source_object,
+                                       gpointer      task_data,
+                                       GCancellable *cancellable)
+{
+  IdeConfigurationManager *self = source_object;
+  g_autoptr(GFile) settings_file = NULL;
+  IdeContext *context;
+  GError *error = NULL;
+  IdeVcs *vcs;
+  GFile *workdir;
+
+  g_assert (G_IS_TASK (task));
+  g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  vcs = ide_context_get_vcs (context);
+  workdir = ide_vcs_get_working_directory (vcs);
+  settings_file = g_file_get_child (workdir, ".project-settings");
+
+  if (g_file_query_exists (settings_file, cancellable))
+    {
+      g_autoptr(GKeyFile) key_file = NULL;
+      g_autofree gchar *contents = NULL;
+      gsize len;
+
+      if (!g_file_load_contents (settings_file, cancellable, &contents, &len, NULL, &error))
+        {
+          ide_context_warning (context, "%s", error->message);
+          g_clear_error (&error);
+          goto soft_error;
+        }
+
+      key_file = g_key_file_new ();
+
+      if (!g_key_file_load_from_data (key_file, contents, len, 0, &error))
+        {
+          ide_context_warning (context, "%s", error->message);
+          g_clear_error (&error);
+          goto soft_error;
+        }
+
+      /*
+       * Try to find all of our configuration zones within the key file.
+       * This is stuff like ...
+       */
+      // items_changed (...);
+    }
+
+soft_error:
+  g_task_return_boolean (task, TRUE);
+}
+
+static void
+ide_configuration_manager_init_async (GAsyncInitable      *initable,
+                                      gint                 priority,
+                                      GCancellable        *cancellable,
+                                      GAsyncReadyCallback  callback,
+                                      gpointer             user_data)
+{
+  IdeConfigurationManager *self = (IdeConfigurationManager *)initable;
+  g_autoptr(GTask) task = NULL;
+
+  g_assert (G_IS_ASYNC_INITABLE (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_run_in_thread (task, ide_configuration_manager_init_worker);
+}
+
+static gboolean
+ide_configuration_manager_init_finish (GAsyncInitable  *initable,
+                                       GAsyncResult    *result,
+                                       GError         **error)
+{
+  g_assert (IDE_IS_CONFIGURATION_MANAGER (initable));
+  g_assert (G_IS_TASK (result));
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+async_initable_iface_init (GAsyncInitableIface *iface)
+{
+  iface->init_async = ide_configuration_manager_init_async;
+  iface->init_finish = ide_configuration_manager_init_finish;
+}
+
+void
+ide_configuration_manager_set_current (IdeConfigurationManager *self,
+                                       IdeConfiguration        *current)
+{
+  g_return_if_fail (IDE_IS_CONFIGURATION_MANAGER (self));
+  g_return_if_fail (!current || IDE_IS_CONFIGURATION (current));
+
+  if (g_set_object (&self->current, current))
+    g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CURRENT]);
+}
+
+/**
+ * ide_configuration_manager_get_current:
+ * @self: An #IdeConfigurationManager
+ *
+ * Gets the current configuration to use for building.
+ *
+ * Many systems allow you to pass a configuration in instead of relying on the
+ * default configuration. This sets the default configuration that various
+ * background items might use, such as tags builders which need to discover
+ * settings.
+ *
+ * Returns: (transfer none): An #IdeConfiguration
+ */
+IdeConfiguration *
+ide_configuration_manager_get_current (IdeConfigurationManager *self)
+{
+  g_return_val_if_fail (IDE_IS_CONFIGURATION_MANAGER (self), NULL);
+
+  if (self->current == NULL)
+    {
+      IdeContext *context;
+
+      context = ide_object_get_context (IDE_OBJECT (self));
+      self->current = ide_configuration_new (context, "libide-default", "local", "system");
+    }
+
+  return self->current;
+}
diff --git a/libide/ide-configuration-manager.h b/libide/ide-configuration-manager.h
new file mode 100644
index 0000000..00db9a6
--- /dev/null
+++ b/libide/ide-configuration-manager.h
@@ -0,0 +1,39 @@
+/* ide-configuration-manager.h
+ *
+ * Copyright (C) 2016 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/>.
+ */
+
+#ifndef IDE_CONFIGURATION_MANAGER_H
+#define IDE_CONFIGURATION_MANAGER_H
+
+#include <gio/gio.h>
+
+#include "ide-object.h"
+#include "ide-types.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_CONFIGURATION_MANAGER (ide_configuration_manager_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeConfigurationManager, ide_configuration_manager, IDE, CONFIGURATION_MANAGER, 
IdeObject)
+
+IdeConfiguration *ide_configuration_manager_get_current (IdeConfigurationManager *self);
+void              ide_configuration_manager_set_current (IdeConfigurationManager *self,
+                                                         IdeConfiguration        *configuration);
+
+G_END_DECLS
+
+#endif /* IDE_CONFIGURATION_MANAGER_H */
diff --git a/libide/ide-configuration.c b/libide/ide-configuration.c
index 58e28ab..e47a40b 100644
--- a/libide/ide-configuration.c
+++ b/libide/ide-configuration.c
@@ -16,54 +16,131 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#define G_LOG_DOMAIN "ide-configuration"
+
 #include <string.h>
 
 #include "ide-configuration.h"
+#include "ide-context.h"
 #include "ide-device.h"
+#include "ide-device-manager.h"
+#include "ide-environ.h"
 #include "ide-runtime.h"
+#include "ide-runtime-manager.h"
 
 struct _IdeConfiguration
 {
-  GObject     parent_instance;
+  IdeObject   parent_instance;
 
   gchar      *id;
-  IdeDevice  *device;
-  GPtrArray  *environ;
-  IdeRuntime *runtime;
+  gchar      *device_id;
+  gchar      *runtime_id;
+  IdeEnviron *environ;
+  IdeEnviron *device_environ;
+  IdeEnviron *runtime_environ;
+  gchar      *prefix;
+
+  gint        parallelism;
+  guint       debug : 1;
 };
 
 G_DEFINE_TYPE (IdeConfiguration, ide_configuration, IDE_TYPE_OBJECT)
 
-static void ide_configuration_set_device  (IdeConfiguration *self,
-                                           IdeDevice        *device);
-static void ide_configuration_set_runtime (IdeConfiguration *self,
-                                           IdeRuntime       *runtime);
-static void ide_configuration_set_id      (IdeConfiguration *self,
-                                           const gchar      *id);
+static void ide_configuration_set_device     (IdeConfiguration *self,
+                                              IdeDevice        *device);
+static void ide_configuration_set_device_id  (IdeConfiguration *self,
+                                              const gchar      *device_id);
+static void ide_configuration_set_runtime    (IdeConfiguration *self,
+                                              IdeRuntime       *runtime);
+static void ide_configuration_set_runtime_id (IdeConfiguration *self,
+                                              const gchar      *runtime_id);
+static void ide_configuration_set_id         (IdeConfiguration *self,
+                                              const gchar      *id);
 
 enum {
   PROP_0,
+  PROP_DEBUG,
   PROP_DEVICE,
+  PROP_DEVICE_ID,
   PROP_ENVIRON,
   PROP_ID,
+  PROP_PARALLELISM,
+  PROP_PREFIX,
   PROP_RUNTIME,
+  PROP_RUNTIME_ID,
   N_PROPS
 };
 
 static GParamSpec *properties [N_PROPS];
 
 static void
+ide_configuration_device_manager_items_changed (IdeConfiguration *self,
+                                                guint             position,
+                                                guint             added,
+                                                guint             removed,
+                                                IdeDeviceManager *device_manager)
+{
+  IdeDevice *device;
+
+  g_assert (IDE_IS_CONFIGURATION (self));
+  g_assert (IDE_IS_DEVICE_MANAGER (device_manager));
+
+  device = ide_device_manager_get_device (device_manager, self->device_id);
+
+  ide_environ_reset (self->device_environ);
+
+  if (device != NULL)
+    ide_device_prepare_configuration (device, self);
+}
+
+static void
+ide_configuration_runtime_manager_items_changed (IdeConfiguration  *self,
+                                                 guint              position,
+                                                 guint              added,
+                                                 guint              removed,
+                                                 IdeRuntimeManager *runtime_manager)
+{
+  IdeRuntime *runtime;
+
+  g_assert (IDE_IS_CONFIGURATION (self));
+  g_assert (IDE_IS_RUNTIME_MANAGER (runtime_manager));
+
+  runtime = ide_runtime_manager_get_runtime (runtime_manager, self->runtime_id);
+
+  ide_environ_reset (self->runtime_environ);
+
+  if (runtime != NULL)
+    ide_runtime_prepare_configuration (runtime, self);
+}
+
+static void
 ide_configuration_constructed (GObject *object)
 {
   IdeConfiguration *self = (IdeConfiguration *)object;
+  IdeContext *context;
+  IdeDeviceManager *device_manager;
+  IdeRuntimeManager *runtime_manager;
 
   G_OBJECT_CLASS (ide_configuration_parent_class)->constructed (object);
 
-  if (self->device != NULL)
-    ide_device_prepare_configuration (self->device, self);
+  context = ide_object_get_context (IDE_OBJECT (self));
+  device_manager = ide_context_get_device_manager (context);
+  runtime_manager = ide_context_get_runtime_manager (context);
+
+  g_signal_connect_object (device_manager,
+                           "items-changed",
+                           G_CALLBACK (ide_configuration_device_manager_items_changed),
+                           self,
+                           G_CONNECT_SWAPPED);
 
-  if (self->runtime != NULL)
-    ide_runtime_prepare_configuration (self->runtime, self);
+  g_signal_connect_object (runtime_manager,
+                           "items-changed",
+                           G_CALLBACK (ide_configuration_runtime_manager_items_changed),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  ide_configuration_device_manager_items_changed (self, 0, 0, 0, device_manager);
+  ide_configuration_runtime_manager_items_changed (self, 0, 0, 0, runtime_manager);
 }
 
 static void
@@ -71,10 +148,11 @@ ide_configuration_finalize (GObject *object)
 {
   IdeConfiguration *self = (IdeConfiguration *)object;
 
-  g_clear_object (&self->device);
-  g_clear_pointer (&self->environ, g_ptr_array_unref);
+  g_clear_pointer (&self->device_id, g_free);
+  g_clear_pointer (&self->environ, ide_environ_unref);
   g_clear_pointer (&self->id, g_free);
-  g_clear_object (&self->runtime);
+  g_clear_pointer (&self->prefix, g_free);
+  g_clear_pointer (&self->runtime_id, g_free);
 
   G_OBJECT_CLASS (ide_configuration_parent_class)->finalize (object);
 }
@@ -89,6 +167,10 @@ ide_configuration_get_property (GObject    *object,
 
   switch (prop_id)
     {
+    case PROP_DEBUG:
+      g_value_set_boolean (value, ide_configuration_get_debug (self));
+      break;
+
     case PROP_DEVICE:
       g_value_set_object (value, ide_configuration_get_device (self));
       break;
@@ -101,10 +183,22 @@ ide_configuration_get_property (GObject    *object,
       g_value_set_string (value, ide_configuration_get_id (self));
       break;
 
+    case PROP_PARALLELISM:
+      g_value_set_int (value, ide_configuration_get_parallelism (self));
+      break;
+
+    case PROP_PREFIX:
+      g_value_set_string (value, ide_configuration_get_prefix (self));
+      break;
+
     case PROP_RUNTIME:
       g_value_set_object (value, ide_configuration_get_runtime (self));
       break;
 
+    case PROP_RUNTIME_ID:
+      g_value_set_object (value, ide_configuration_get_runtime (self));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -120,18 +214,38 @@ ide_configuration_set_property (GObject      *object,
 
   switch (prop_id)
     {
+    case PROP_DEBUG:
+      ide_configuration_set_debug (self, g_value_get_boolean (value));
+      break;
+
     case PROP_DEVICE:
       ide_configuration_set_device (self, g_value_get_object (value));
       break;
 
+    case PROP_DEVICE_ID:
+      ide_configuration_set_device_id (self, g_value_get_string (value));
+      break;
+
     case PROP_ID:
       ide_configuration_set_id (self, g_value_get_string (value));
       break;
 
+    case PROP_PREFIX:
+      ide_configuration_set_prefix (self, g_value_get_string (value));
+      break;
+
+    case PROP_PARALLELISM:
+      ide_configuration_set_parallelism (self, g_value_get_int (value));
+      break;
+
     case PROP_RUNTIME:
       ide_configuration_set_runtime (self, g_value_get_object (value));
       break;
 
+    case PROP_RUNTIME_ID:
+      ide_configuration_set_runtime_id (self, g_value_get_string (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -147,6 +261,13 @@ ide_configuration_class_init (IdeConfigurationClass *klass)
   object_class->get_property = ide_configuration_get_property;
   object_class->set_property = ide_configuration_set_property;
 
+  properties [PROP_DEBUG] =
+    g_param_spec_boolean ("debug",
+                          "Debug",
+                          "Debug",
+                          TRUE,
+                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   properties [PROP_DEVICE] =
     g_param_spec_object ("device",
                          "Device",
@@ -154,6 +275,13 @@ ide_configuration_class_init (IdeConfigurationClass *klass)
                          IDE_TYPE_DEVICE,
                          (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
 
+  properties [PROP_DEVICE_ID] =
+    g_param_spec_string ("device-id",
+                         "Device Id",
+                         "The identifier of the device",
+                         "local",
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
   properties [PROP_ENVIRON] =
     g_param_spec_boxed ("environ",
                         "Environ",
@@ -168,6 +296,22 @@ ide_configuration_class_init (IdeConfigurationClass *klass)
                          NULL,
                          (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
 
+  properties [PROP_PARALLELISM] =
+    g_param_spec_int ("parallelism",
+                      "Parallelism",
+                      "Parallelism",
+                      -1,
+                      G_MAXINT,
+                      -1,
+                      (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_PREFIX] =
+    g_param_spec_string ("prefix",
+                         "Prefix",
+                         "Prefix",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   properties [PROP_RUNTIME] =
     g_param_spec_object ("runtime",
                          "Runtime",
@@ -175,46 +319,90 @@ ide_configuration_class_init (IdeConfigurationClass *klass)
                          IDE_TYPE_RUNTIME,
                          (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
 
+  properties [PROP_RUNTIME_ID] =
+    g_param_spec_string ("runtime-id",
+                         "Runtime Id",
+                         "The identifier of the runtime",
+                         "system",
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
   g_object_class_install_properties (object_class, N_PROPS, properties);
 }
 
 static void
 ide_configuration_init (IdeConfiguration *self)
 {
-  self->environ = g_ptr_array_new_with_free_func (g_free);
-  g_ptr_array_add (self->environ, NULL);
+  self->device_id = g_strdup ("local");
+  self->runtime_id = g_strdup ("system");
+  self->debug = TRUE;
+  self->device_environ = ide_environ_new (NULL);
+  self->runtime_environ = ide_environ_new (self->device_environ);
+  self->environ = ide_environ_new (self->runtime_environ);
 }
 
 IdeConfiguration *
-ide_configuration_new (const gchar *id,
-                       IdeDevice   *device,
-                       IdeRuntime  *runtime)
+ide_configuration_new (IdeContext  *context,
+                       const gchar *id,
+                       const gchar *device_id,
+                       const gchar *runtime_id)
 {
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
   g_return_val_if_fail (id != NULL, NULL);
-  g_return_val_if_fail (IDE_IS_DEVICE (device), NULL);
-  g_return_val_if_fail (IDE_IS_RUNTIME (runtime), NULL);
+  g_return_val_if_fail (device_id != NULL, NULL);
+  g_return_val_if_fail (runtime_id != NULL, NULL);
 
   return g_object_new (IDE_TYPE_CONFIGURATION,
-                       "device", device,
+                       "context", context,
+                       "device-id", device_id,
                        "id", id,
-                       "runtime", runtime,
+                       "runtime-id", runtime_id,
                        NULL);
 }
 
+const gchar *
+ide_configuration_get_device_id (IdeConfiguration *self)
+{
+  g_return_val_if_fail (IDE_IS_CONFIGURATION (self), NULL);
+
+  return self->device_id;
+}
+
+static void
+ide_configuration_set_device_id (IdeConfiguration *self,
+                                 const gchar      *device_id)
+{
+  g_return_if_fail (IDE_IS_CONFIGURATION (self));
+  g_return_if_fail (device_id != NULL);
+
+  if (g_strcmp0 (device_id, self->device_id) != 0)
+    {
+      g_free (self->device_id);
+      self->device_id = g_strdup (device_id);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DEVICE_ID]);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DEVICE]);
+    }
+}
+
 /**
  * ide_configuration_get_device:
  * @self: An #IdeConfiguration
  *
  * Gets the device for the configuration.
  *
- * Returns: (transfer none): An #IdeDevice.
+ * Returns: (transfer none) (nullable): An #IdeDevice.
  */
 IdeDevice *
 ide_configuration_get_device (IdeConfiguration *self)
 {
+  IdeDeviceManager *device_manager;
+  IdeContext *context;
+
   g_return_val_if_fail (IDE_IS_CONFIGURATION (self), NULL);
 
-  return self->device;
+  context = ide_object_get_context (IDE_OBJECT (self));
+  device_manager = ide_context_get_device_manager (context);
+
+  return ide_device_manager_get_device (device_manager, self->device_id);
 }
 
 static void
@@ -224,7 +412,31 @@ ide_configuration_set_device (IdeConfiguration *self,
   g_return_if_fail (IDE_IS_CONFIGURATION (self));
   g_return_if_fail (IDE_IS_DEVICE (device));
 
-  g_set_object (&self->device, device);
+  ide_configuration_set_device_id (self, ide_device_get_id (device));
+}
+
+const gchar *
+ide_configuration_get_runtime_id (IdeConfiguration *self)
+{
+  g_return_val_if_fail (IDE_IS_CONFIGURATION (self), NULL);
+
+  return self->runtime_id;
+}
+
+static void
+ide_configuration_set_runtime_id (IdeConfiguration *self,
+                                  const gchar      *runtime_id)
+{
+  g_return_if_fail (IDE_IS_CONFIGURATION (self));
+  g_return_if_fail (runtime_id != NULL);
+
+  if (g_strcmp0 (runtime_id, self->runtime_id) != 0)
+    {
+      g_free (self->runtime_id);
+      self->runtime_id = g_strdup (runtime_id);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUNTIME_ID]);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUNTIME]);
+    }
 }
 
 /**
@@ -233,14 +445,20 @@ ide_configuration_set_device (IdeConfiguration *self,
  *
  * Gets the runtime for the configuration.
  *
- * Returns: (transfer none): An #ideRuntime
+ * Returns: (transfer none) (nullable): An #IdeRuntime
  */
 IdeRuntime *
 ide_configuration_get_runtime (IdeConfiguration *self)
 {
+  IdeRuntimeManager *runtime_manager;
+  IdeContext *context;
+
   g_return_val_if_fail (IDE_IS_CONFIGURATION (self), NULL);
 
-  return self->runtime;
+  context = ide_object_get_context (IDE_OBJECT (self));
+  runtime_manager = ide_context_get_runtime_manager (context);
+
+  return ide_runtime_manager_get_runtime (runtime_manager, self->runtime_id);
 }
 
 static void
@@ -250,67 +468,33 @@ ide_configuration_set_runtime (IdeConfiguration *self,
   g_return_if_fail (IDE_IS_CONFIGURATION (self));
   g_return_if_fail (IDE_IS_RUNTIME (runtime));
 
-  g_set_object (&self->runtime, runtime);
+  ide_configuration_set_runtime_id (self, ide_runtime_get_id (runtime));
 }
 
-const gchar * const *
+/**
+ * ide_configuration_get_environ:
+ * @self: An #IdeConfiguration
+ *
+ * Gets the environment to use when spawning processes.
+ *
+ * Returns: (transfer full): An array of key=value environment variables.
+ */
+gchar **
 ide_configuration_get_environ (IdeConfiguration *self)
 {
   g_return_val_if_fail (IDE_IS_CONFIGURATION (self), NULL);
 
-  return (const gchar * const *)self->environ->pdata;
-}
-
-static gint
-ide_configuration_find_env (IdeConfiguration *self,
-                            const gchar      *key)
-{
-  g_assert (IDE_IS_CONFIGURATION (self));
-  g_assert (key != NULL);
-
-  for (gint i = 0; i < self->environ->len; i++)
-    {
-      const gchar *pair = g_ptr_array_index (self->environ, i);
-      const gchar *eq;
-
-      if (pair == NULL)
-        break;
-
-      if (NULL == (eq = strchr (pair, '=')))
-        {
-          if (strcmp (pair, key) == 0)
-            return i;
-          return -1;
-        }
-
-      if (strncmp (eq, key, (eq - pair)) == 0)
-        return i;
-    }
-
-  return -1;
+  return ide_environ_get (self->environ);
 }
 
 const gchar *
 ide_configuration_getenv (IdeConfiguration *self,
                           const gchar      *key)
 {
-  gint i;
-
   g_return_val_if_fail (IDE_IS_CONFIGURATION (self), NULL);
   g_return_val_if_fail (key != NULL, NULL);
 
-  i = ide_configuration_find_env (self, key);
-
-  if (i >= 0)
-    {
-      const gchar *pair = g_ptr_array_index (self->environ, i);
-      const gchar *eq = strchr (pair, '=');
-
-      if (eq != NULL)
-        return eq + 1;
-    }
-
-  return NULL;
+  return ide_environ_getenv (self->environ, key);
 }
 
 void
@@ -318,30 +502,10 @@ ide_configuration_setenv (IdeConfiguration *self,
                           const gchar      *key,
                           const gchar      *value)
 {
-  gint i;
-
-  g_assert (IDE_IS_CONFIGURATION (self));
-  g_assert (key != NULL);
-
-  i = ide_configuration_find_env (self, key);
+  g_return_if_fail (IDE_IS_CONFIGURATION (self));
+  g_return_if_fail (key != NULL);
 
-  if (i >= 0)
-    {
-      if (value == NULL)
-        {
-          g_ptr_array_remove_index (self->environ, i);
-        }
-      else
-        {
-          g_free (g_ptr_array_index (self->environ, i));
-          g_ptr_array_index (self->environ, i) = g_strdup (value);
-        }
-    }
-  else
-    {
-      g_ptr_array_index (self->environ, self->environ->len) = g_strdup_printf ("%s=%s", key, value);
-      g_ptr_array_add (self->environ, NULL);
-    }
+  ide_environ_setenv (self->environ, key, value);
 }
 
 const gchar *
@@ -366,3 +530,71 @@ ide_configuration_set_id (IdeConfiguration *self,
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ID]);
     }
 }
+
+const gchar *
+ide_configuration_get_prefix (IdeConfiguration *self)
+{
+  g_return_val_if_fail (IDE_IS_CONFIGURATION (self), NULL);
+
+  return self->prefix;
+}
+
+void
+ide_configuration_set_prefix (IdeConfiguration *self,
+                              const gchar      *prefix)
+{
+  g_return_if_fail (IDE_IS_CONFIGURATION (self));
+  g_return_if_fail (prefix != NULL);
+
+  if (g_strcmp0 (prefix, self->prefix) != 0)
+    {
+      g_free (self->prefix);
+      self->prefix = g_strdup (prefix);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PREFIX]);
+    }
+}
+
+gint
+ide_configuration_get_parallelism (IdeConfiguration *self)
+{
+  g_return_val_if_fail (IDE_IS_CONFIGURATION (self), -1);
+
+  return self->parallelism;
+}
+
+void
+ide_configuration_set_parallelism (IdeConfiguration *self,
+                                   gint              parallelism)
+{
+  g_return_if_fail (IDE_IS_CONFIGURATION (self));
+  g_return_if_fail (parallelism >= -1);
+
+  if (parallelism != self->parallelism)
+    {
+      self->parallelism = parallelism;
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PARALLELISM]);
+    }
+}
+
+gboolean
+ide_configuration_get_debug (IdeConfiguration *self)
+{
+  g_return_val_if_fail (IDE_IS_CONFIGURATION (self), FALSE);
+
+  return self->debug;
+}
+
+void
+ide_configuration_set_debug (IdeConfiguration *self,
+                             gboolean          debug)
+{
+  g_return_if_fail (IDE_IS_CONFIGURATION (self));
+
+  debug = !!debug;
+
+  if (debug != self->debug)
+    {
+      self->debug = debug;
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DEBUG]);
+    }
+}
diff --git a/libide/ide-configuration.h b/libide/ide-configuration.h
index 2953cf1..8fbb698 100644
--- a/libide/ide-configuration.h
+++ b/libide/ide-configuration.h
@@ -30,21 +30,34 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeConfiguration, ide_configuration, IDE, CONFIGURATION, IdeObject)
 
-IdeConfiguration    *ide_configuration_new              (const gchar       *id,
-                                                         IdeDevice         *device,
-                                                         IdeRuntime        *runtime);
+IdeConfiguration    *ide_configuration_new              (IdeContext        *context,
+                                                         const gchar       *id,
+                                                         const gchar       *device_id,
+                                                         const gchar       *runtime_id);
 const gchar         *ide_configuration_get_id           (IdeConfiguration  *self);
+const gchar         *ide_configuration_get_runtime_id   (IdeConfiguration  *self);
+const gchar         *ide_configuration_get_device_id    (IdeConfiguration  *self);
 const gchar         *ide_configuration_get_display_name (IdeConfiguration  *self);
 void                 ide_configuration_set_display_name (IdeConfiguration  *self,
                                                          const gchar       *display_name);
 IdeRuntime          *ide_configuration_get_runtime      (IdeConfiguration  *self);
 IdeDevice           *ide_configuration_get_device       (IdeConfiguration  *self);
-const gchar * const *ide_configuration_get_environ      (IdeConfiguration  *self);
+
+gchar              **ide_configuration_get_environ      (IdeConfiguration  *self);
 const gchar         *ide_configuration_getenv           (IdeConfiguration  *self,
                                                          const gchar       *key);
 void                 ide_configuration_setenv           (IdeConfiguration  *self,
                                                          const gchar       *key,
                                                          const gchar       *value);
+gboolean             ide_configuration_get_debug        (IdeConfiguration  *self);
+void                 ide_configuration_set_debug        (IdeConfiguration  *self,
+                                                         gboolean           debug);
+const gchar         *ide_configuration_get_prefix       (IdeConfiguration  *self);
+void                 ide_configuration_set_prefix       (IdeConfiguration  *self,
+                                                         const gchar       *prefix);
+gint                 ide_configuration_get_parallelism  (IdeConfiguration  *self);
+void                 ide_configuration_set_parallelism  (IdeConfiguration  *self,
+                                                         gint               parallelism);
 
 G_END_DECLS
 
diff --git a/libide/ide-context.c b/libide/ide-context.c
index 8f1b673..6f9a041 100644
--- a/libide/ide-context.c
+++ b/libide/ide-context.c
@@ -27,6 +27,7 @@
 #include "ide-buffer-manager.h"
 #include "ide-buffer.h"
 #include "ide-build-system.h"
+#include "ide-configuration-manager.h"
 #include "ide-context.h"
 #include "ide-debug.h"
 #include "ide-device-manager.h"
@@ -58,6 +59,7 @@ struct _IdeContext
   IdeBackForwardList       *back_forward_list;
   IdeBufferManager         *buffer_manager;
   IdeBuildSystem           *build_system;
+  IdeConfigurationManager  *configuration_manager;
   IdeDeviceManager         *device_manager;
   IdeDoap                  *doap;
   GtkRecentManager         *recent_manager;
@@ -534,6 +536,7 @@ ide_context_finalize (GObject *object)
   g_clear_pointer (&self->recent_projects_path, g_free);
 
   g_clear_object (&self->build_system);
+  g_clear_object (&self->configuration_manager);
   g_clear_object (&self->device_manager);
   g_clear_object (&self->doap);
   g_clear_object (&self->project);
@@ -797,6 +800,10 @@ ide_context_init (IdeContext *self)
                                        "context", self,
                                        NULL);
 
+  self->configuration_manager = g_object_new (IDE_TYPE_CONFIGURATION_MANAGER,
+                                              "context", self,
+                                              NULL);
+
   self->project = g_object_new (IDE_TYPE_PROJECT,
                                 "context", self,
                                 NULL);
@@ -1357,6 +1364,44 @@ ide_context_init_search_engine (gpointer             source_object,
 }
 
 static void
+ide_context_init_configuration_manager_cb (GObject      *object,
+                                           GAsyncResult *result,
+                                           gpointer      user_data)
+{
+  GAsyncInitable *initable = (GAsyncInitable *)object;
+  g_autoptr(GTask) task = user_data;
+  GError *error = NULL;
+
+  g_assert (G_IS_ASYNC_INITABLE (initable));
+  g_assert (G_IS_ASYNC_RESULT (result));
+
+  if (!g_async_initable_init_finish (initable, result, &error))
+    g_task_return_error (task, error);
+  else
+    g_task_return_boolean (task, TRUE);
+}
+
+static void
+ide_context_init_configuration_manager (gpointer             source_object,
+                                        GCancellable        *cancellable,
+                                        GAsyncReadyCallback  callback,
+                                        gpointer             user_data)
+{
+  IdeContext *self = source_object;
+  g_autoptr(GTask) task = NULL;
+
+  g_assert (IDE_IS_CONTEXT (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_async_initable_init_async (G_ASYNC_INITABLE (self->configuration_manager),
+                               G_PRIORITY_DEFAULT,
+                               cancellable,
+                               ide_context_init_configuration_manager_cb,
+                               g_object_ref (task));
+}
+
+static void
 ide_context_init_loaded (gpointer             source_object,
                          GCancellable        *cancellable,
                          GAsyncReadyCallback  callback,
@@ -1400,6 +1445,7 @@ ide_context_init_async (GAsyncInitable      *initable,
                         ide_context_init_unsaved_files,
                         ide_context_init_add_recent,
                         ide_context_init_search_engine,
+                        ide_context_init_configuration_manager,
                         ide_context_init_loaded,
                         NULL);
 }
@@ -1957,3 +2003,43 @@ ide_context_get_runtime_manager (IdeContext *self)
 
   return self->runtime_manager;
 }
+
+/**
+ * ide_context_get_configuration_manager:
+ * @self: An #IdeContext
+ *
+ * Gets the #IdeConfigurationManager for the context.
+ *
+ * The configuration manager is responsible for loading and saving
+ * configurations. Configurations consist of information about how to
+ * perform a particular build. Such information includes the target
+ * #IdeDevice, the #IdeRuntime to use, and various other build options.
+ *
+ * Returns: (transfer none): An #IdeConfigurationManager.
+ */
+IdeConfigurationManager *
+ide_context_get_configuration_manager (IdeContext *self)
+{
+  g_return_val_if_fail (IDE_IS_CONTEXT (self), NULL);
+
+  return self->configuration_manager;
+}
+
+void
+ide_context_warning (IdeContext  *self,
+                     const gchar *format,
+                     ...)
+{
+  va_list args;
+
+  g_return_if_fail (IDE_IS_CONTEXT (self));
+  g_return_if_fail (format != NULL);
+
+  va_start (args, format);
+  /*
+   * TODO: Track logging information so that we can display warnings
+   *       to the user in the workbench.
+   */
+  g_logv ("Ide", G_LOG_LEVEL_WARNING, format, args);
+  va_end (args);
+}
diff --git a/libide/ide-context.h b/libide/ide-context.h
index d1c6604..31d9158 100644
--- a/libide/ide-context.h
+++ b/libide/ide-context.h
@@ -30,51 +30,55 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeContext, ide_context, IDE, CONTEXT, GObject)
 
-IdeBackForwardList       *ide_context_get_back_forward_list (IdeContext           *self);
-GFile                    *ide_context_get_project_file      (IdeContext           *self);
-IdeBufferManager         *ide_context_get_buffer_manager    (IdeContext           *self);
-IdeBuildSystem           *ide_context_get_build_system      (IdeContext           *self);
-IdeDeviceManager         *ide_context_get_device_manager    (IdeContext           *self);
-IdeProject               *ide_context_get_project           (IdeContext           *self);
-GtkRecentManager         *ide_context_get_recent_manager    (IdeContext           *self);
-IdeRuntimeManager        *ide_context_get_runtime_manager   (IdeContext           *self);
-IdeScriptManager         *ide_context_get_script_manager    (IdeContext           *self);
-IdeSearchEngine          *ide_context_get_search_engine     (IdeContext           *self);
-IdeSettings              *ide_context_get_settings          (IdeContext           *self,
-                                                             const gchar          *schema_id,
-                                                             const gchar          *relative_path);
-IdeSourceSnippetsManager *ide_context_get_snippets_manager  (IdeContext           *self);
-IdeUnsavedFiles          *ide_context_get_unsaved_files     (IdeContext           *self);
-IdeVcs                   *ide_context_get_vcs               (IdeContext           *self);
-const gchar              *ide_context_get_root_build_dir    (IdeContext           *self);
-gpointer                  ide_context_get_service_typed     (IdeContext           *self,
-                                                             GType                 service_type);
-void                      ide_context_unload_async          (IdeContext           *self,
-                                                             GCancellable         *cancellable,
-                                                             GAsyncReadyCallback   callback,
-                                                             gpointer              user_data);
-gboolean                  ide_context_unload_finish         (IdeContext           *self,
-                                                             GAsyncResult         *result,
-                                                             GError              **error);
-void                      ide_context_new_async             (GFile                *project_file,
-                                                             GCancellable         *cancellable,
-                                                             GAsyncReadyCallback   callback,
-                                                             gpointer              user_data);
-IdeContext               *ide_context_new_finish            (GAsyncResult         *result,
-                                                             GError              **error);
-void                      ide_context_set_root_build_dir    (IdeContext           *self,
-                                                             const gchar          *root_build_dir);
-void                      ide_context_restore_async         (IdeContext           *self,
-                                                             GCancellable         *cancellable,
-                                                             GAsyncReadyCallback   callback,
-                                                             gpointer              user_data);
-gboolean                  ide_context_restore_finish        (IdeContext           *self,
-                                                             GAsyncResult         *result,
-                                                             GError              **error);
-void                      ide_context_hold                  (IdeContext           *self);
-void                      ide_context_hold_for_object       (IdeContext           *self,
-                                                             gpointer              instance);
-void                      ide_context_release               (IdeContext           *self);
+IdeBackForwardList       *ide_context_get_back_forward_list     (IdeContext           *self);
+GFile                    *ide_context_get_project_file          (IdeContext           *self);
+IdeBufferManager         *ide_context_get_buffer_manager        (IdeContext           *self);
+IdeBuildSystem           *ide_context_get_build_system          (IdeContext           *self);
+IdeConfigurationManager  *ide_context_get_configuration_manager (IdeContext           *self);
+IdeDeviceManager         *ide_context_get_device_manager        (IdeContext           *self);
+IdeProject               *ide_context_get_project               (IdeContext           *self);
+GtkRecentManager         *ide_context_get_recent_manager        (IdeContext           *self);
+IdeRuntimeManager        *ide_context_get_runtime_manager       (IdeContext           *self);
+IdeScriptManager         *ide_context_get_script_manager        (IdeContext           *self);
+IdeSearchEngine          *ide_context_get_search_engine         (IdeContext           *self);
+IdeSettings              *ide_context_get_settings              (IdeContext           *self,
+                                                                 const gchar          *schema_id,
+                                                                 const gchar          *relative_path);
+IdeSourceSnippetsManager *ide_context_get_snippets_manager      (IdeContext           *self);
+IdeUnsavedFiles          *ide_context_get_unsaved_files         (IdeContext           *self);
+IdeVcs                   *ide_context_get_vcs                   (IdeContext           *self);
+const gchar              *ide_context_get_root_build_dir        (IdeContext           *self);
+gpointer                  ide_context_get_service_typed         (IdeContext           *self,
+                                                                 GType                 service_type);
+void                      ide_context_unload_async              (IdeContext           *self,
+                                                                 GCancellable         *cancellable,
+                                                                 GAsyncReadyCallback   callback,
+                                                                 gpointer              user_data);
+gboolean                  ide_context_unload_finish             (IdeContext           *self,
+                                                                 GAsyncResult         *result,
+                                                                 GError              **error);
+void                      ide_context_new_async                 (GFile                *project_file,
+                                                                 GCancellable         *cancellable,
+                                                                 GAsyncReadyCallback   callback,
+                                                                 gpointer              user_data);
+IdeContext               *ide_context_new_finish                (GAsyncResult         *result,
+                                                                 GError              **error);
+void                      ide_context_set_root_build_dir        (IdeContext           *self,
+                                                                 const gchar          *root_build_dir);
+void                      ide_context_restore_async             (IdeContext           *self,
+                                                                 GCancellable         *cancellable,
+                                                                 GAsyncReadyCallback   callback,
+                                                                 gpointer              user_data);
+gboolean                  ide_context_restore_finish            (IdeContext           *self,
+                                                                 GAsyncResult         *result,
+                                                                 GError              **error);
+void                      ide_context_hold                      (IdeContext           *self);
+void                      ide_context_hold_for_object           (IdeContext           *self,
+                                                                 gpointer              instance);
+void                      ide_context_release                   (IdeContext           *self);
+void                      ide_context_warning                   (IdeContext           *self,
+                                                                 const gchar          *format,
+                                                                 ...) G_GNUC_PRINTF (2, 3);
 
 G_END_DECLS
 
diff --git a/libide/ide-device.h b/libide/ide-device.h
index 484e655..595436c 100644
--- a/libide/ide-device.h
+++ b/libide/ide-device.h
@@ -20,6 +20,7 @@
 #define IDE_DEVICE_H
 
 #include "ide-object.h"
+#include "ide-types.h"
 
 G_BEGIN_DECLS
 
diff --git a/libide/ide-environ.c b/libide/ide-environ.c
new file mode 100644
index 0000000..48f37dd
--- /dev/null
+++ b/libide/ide-environ.c
@@ -0,0 +1,184 @@
+/* ide-environ.c
+ *
+ * Copyright (C) 2016 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 "ide-environ"
+
+#include <string.h>
+
+#include "ide-environ.h"
+
+struct _IdeEnviron
+{
+  volatile gint  ref_count;
+  IdeEnviron    *parent;
+  GPtrArray     *env;
+};
+
+IdeEnviron *
+ide_environ_new (IdeEnviron *parent)
+{
+  IdeEnviron *self;
+
+  self = g_slice_new0 (IdeEnviron);
+  self->ref_count = 1;
+  self->parent = parent ? ide_environ_ref (parent) : NULL;
+  self->env = g_ptr_array_new_with_free_func (g_free);
+
+  return self;
+}
+
+IdeEnviron *
+ide_environ_ref (IdeEnviron *self)
+{
+  g_return_val_if_fail (self != NULL, NULL);
+  g_return_val_if_fail (self->ref_count > 0, NULL);
+
+  g_atomic_int_inc (&self->ref_count);
+
+  return self;
+}
+
+void
+ide_environ_unref (IdeEnviron *self)
+{
+  g_return_if_fail (self != NULL);
+  g_return_if_fail (self->ref_count > 0);
+
+  if (g_atomic_int_dec_and_test (&self->ref_count))
+    {
+      g_clear_pointer (&self->parent, ide_environ_unref);
+      g_clear_pointer (&self->env, g_ptr_array_unref);
+      g_slice_free (IdeEnviron, self);
+    }
+}
+
+const gchar *
+ide_environ_getenv (IdeEnviron  *self,
+                    const gchar *key)
+{
+  g_return_val_if_fail (self != NULL, NULL);
+  g_return_val_if_fail (key != NULL, NULL);
+
+  for (guint i = 0; i < self->env->len; i++)
+    {
+      const gchar *pair = g_ptr_array_index (self->env, i);
+      const gchar *eq = strchr (pair, '=');
+
+      if (eq == NULL)
+        {
+          g_assert_not_reached ();
+          continue;
+        }
+
+      if (strncmp (key, pair, eq - pair) == 0)
+        return eq + 1;
+    }
+
+  if (self->parent != NULL)
+    return ide_environ_getenv (self->parent, key);
+
+  return NULL;
+}
+
+void
+ide_environ_setenv (IdeEnviron  *self,
+                    const gchar *key,
+                    const gchar *value)
+{
+  g_return_if_fail (self != NULL);
+  g_return_if_fail (key != NULL);
+
+  for (guint i = 0; i < self->env->len; i++)
+    {
+      gchar *pair = g_ptr_array_index (self->env, i);
+      const gchar *eq = strchr (pair, '=');
+
+      if (eq == NULL)
+        {
+          g_assert_not_reached ();
+          continue;
+        }
+
+      if (strncmp (key, pair, eq - pair) == 0)
+        {
+          if (value == NULL)
+            {
+              g_ptr_array_remove_index (self->env, i);
+            }
+          else
+            {
+              g_ptr_array_index (self->env, i) = g_strdup_printf ("%s=%s", key, value);
+              g_free (pair);
+            }
+        }
+    }
+
+  if (value != NULL)
+    g_ptr_array_add (self->env, g_strdup_printf ("%s=%s", key, value));
+}
+
+void
+ide_environ_reset (IdeEnviron *self)
+{
+  g_return_if_fail (self != NULL);
+
+  if (self->env->len > 0)
+    g_ptr_array_remove_range (self->env, 0, self->env->len);
+}
+
+
+static void
+ide_environ_get_internal (IdeEnviron *self,
+                          GPtrArray  *ar)
+{
+  g_assert (self != NULL);
+  g_assert (ar != NULL);
+
+  if (self->parent != NULL)
+    ide_environ_get_internal (self->parent, ar);
+
+  for (guint i = 0; i < self->env->len; i++)
+    {
+      const gchar *pair = g_ptr_array_index (self->env, i);
+
+      g_ptr_array_add (ar, g_strdup (pair));
+    }
+}
+
+/**
+ * ide_environ_get:
+ * @self: An #IdeEnviron
+ *
+ * Gets the environment as suitable for passing to various GLib systems
+ * such as GSubprocess and g_spawn_async().
+ *
+ * Returns: (transfer full): A newly allocated string array.
+ */
+gchar **
+ide_environ_get (IdeEnviron *self)
+{
+  GPtrArray *ar;
+
+  g_return_val_if_fail (self != NULL, NULL);
+
+  ar = g_ptr_array_new ();
+  ide_environ_get_internal (self, ar);
+  g_ptr_array_add (ar, NULL);
+
+  return (gchar **)g_ptr_array_free (ar, FALSE);
+}
diff --git a/libide/ide-environ.h b/libide/ide-environ.h
new file mode 100644
index 0000000..1bd5116
--- /dev/null
+++ b/libide/ide-environ.h
@@ -0,0 +1,41 @@
+/* ide-environ.h
+ *
+ * Copyright (C) 2016 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/>.
+ */
+
+#ifndef IDE_ENVIRON_H
+#define IDE_ENVIRON_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _IdeEnviron IdeEnviron;
+
+IdeEnviron   *ide_environ_new    (IdeEnviron  *parent);
+IdeEnviron   *ide_environ_ref    (IdeEnviron  *self);
+void          ide_environ_unref  (IdeEnviron  *self);
+const gchar  *ide_environ_getenv (IdeEnviron  *self,
+                                  const gchar *key);
+void          ide_environ_setenv (IdeEnviron  *self,
+                                  const gchar *key,
+                                  const gchar *value);
+gchar        **ide_environ_get   (IdeEnviron  *self);
+void           ide_environ_reset (IdeEnviron  *self);
+
+G_END_DECLS
+
+#endif /* IDE_ENVIRON_H */
diff --git a/libide/ide-runtime.c b/libide/ide-runtime.c
index e664460..d9c2ce2 100644
--- a/libide/ide-runtime.c
+++ b/libide/ide-runtime.c
@@ -95,7 +95,8 @@ static IdeSubprocessLauncher *
 ide_runtime_real_create_launcher (IdeRuntime  *self,
                                   GError     **error)
 {
-  return ide_subprocess_launcher_new (0);
+  return ide_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE |
+                                      G_SUBPROCESS_FLAGS_STDERR_PIPE);
 }
 
 static gboolean
diff --git a/libide/ide-types.h b/libide/ide-types.h
index 857df5f..eced85f 100644
--- a/libide/ide-types.h
+++ b/libide/ide-types.h
@@ -42,6 +42,7 @@ typedef struct _IdeBuildResult                 IdeBuildResult;
 typedef struct _IdeBuildSystem                 IdeBuildSystem;
 
 typedef struct _IdeConfiguration               IdeConfiguration;
+typedef struct _IdeConfigurationManager        IdeConfigurationManager;
 
 typedef struct _IdeContext                     IdeContext;
 
@@ -51,9 +52,7 @@ typedef struct _IdeDebuggerInterface           IdeDebuggerInterface;
 typedef struct _IdeDeployer                    IdeDeployer;
 
 typedef struct _IdeDevice                      IdeDevice;
-
 typedef struct _IdeDeviceManager               IdeDeviceManager;
-
 typedef struct _IdeDeviceProvider              IdeDeviceProvider;
 
 typedef struct _IdeDiagnostic                  IdeDiagnostic;
@@ -102,6 +101,7 @@ typedef struct _IdeRefactoryInterface          IdeRefactoryInterface;
 
 typedef struct _IdeRuntime                     IdeRuntime;
 typedef struct _IdeRuntimeManager              IdeRuntimeManager;
+typedef struct _IdeRuntimeProvider             IdeRuntimeProvider;
 
 typedef struct _IdeScript                      IdeScript;
 
diff --git a/libide/ide.h b/libide/ide.h
index f05767a..02ecbbd 100644
--- a/libide/ide.h
+++ b/libide/ide.h
@@ -25,6 +25,8 @@ G_BEGIN_DECLS
 
 #define IDE_INSIDE
 
+#include "ide-types.h"
+
 #include "ide-application.h"
 #include "ide-application-addin.h"
 #include "ide-application-tool.h"
@@ -40,6 +42,8 @@ G_BEGIN_DECLS
 #include "ide-completion-item.h"
 #include "ide-completion-provider.h"
 #include "ide-completion-results.h"
+#include "ide-configuration.h"
+#include "ide-configuration-manager.h"
 #include "ide-context.h"
 #include "ide-debug.h"
 #include "ide-debugger.h"
diff --git a/plugins/autotools/ide-autotools-build-system.c b/plugins/autotools/ide-autotools-build-system.c
index adaf9a9..548a49e 100644
--- a/plugins/autotools/ide-autotools-build-system.c
+++ b/plugins/autotools/ide-autotools-build-system.c
@@ -32,6 +32,7 @@
 #include "ide-autotools-build-system.h"
 #include "ide-autotools-builder.h"
 #include "ide-buffer-manager.h"
+#include "ide-configuration.h"
 #include "ide-context.h"
 #include "ide-debug.h"
 #include "ide-device.h"
@@ -218,10 +219,6 @@ ide_autotools_build_system_get_local_makefile_async (IdeAutotoolsBuildSystem *se
                                                      gpointer                 user_data)
 {
   IdeContext *context;
-  IdeDeviceManager *device_manager;
-  IdeDevice *device;
-  IdeRuntimeManager *runtime_manager;
-  IdeRuntime *runtime;
   g_autoptr(IdeConfiguration) configuration = NULL;
   g_autoptr(GTask) task = NULL;
   g_autoptr(IdeBuilder) builder = NULL;
@@ -236,13 +233,7 @@ ide_autotools_build_system_get_local_makefile_async (IdeAutotoolsBuildSystem *se
 
   context = ide_object_get_context (IDE_OBJECT (self));
 
-  device_manager = ide_context_get_device_manager (context);
-  device = ide_device_manager_get_device (device_manager, "local");
-
-  runtime_manager = ide_context_get_runtime_manager (context);
-  runtime = ide_runtime_manager_get_runtime (runtime_manager, "system");
-
-  configuration = ide_configuration_new ("autotools-bootstrap", device, runtime);
+  configuration = ide_configuration_new (context, "autotools-bootstrap", "local", "system");
 
   builder = ide_autotools_build_system_get_builder (IDE_BUILD_SYSTEM (self), configuration, &error);
 
@@ -831,17 +822,23 @@ simple_make_command_cb (GObject      *object,
 }
 
 static void
-simple_make_command (GFile       *directory,
-                     const gchar *target,
-                     GTask       *task)
+simple_make_command (GFile            *directory,
+                     const gchar      *target,
+                     GTask            *task,
+                     IdeConfiguration *configuration)
 {
-  g_autoptr(GSubprocessLauncher) launcher = NULL;
+  g_autoptr(IdeSubprocessLauncher) launcher = NULL;
   g_autoptr(GSubprocess) subprocess = NULL;
+  GCancellable *cancellable;
+  IdeRuntime *runtime;
   GError *error = NULL;
 
   g_assert (G_IS_FILE (directory));
   g_assert (target != NULL);
   g_assert (G_IS_TASK (task));
+  g_assert (IDE_IS_CONFIGURATION (configuration));
+
+  cancellable = g_task_get_cancellable (task);
 
   if (!g_file_is_native (directory))
     {
@@ -852,12 +849,29 @@ simple_make_command (GFile       *directory,
       return;
     }
 
-  launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDERR_SILENCE |
-                                        G_SUBPROCESS_FLAGS_STDOUT_SILENCE);
-  g_subprocess_launcher_set_cwd (launcher, g_file_get_path (directory));
+  if (NULL == (runtime = ide_configuration_get_runtime (configuration)))
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_NOT_FOUND,
+                               "Failed to locate runtime");
+      return;
+    }
+
+  if (NULL == (launcher = ide_runtime_create_launcher (runtime, &error)))
+    {
+      g_task_return_error (task, error);
+      return;
+    }
+
+  ide_subprocess_launcher_set_cwd (launcher, g_file_get_path (directory));
 
-  subprocess = g_subprocess_launcher_spawn (launcher, &error, GNU_MAKE_NAME, target, NULL);
-  if (subprocess == NULL)
+  if (ide_runtime_contains_program_in_path (runtime, "gmake", cancellable))
+    ide_subprocess_launcher_push_argv (launcher, "gmake");
+  else
+    ide_subprocess_launcher_push_argv (launcher, "make");
+
+  if (NULL == (subprocess = ide_subprocess_launcher_spawn_sync (launcher, cancellable, &error)))
     {
       g_task_return_error (task, error);
       return;
@@ -870,28 +884,35 @@ simple_make_command (GFile       *directory,
 }
 
 static void
-ide_autotools_build_system_build_async (IdeTagsBuilder      *builder,
-                                        GFile               *file_or_directory,
-                                        gboolean             recursive,
-                                        GCancellable        *cancellable,
-                                        GAsyncReadyCallback  callback,
-                                        gpointer             user_data)
+ide_autotools_build_system_tags_build_async (IdeTagsBuilder      *builder,
+                                             GFile               *file_or_directory,
+                                             gboolean             recursive,
+                                             GCancellable        *cancellable,
+                                             GAsyncReadyCallback  callback,
+                                             gpointer             user_data)
 {
   IdeAutotoolsBuildSystem *self = (IdeAutotoolsBuildSystem *)builder;
+  IdeConfigurationManager *config_manager;
+  IdeConfiguration *configuration;
+  IdeContext *context;
   g_autoptr(GTask) task = NULL;
 
-  g_return_if_fail (IDE_IS_AUTOTOOLS_BUILD_SYSTEM (self));
-  g_return_if_fail (G_IS_FILE (file_or_directory));
-  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+  g_assert (IDE_IS_AUTOTOOLS_BUILD_SYSTEM (self));
+  g_assert (G_IS_FILE (file_or_directory));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  config_manager = ide_context_get_configuration_manager (context);
+  configuration = ide_configuration_manager_get_current (config_manager);
 
   task = g_task_new (self, cancellable, callback, user_data);
-  simple_make_command (file_or_directory, "ctags", task);
+  simple_make_command (file_or_directory, "ctags", task, configuration);
 }
 
 static gboolean
-ide_autotools_build_system_build_finish (IdeTagsBuilder  *builder,
-                                         GAsyncResult    *result,
-                                         GError         **error)
+ide_autotools_build_system_tags_build_finish (IdeTagsBuilder  *builder,
+                                              GAsyncResult    *result,
+                                              GError         **error)
 {
   IdeAutotoolsBuildSystem *self = (IdeAutotoolsBuildSystem *)builder;
   GTask *task = (GTask *)result;
@@ -905,6 +926,6 @@ ide_autotools_build_system_build_finish (IdeTagsBuilder  *builder,
 static void
 tags_builder_iface_init (IdeTagsBuilderInterface *iface)
 {
-  iface->build_async = ide_autotools_build_system_build_async;
-  iface->build_finish = ide_autotools_build_system_build_finish;
+  iface->build_async = ide_autotools_build_system_tags_build_async;
+  iface->build_finish = ide_autotools_build_system_tags_build_finish;
 }
diff --git a/plugins/autotools/ide-autotools-build-task.c b/plugins/autotools/ide-autotools-build-task.c
index 10329c4..66de8a1 100644
--- a/plugins/autotools/ide-autotools-build-task.c
+++ b/plugins/autotools/ide-autotools-build-task.c
@@ -28,14 +28,16 @@
 
 #include "ide-autotools-build-task.h"
 
-typedef struct
+struct _IdeAutotoolsBuildTask
 {
+  IdeObject         parent_instance;
   IdeConfiguration *configuration;
   GFile            *directory;
+  GPtrArray        *extra_targets;
   guint             require_autogen : 1;
   guint             require_configure : 1;
   guint             executed : 1;
-} IdeAutotoolsBuildTaskPrivate;
+};
 
 typedef struct
 {
@@ -56,8 +58,7 @@ typedef gboolean (*WorkStep) (GTask                 *task,
                               WorkerState           *state,
                               GCancellable          *cancellable);
 
-G_DEFINE_TYPE_WITH_PRIVATE (IdeAutotoolsBuildTask, ide_autotools_build_task,
-                            IDE_TYPE_BUILD_RESULT)
+G_DEFINE_TYPE (IdeAutotoolsBuildTask, ide_autotools_build_task, IDE_TYPE_BUILD_RESULT)
 
 enum {
   PROP_0,
@@ -100,53 +101,37 @@ static WorkStep workSteps [] = {
 };
 
 gboolean
-ide_autotools_build_task_get_require_autogen (IdeAutotoolsBuildTask *task)
+ide_autotools_build_task_get_require_autogen (IdeAutotoolsBuildTask *self)
 {
-  IdeAutotoolsBuildTaskPrivate *priv;
-
-  g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (task), FALSE);
-
-  priv = ide_autotools_build_task_get_instance_private (task);
+  g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self), FALSE);
 
-  return priv->require_autogen;
+  return self->require_autogen;
 }
 
 static void
-ide_autotools_build_task_set_require_autogen (IdeAutotoolsBuildTask *task,
+ide_autotools_build_task_set_require_autogen (IdeAutotoolsBuildTask *self,
                                               gboolean               require_autogen)
 {
-  IdeAutotoolsBuildTaskPrivate *priv;
-
-  g_return_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (task));
-
-  priv = ide_autotools_build_task_get_instance_private (task);
+  g_return_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self));
 
-  priv->require_autogen = !!require_autogen;
+  self->require_autogen = !!require_autogen;
 }
 
 gboolean
-ide_autotools_build_task_get_require_configure (IdeAutotoolsBuildTask *task)
+ide_autotools_build_task_get_require_configure (IdeAutotoolsBuildTask *self)
 {
-  IdeAutotoolsBuildTaskPrivate *priv;
-
-  g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (task), FALSE);
-
-  priv = ide_autotools_build_task_get_instance_private (task);
+  g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self), FALSE);
 
-  return priv->require_configure;
+  return self->require_configure;
 }
 
 static void
-ide_autotools_build_task_set_require_configure (IdeAutotoolsBuildTask *task,
+ide_autotools_build_task_set_require_configure (IdeAutotoolsBuildTask *self,
                                                 gboolean               require_configure)
 {
-  IdeAutotoolsBuildTaskPrivate *priv;
-
-  g_return_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (task));
-
-  priv = ide_autotools_build_task_get_instance_private (task);
+  g_return_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self));
 
-  priv->require_autogen = !!require_configure;
+  self->require_autogen = !!require_configure;
 }
 
 /**
@@ -159,26 +144,18 @@ ide_autotools_build_task_set_require_configure (IdeAutotoolsBuildTask *task,
 GFile *
 ide_autotools_build_task_get_directory (IdeAutotoolsBuildTask *self)
 {
-  IdeAutotoolsBuildTaskPrivate *priv;
-
   g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self), NULL);
 
-  priv = ide_autotools_build_task_get_instance_private (self);
-
-  return priv->directory;
+  return self->directory;
 }
 
 static void
 ide_autotools_build_task_set_directory (IdeAutotoolsBuildTask *self,
                                         GFile                 *directory)
 {
-  IdeAutotoolsBuildTaskPrivate *priv;
-
   g_return_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self));
   g_return_if_fail (!directory || G_IS_FILE (directory));
 
-  priv = ide_autotools_build_task_get_instance_private (self);
-
   /*
    * We require a build directory that is accessable via a native path.
    */
@@ -195,8 +172,8 @@ ide_autotools_build_task_set_directory (IdeAutotoolsBuildTask *self,
         }
     }
 
-  if (priv->directory != directory)
-    if (g_set_object (&priv->directory, directory))
+  if (self->directory != directory)
+    if (g_set_object (&self->directory, directory))
       g_object_notify_by_pspec (G_OBJECT (self),
                                 properties [PROP_DIRECTORY]);
 }
@@ -210,23 +187,19 @@ ide_autotools_build_task_set_directory (IdeAutotoolsBuildTask *self,
 IdeConfiguration *
 ide_autotools_build_task_get_configuration (IdeAutotoolsBuildTask *self)
 {
-  IdeAutotoolsBuildTaskPrivate *priv = ide_autotools_build_task_get_instance_private (self);
-
   g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self), NULL);
 
-  return priv->configuration;
+  return self->configuration;
 }
 
 static void
 ide_autotools_build_task_set_configuration (IdeAutotoolsBuildTask *self,
                                             IdeConfiguration      *configuration)
 {
-  IdeAutotoolsBuildTaskPrivate *priv = ide_autotools_build_task_get_instance_private (self);
-
   g_assert (IDE_IS_AUTOTOOLS_BUILD_TASK (self));
   g_assert (IDE_IS_CONFIGURATION (configuration));
 
-  if (g_set_object (&priv->configuration, configuration))
+  if (g_set_object (&self->configuration, configuration))
     g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CONFIGURATION]);
 }
 
@@ -234,12 +207,9 @@ static void
 ide_autotools_build_task_finalize (GObject *object)
 {
   IdeAutotoolsBuildTask *self = (IdeAutotoolsBuildTask *)object;
-  IdeAutotoolsBuildTaskPrivate *priv;
 
-  priv = ide_autotools_build_task_get_instance_private (self);
-
-  g_clear_object (&priv->directory);
-  g_clear_object (&priv->configuration);
+  g_clear_object (&self->directory);
+  g_clear_object (&self->configuration);
 
   G_OBJECT_CLASS (ide_autotools_build_task_parent_class)->finalize (object);
 }
@@ -363,7 +333,6 @@ static gchar **
 gen_configure_argv (IdeAutotoolsBuildTask *self,
                     WorkerState           *state)
 {
-  IdeAutotoolsBuildTaskPrivate *priv = ide_autotools_build_task_get_instance_private (self);
   IdeDevice *device;
   GPtrArray *ar;
   const gchar *opts;
@@ -381,17 +350,17 @@ gen_configure_argv (IdeAutotoolsBuildTask *self,
   g_ptr_array_add (ar, configure_path);
 
   /* --prefix /app */
-  if (!(prefix = g_strdup (ide_configuration_getenv (priv->configuration, "PREFIX"))))
+  if (!(prefix = g_strdup (ide_configuration_getenv (self->configuration, "PREFIX"))))
     prefix = g_build_filename (state->project_path, "_install", NULL);
   g_ptr_array_add (ar, g_strdup_printf ("--prefix=%s", prefix));
   g_free (prefix);
 
   /* --host=triplet */
-  device = ide_configuration_get_device (priv->configuration);
+  device = ide_configuration_get_device (self->configuration);
   system_type = ide_device_get_system_type (device);
   g_ptr_array_add (ar, g_strdup_printf ("--host=%s", system_type));
 
-  if (NULL != (opts = ide_configuration_getenv (priv->configuration, "CONFIGURE_ARGS")))
+  if (NULL != (opts = ide_configuration_getenv (self->configuration, "CONFIGURE_ARGS")))
     {
       GError *error = NULL;
       gint argc;
@@ -419,7 +388,6 @@ static WorkerState *
 worker_state_new (IdeAutotoolsBuildTask *self,
                   IdeBuilderBuildFlags   flags)
 {
-  IdeAutotoolsBuildTaskPrivate *priv = ide_autotools_build_task_get_instance_private (self);
   g_autofree gchar *name = NULL;
   IdeContext *context;
   IdeDevice *device;
@@ -431,13 +399,13 @@ worker_state_new (IdeAutotoolsBuildTask *self,
   gint val32;
 
   g_return_val_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self), NULL);
-  g_return_val_if_fail (IDE_IS_CONFIGURATION (priv->configuration), NULL);
+  g_return_val_if_fail (IDE_IS_CONFIGURATION (self->configuration), NULL);
 
   context = ide_object_get_context (IDE_OBJECT (self));
   project_file = ide_context_get_project_file (context);
 
-  device = ide_configuration_get_device (priv->configuration);
-  runtime = ide_configuration_get_runtime (priv->configuration);
+  device = ide_configuration_get_device (self->configuration);
+  runtime = ide_configuration_get_runtime (self->configuration);
 
   name = g_file_get_basename (project_file);
 
@@ -447,14 +415,14 @@ worker_state_new (IdeAutotoolsBuildTask *self,
     project_dir = g_object_ref (project_file);
 
   state = g_slice_new0 (WorkerState);
-  state->require_autogen = priv->require_autogen || !!(flags & IDE_BUILDER_BUILD_FLAGS_FORCE_BOOTSTRAP);
-  state->require_configure = priv->require_configure || (state->require_autogen && !(flags & 
IDE_BUILDER_BUILD_FLAGS_NO_CONFIGURE));
-  state->directory_path = g_file_get_path (priv->directory);
+  state->require_autogen = self->require_autogen || !!(flags & IDE_BUILDER_BUILD_FLAGS_FORCE_BOOTSTRAP);
+  state->require_configure = self->require_configure || (state->require_autogen && !(flags & 
IDE_BUILDER_BUILD_FLAGS_NO_CONFIGURE));
+  state->directory_path = g_file_get_path (self->directory);
   state->project_path = g_file_get_path (project_dir);
   state->system_type = g_strdup (ide_device_get_system_type (device));
   state->runtime = g_object_ref (runtime);
 
-  val32 = atoi (ide_configuration_getenv (priv->configuration, "PARALLEL") ?: "-1");
+  val32 = atoi (ide_configuration_getenv (self->configuration, "PARALLEL") ?: "-1");
 
   if (val32 == -1)
     state->parallel = g_strdup_printf ("-j%u", g_get_num_processors () + 1);
@@ -560,16 +528,13 @@ ide_autotools_build_task_execute_async (IdeAutotoolsBuildTask *self,
                                         GAsyncReadyCallback    callback,
                                         gpointer               user_data)
 {
-  IdeAutotoolsBuildTaskPrivate *priv;
   g_autoptr(GTask) task = NULL;
   WorkerState *state;
 
   g_return_if_fail (IDE_IS_AUTOTOOLS_BUILD_TASK (self));
   g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  priv = ide_autotools_build_task_get_instance_private (self);
-
-  if (priv->executed)
+  if (self->executed)
     {
       g_task_report_new_error (self, callback, user_data,
                                ide_autotools_build_task_execute_async,
@@ -579,7 +544,7 @@ ide_autotools_build_task_execute_async (IdeAutotoolsBuildTask *self,
       return;
     }
 
-  priv->executed = TRUE;
+  self->executed = TRUE;
 
   state = worker_state_new (self, flags);
 
@@ -850,8 +815,9 @@ step_make_all  (GTask                 *task,
       return FALSE;
     }
 
-  ide_subprocess_launcher_set_flags  (launcher,
-                                      (G_SUBPROCESS_FLAGS_STDERR_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE));
+  ide_subprocess_launcher_set_flags (launcher,
+                                     (G_SUBPROCESS_FLAGS_STDERR_PIPE |
+                                      G_SUBPROCESS_FLAGS_STDOUT_PIPE));
   ide_subprocess_launcher_set_cwd (launcher, state->directory_path);
   ide_subprocess_launcher_setenv (launcher, "LANG", "C", TRUE);
 
diff --git a/plugins/autotools/ide-autotools-build-task.h b/plugins/autotools/ide-autotools-build-task.h
index 9f5a7a2..2dd19e1 100644
--- a/plugins/autotools/ide-autotools-build-task.h
+++ b/plugins/autotools/ide-autotools-build-task.h
@@ -27,15 +27,10 @@ G_BEGIN_DECLS
 
 #define IDE_TYPE_AUTOTOOLS_BUILD_TASK (ide_autotools_build_task_get_type())
 
-G_DECLARE_FINAL_TYPE (IdeAutotoolsBuildTask, ide_autotools_build_task,
-                      IDE, AUTOTOOLS_BUILD_TASK, IdeBuildResult)
-
-struct _IdeAutotoolsBuildTask
-{
-  IdeBuildResult parent_instance;
-};
+G_DECLARE_FINAL_TYPE (IdeAutotoolsBuildTask, ide_autotools_build_task, IDE, AUTOTOOLS_BUILD_TASK, 
IdeBuildResult)
 
 GFile    *ide_autotools_build_task_get_directory  (IdeAutotoolsBuildTask  *self);
+void      ide_autotools_build_task_add_target     (IdeAutotoolsBuildTask  *self);
 void      ide_autotools_build_task_execute_async  (IdeAutotoolsBuildTask  *self,
                                                    IdeBuilderBuildFlags    flags,
                                                    GCancellable           *cancellable,
diff --git a/plugins/build-tools/gbp-build-tool.c b/plugins/build-tools/gbp-build-tool.c
index fb71b02..c3dcb02 100644
--- a/plugins/build-tools/gbp-build-tool.c
+++ b/plugins/build-tools/gbp-build-tool.c
@@ -186,10 +186,6 @@ gbp_build_tool_new_context_cb (GObject      *object,
   device_manager = ide_context_get_device_manager (context);
   device = ide_device_manager_get_device (device_manager, device_id);
 
-  runtime_id = g_object_get_data (G_OBJECT (task), "RUNTIME_ID");
-  runtime_manager = ide_context_get_runtime_manager (context);
-  runtime = ide_runtime_manager_get_runtime (runtime_manager, runtime_id);
-
   if (device == NULL)
     {
       /* TODO: Wait for devices to settle. */
@@ -201,7 +197,21 @@ gbp_build_tool_new_context_cb (GObject      *object,
       return;
     }
 
-  configuration = ide_configuration_new ("command-line-build", device, runtime);
+  runtime_id = g_object_get_data (G_OBJECT (task), "RUNTIME_ID");
+  runtime_manager = ide_context_get_runtime_manager (context);
+  runtime = ide_runtime_manager_get_runtime (runtime_manager, runtime_id);
+
+  if (runtime == NULL)
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_NOT_FOUND,
+                               _("Failed to locate runtime \"%s\""),
+                               runtime_id);
+      return;
+    }
+
+  configuration = ide_configuration_new (context, "command-line-build", device_id, runtime_id);
 
   if (parallel > -1)
     {
diff --git a/plugins/build-tools/gbp-build-workbench-addin.c b/plugins/build-tools/gbp-build-workbench-addin.c
index 8735653..9462b2e 100644
--- a/plugins/build-tools/gbp-build-workbench-addin.c
+++ b/plugins/build-tools/gbp-build-workbench-addin.c
@@ -168,8 +168,9 @@ gbp_build_workbench_addin_do_build (GbpBuildWorkbenchAddin *self,
                                     IdeBuilderBuildFlags    flags)
 {
   g_autoptr(IdeBuilder) builder = NULL;
-  g_autoptr(IdeConfiguration) configuration = NULL;
   g_autoptr(GError) error = NULL;
+  IdeConfigurationManager *config_manager;
+  IdeConfiguration *configuration;
   IdeBuildSystem *build_system;
   IdeWorkbench *workbench;
   IdeContext *context;
@@ -186,11 +187,8 @@ gbp_build_workbench_addin_do_build (GbpBuildWorkbenchAddin *self,
   workbench = ide_widget_get_workbench (GTK_WIDGET (self->panel));
   context = ide_workbench_get_context (workbench);
   build_system = ide_context_get_build_system (context);
-
-  /*
-   * TODO: Use a configuration stored on the workbench.
-   */
-  configuration = ide_configuration_new ("fixme.save.config.for.later", self->device, self->runtime);
+  config_manager = ide_context_get_configuration_manager (context);
+  configuration = ide_configuration_manager_get_current (config_manager);
 
   builder = ide_build_system_get_builder (build_system, configuration, &error);
 
diff --git a/plugins/xdg-app/gbp-xdg-runtime-provider.c b/plugins/xdg-app/gbp-xdg-runtime-provider.c
index b2ab5df..c55d5c7 100644
--- a/plugins/xdg-app/gbp-xdg-runtime-provider.c
+++ b/plugins/xdg-app/gbp-xdg-runtime-provider.c
@@ -107,7 +107,7 @@ gbp_xdg_runtime_provider_load_worker (GTask        *task,
       arch = xdg_app_ref_get_arch (XDG_APP_REF (ref));
       branch = xdg_app_ref_get_branch (XDG_APP_REF (ref));
 
-      id = g_strdup_printf ("%s-%s-%s", name, branch, arch);
+      id = g_strdup_printf ("xdg-app:%s/%s/%s", name, branch, arch);
       str = g_strdup_printf ("%s %s (%s)", name, branch, arch);
 
       metadata = xdg_app_installed_ref_load_metadata (XDG_APP_INSTALLED_REF (ref),
diff --git a/plugins/xdg-app/gbp-xdg-runtime.c b/plugins/xdg-app/gbp-xdg-runtime.c
index 6b0f133..3befc16 100644
--- a/plugins/xdg-app/gbp-xdg-runtime.c
+++ b/plugins/xdg-app/gbp-xdg-runtime.c
@@ -196,7 +196,7 @@ gbp_xdg_runtime_prepare_configuration (IdeRuntime       *runtime,
   g_assert (IDE_IS_RUNTIME (runtime));
   g_assert (IDE_IS_CONFIGURATION (configuration));
 
-  ide_configuration_setenv (configuration, "PREFIX", "/app");
+  ide_configuration_set_prefix (configuration, "/app");
 }
 
 static void


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