[gnome-builder: 39/139] libide-foundry: move existing components into libide-foundry



commit 81b0a934544b0cc863338ea1a6467c92a688dd78
Author: Christian Hergert <chergert redhat com>
Date:   Wed Jan 9 16:24:06 2019 -0800

    libide-foundry: move existing components into libide-foundry
    
    The new libide-foundry static library contains features related to
    building, running, testing, and packaging software. It also includes
    device managers and someday would likely contain things like simulator
    abstractions.
    
    We may, at some point, consider moving libide-debugger into the foundry
    rather than a separate library.

 src/libide/config/meson.build                      |  21 --
 src/libide/devices/OVERVIEW.md                     |  18 -
 src/libide/devices/meson.build                     |  26 --
 src/libide/directory/OVERVIEW.md                   |  20 --
 src/libide/directory/directory.plugin              |  13 -
 src/libide/directory/ide-directory-build-system.c  | 192 ----------
 src/libide/directory/ide-directory-plugin.c        |  40 ---
 src/libide/directory/ide-directory-vcs.c           | 261 --------------
 src/libide/directory/meson.build                   |  15 -
 .../ide-configuration-manager.c                    | 181 ++++++++--
 .../ide-configuration-manager.h                    |  15 +-
 .../ide-configuration-private.h                    |   0
 .../ide-configuration-provider.c                   |   7 +-
 .../ide-configuration-provider.h                   |   9 +-
 src/libide/{config => foundry}/ide-configuration.c |  57 +--
 src/libide/{config => foundry}/ide-configuration.h |  10 +-
 .../{devices => foundry}/ide-deploy-strategy.c     |   4 +-
 .../{devices => foundry}/ide-deploy-strategy.h     |   7 +-
 src/libide/{devices => foundry}/ide-device-info.c  |   5 +-
 src/libide/{devices => foundry}/ide-device-info.h  |   9 +-
 .../{devices => foundry}/ide-device-manager.c      | 335 ++++++++++++------
 .../{devices => foundry}/ide-device-manager.h      |  11 +-
 .../{devices => foundry}/ide-device-private.h      |   0
 .../{devices => foundry}/ide-device-provider.c     |   3 +-
 .../{devices => foundry}/ide-device-provider.h     |   9 +-
 src/libide/{devices => foundry}/ide-device.c       |   8 +-
 src/libide/{devices => foundry}/ide-device.h       |  11 +-
 src/libide/foundry/ide-fallback-build-system.c     | 169 +++++++++
 .../ide-fallback-build-system.h}                   |  13 +-
 src/libide/foundry/ide-foundry-compat.c            | 227 ++++++++++++
 .../ide-foundry-compat.h}                          |  16 +-
 src/libide/foundry/ide-foundry-init.c              | 161 +++++++++
 src/libide/foundry/ide-foundry-init.h              |  34 ++
 src/libide/foundry/ide-foundry-types.h             |  71 ++++
 src/libide/{local => foundry}/ide-local-device.c   |   9 +-
 src/libide/{local => foundry}/ide-local-device.h   |   8 +-
 .../{runner => foundry}/ide-run-manager-private.h  |   2 +-
 src/libide/{runner => foundry}/ide-run-manager.c   | 120 +++++--
 src/libide/{runner => foundry}/ide-run-manager.h   |  13 +-
 src/libide/{runner => foundry}/ide-runner-addin.c  |   6 +-
 src/libide/{runner => foundry}/ide-runner-addin.h  |   9 +-
 src/libide/{runner => foundry}/ide-runner.c        |  28 +-
 src/libide/{runner => foundry}/ide-runner.h        |  18 +-
 .../{runtimes => foundry}/ide-runtime-manager.c    | 112 +++---
 .../{runtimes => foundry}/ide-runtime-manager.h    |  11 +-
 .../{runtimes => foundry}/ide-runtime-private.h    |   3 +-
 .../{runtimes => foundry}/ide-runtime-provider.c   |  19 +-
 .../{runtimes => foundry}/ide-runtime-provider.h   |  10 +-
 src/libide/{runtimes => foundry}/ide-runtime.c     | 100 ++++--
 src/libide/{runtimes => foundry}/ide-runtime.h     |  29 +-
 .../{toolchain => foundry}/ide-simple-toolchain.c  |   9 +-
 .../{toolchain => foundry}/ide-simple-toolchain.h  |  11 +-
 src/libide/{testing => foundry}/ide-test-manager.c | 208 ++++++++++-
 src/libide/foundry/ide-test-manager.h              |  77 ++++
 src/libide/{testing => foundry}/ide-test-private.h |   8 +-
 .../{testing => foundry}/ide-test-provider.c       |   5 +-
 .../{testing => foundry}/ide-test-provider.h       |  18 +-
 src/libide/{testing => foundry}/ide-test.c         |   8 +-
 src/libide/{testing => foundry}/ide-test.h         |   8 +-
 .../{toolchain => foundry}/ide-toolchain-manager.c |  43 ++-
 .../{toolchain => foundry}/ide-toolchain-manager.h |   9 +-
 .../{toolchain => foundry}/ide-toolchain-private.h |   3 +-
 .../ide-toolchain-provider.c                       |   7 +-
 .../ide-toolchain-provider.h                       |   9 +-
 src/libide/{toolchain => foundry}/ide-toolchain.c  |   8 +-
 src/libide/{toolchain => foundry}/ide-toolchain.h  |  12 +-
 src/libide/foundry/ide-triplet.c                   | 389 +++++++++++++++++++++
 src/libide/foundry/ide-triplet.h                   |  70 ++++
 src/libide/foundry/libide-foundry.h                |  75 ++++
 src/libide/foundry/meson.build                     | 192 ++++++++++
 src/libide/local/meson.build                       |  12 -
 src/libide/runner/OVERVIEW.md                      | 100 ------
 src/libide/runner/ide-run-button.c                 | 202 -----------
 src/libide/runner/ide-run-button.h                 |  33 --
 src/libide/runner/ide-run-button.ui                |  67 ----
 src/libide/runner/meson.build                      |  23 --
 src/libide/runtimes/meson.build                    |  21 --
 src/libide/testing/gtk/menus.ui                    |  17 -
 src/libide/testing/ide-test-editor-addin.c         | 121 -------
 src/libide/testing/ide-test-editor-addin.h         |  31 --
 src/libide/testing/ide-test-manager.h              |  55 ---
 src/libide/testing/ide-test-panel.c                | 364 -------------------
 src/libide/testing/ide-test-panel.h                |  31 --
 src/libide/testing/ide-test-panel.ui               |  51 ---
 src/libide/testing/meson.build                     |  30 --
 src/libide/testing/testing-plugin.c                |  36 --
 src/libide/testing/testing.plugin                  |   9 -
 src/libide/toolchain/meson.build                   |  18 -
 88 files changed, 2545 insertions(+), 2320 deletions(-)
---
diff --git a/src/libide/config/ide-configuration-manager.c b/src/libide/foundry/ide-configuration-manager.c
similarity index 85%
rename from src/libide/config/ide-configuration-manager.c
rename to src/libide/foundry/ide-configuration-manager.c
index 315866ee5..d5c712f12 100644
--- a/src/libide/config/ide-configuration-manager.c
+++ b/src/libide/foundry/ide-configuration-manager.c
@@ -22,20 +22,15 @@
 
 #include "config.h"
 
+#include <dazzle.h>
 #include <glib/gi18n.h>
+#include <libide-threading.h>
 #include <libpeas/peas.h>
 
-#include "ide-context.h"
-#include "ide-debug.h"
-
-#include "application/ide-application.h"
-#include "config/ide-configuration-manager.h"
-#include "config/ide-configuration-private.h"
-#include "config/ide-configuration.h"
-#include "config/ide-configuration-provider.h"
-#include "buildconfig/ide-buildconfig-configuration.h"
-#include "buildconfig/ide-buildconfig-configuration-provider.h"
-#include "threading/ide-task.h"
+#include "ide-configuration-manager.h"
+#include "ide-configuration-private.h"
+#include "ide-configuration.h"
+#include "ide-configuration-provider.h"
 
 #define WRITEBACK_DELAY_SEC 3
 
@@ -60,13 +55,27 @@ typedef struct
   IdeConfiguration         *config;
 } ConfigInfo;
 
-static void async_initable_iface_init           (GAsyncInitableIface *iface);
-static void list_model_iface_init               (GListModelInterface *iface);
-static void ide_configuration_manager_save_tick (IdeTask             *task);
+static void async_initable_iface_init                   (GAsyncInitableIface     *iface);
+static void list_model_iface_init                       (GListModelInterface     *iface);
+static void ide_configuration_manager_save_tick         (IdeTask                 *task);
+static void ide_configuration_manager_actions_current   (IdeConfigurationManager *self,
+                                                         GVariant                *param);
+static void ide_configuration_manager_actions_delete    (IdeConfigurationManager *self,
+                                                         GVariant                *param);
+static void ide_configuration_manager_actions_duplicate (IdeConfigurationManager *self,
+                                                         GVariant                *param);
+
+DZL_DEFINE_ACTION_GROUP (IdeConfigurationManager, ide_configuration_manager, {
+  { "current", ide_configuration_manager_actions_current, "s" },
+  { "delete", ide_configuration_manager_actions_delete, "s" },
+  { "duplicate", ide_configuration_manager_actions_duplicate, "s" },
+})
 
 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))
+                        G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
+                        G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP,
+                                               ide_configuration_manager_init_action_group))
 
 enum {
   PROP_0,
@@ -93,6 +102,57 @@ config_info_clear (gpointer data)
   g_clear_object (&info->provider);
 }
 
+static void
+ide_configuration_manager_actions_current (IdeConfigurationManager *self,
+                                           GVariant                *param)
+{
+  IdeConfiguration *config;
+  const gchar *id;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (param != NULL);
+  g_assert (g_variant_is_of_type (param, G_VARIANT_TYPE_STRING));
+
+  id = g_variant_get_string (param, NULL);
+
+  if ((config = ide_configuration_manager_get_configuration (self, id)))
+    ide_configuration_manager_set_current (self, config);
+}
+
+static void
+ide_configuration_manager_actions_duplicate (IdeConfigurationManager *self,
+                                             GVariant                *param)
+{
+  IdeConfiguration *config;
+  const gchar *id;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (param != NULL);
+  g_assert (g_variant_is_of_type (param, G_VARIANT_TYPE_STRING));
+
+  id = g_variant_get_string (param, NULL);
+
+  if ((config = ide_configuration_manager_get_configuration (self, id)))
+    ide_configuration_manager_duplicate (self, config);
+}
+
+static void
+ide_configuration_manager_actions_delete (IdeConfigurationManager *self,
+                                          GVariant                *param)
+{
+  IdeConfiguration *config;
+  const gchar *id;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (param != NULL);
+  g_assert (g_variant_is_of_type (param, G_VARIANT_TYPE_STRING));
+
+  id = g_variant_get_string (param, NULL);
+
+  if ((config = ide_configuration_manager_get_configuration (self, id)))
+    ide_configuration_manager_delete (self, config);
+}
+
 static void
 ide_configuration_manager_collect_providers (PeasExtensionSet *set,
                                              PeasPluginInfo   *plugin_info,
@@ -225,6 +285,7 @@ IdeConfiguration *
 ide_configuration_manager_get_configuration (IdeConfigurationManager *self,
                                              const gchar             *id)
 {
+  g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
   g_return_val_if_fail (IDE_IS_CONFIGURATION_MANAGER (self), NULL);
   g_return_val_if_fail (id != NULL, NULL);
 
@@ -234,7 +295,7 @@ ide_configuration_manager_get_configuration (IdeConfigurationManager *self,
 
       g_assert (IDE_IS_CONFIGURATION (info->config));
 
-      if (dzl_str_equal0 (id, ide_configuration_get_id (info->config)))
+      if (ide_str_equal0 (id, ide_configuration_get_id (info->config)))
         return info->config;
     }
 
@@ -477,7 +538,7 @@ ide_configuration_manager_changed (IdeConfigurationManager *self,
   g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
   g_assert (IDE_IS_CONFIGURATION (config));
 
-  dzl_clear_source (&self->queued_save_source);
+  g_clear_handle_id (&self->queued_save_source, g_source_remove);
   self->queued_save_source =
     g_timeout_add_seconds_full (G_PRIORITY_LOW,
                                 WRITEBACK_DELAY_SEC,
@@ -624,6 +685,8 @@ ide_configuration_manager_provider_added (PeasExtensionSet *set,
 
   provider_connect (self, provider);
 
+  ide_object_append (IDE_OBJECT (self), IDE_OBJECT (provider));
+
   ide_configuration_provider_load_async (provider,
                                          self->cancellable,
                                          ide_configuration_manager_provider_load_cb,
@@ -663,6 +726,8 @@ ide_configuration_manager_provider_removed (PeasExtensionSet *set,
           g_array_remove_index (self->configs, i);
         }
     }
+
+  ide_object_destroy (IDE_OBJECT (provider));
 }
 
 static void
@@ -722,7 +787,6 @@ ide_configuration_manager_init_load_cb (GObject      *object,
   g_autoptr(GError) error = NULL;
   g_autoptr(IdeTask) task = user_data;
   GPtrArray *providers;
-  IdeContext *context;
 
   IDE_ENTRY;
 
@@ -734,16 +798,11 @@ ide_configuration_manager_init_load_cb (GObject      *object,
   self = ide_task_get_source_object (task);
   g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
 
-  context = ide_object_get_context (IDE_OBJECT (self));
-  g_assert (IDE_IS_CONTEXT (context));
-
   if (!ide_configuration_provider_load_finish (provider, result, &error))
     {
-      g_print ("%s\n", G_OBJECT_TYPE_NAME (provider));
       g_assert (error != NULL);
-      ide_context_warning (context,
-                           "Failed to initialize config provider: %s: %s",
-                           G_OBJECT_TYPE_NAME (provider), error->message);
+      g_warning ("Failed to initialize config provider: %s: %s",
+                 G_OBJECT_TYPE_NAME (provider), error->message);
     }
 
   providers = ide_task_get_task_data (task);
@@ -786,11 +845,10 @@ ide_configuration_manager_init_async (GAsyncInitable      *initable,
   context = ide_object_get_context (IDE_OBJECT (self));
   g_assert (IDE_IS_CONTEXT (context));
 
-  self->project_settings = ide_context_get_project_settings (context);
+  self->project_settings = ide_context_ref_project_settings (context);
 
   self->providers = peas_extension_set_new (peas_engine_get_default (),
                                             IDE_TYPE_CONFIGURATION_PROVIDER,
-                                            "context", context,
                                             NULL);
 
   g_signal_connect (self->providers,
@@ -803,6 +861,11 @@ ide_configuration_manager_init_async (GAsyncInitable      *initable,
                     G_CALLBACK (ide_configuration_manager_provider_removed),
                     self);
 
+  /* We don't call ide_configuration_manager_provider_added() here for each
+   * of our providers because we want to be in control of the async lifetime
+   * and delay our init_async() completion until loaders have finished
+   */
+
   providers = g_ptr_array_new_with_free_func (g_object_unref);
   peas_extension_set_foreach (self->providers,
                               ide_configuration_manager_collect_providers,
@@ -817,6 +880,8 @@ ide_configuration_manager_init_async (GAsyncInitable      *initable,
 
       provider_connect (self, provider);
 
+      ide_object_append (IDE_OBJECT (self), IDE_OBJECT (provider));
+
       ide_configuration_provider_load_async (provider,
                                              cancellable,
                                              ide_configuration_manager_init_load_cb,
@@ -897,6 +962,48 @@ ide_configuration_manager_set_current (IdeConfigurationManager *self,
     }
 }
 
+/**
+ * ide_configuration_manager_ref_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 gets the default configuration that various
+ * background items might use, such as tags builders which need to discover
+ * settings.
+ *
+ * Returns: (transfer full): An #IdeConfiguration
+ *
+ * Since: 3.32
+ */
+IdeConfiguration *
+ide_configuration_manager_ref_current (IdeConfigurationManager *self)
+{
+  g_autoptr(IdeConfiguration) ret = NULL;
+
+  g_return_val_if_fail (IDE_IS_CONFIGURATION_MANAGER (self), NULL);
+  g_return_val_if_fail (self->current != NULL || self->configs->len > 0, NULL);
+
+  ide_object_lock (IDE_OBJECT (self));
+
+  if (self->current != NULL)
+    ret = g_object_ref (self->current);
+  else if (self->configs->len > 0)
+    {
+      const ConfigInfo *info = &g_array_index (self->configs, ConfigInfo, 0);
+
+      g_assert (IDE_IS_CONFIGURATION_PROVIDER (info->provider));
+      g_assert (IDE_IS_CONFIGURATION (info->config));
+
+      ret = g_object_ref (info->config);
+    }
+
+  ide_object_unlock (IDE_OBJECT (self));
+
+  return g_steal_pointer (&ret);
+}
+
 /**
  * ide_configuration_manager_get_current:
  * @self: An #IdeConfigurationManager
@@ -915,6 +1022,7 @@ ide_configuration_manager_set_current (IdeConfigurationManager *self,
 IdeConfiguration *
 ide_configuration_manager_get_current (IdeConfigurationManager *self)
 {
+  g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
   g_return_val_if_fail (IDE_IS_CONFIGURATION_MANAGER (self), NULL);
   g_return_val_if_fail (self->current != NULL || self->configs->len > 0, NULL);
 
@@ -1020,3 +1128,22 @@ ide_configuration_manager_get_ready (IdeConfigurationManager *self)
 
   return FALSE;
 }
+
+/**
+ * ide_configuration_manager_ref_from_context:
+ * @context: an #IdeContext
+ *
+ * Thread-safe version of ide_configuration_manager_from_context().
+ *
+ * Returns: (transfer full): an #IdeConfigurationManager
+ *
+ * Since: 3.32
+ */
+IdeConfigurationManager *
+ide_configuration_manager_ref_from_context (IdeContext *context)
+{
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+  return ide_object_ensure_child_typed (IDE_OBJECT (context),
+                                        IDE_TYPE_CONFIGURATION_MANAGER);
+}
diff --git a/src/libide/config/ide-configuration-manager.h b/src/libide/foundry/ide-configuration-manager.h
similarity index 84%
rename from src/libide/config/ide-configuration-manager.h
rename to src/libide/foundry/ide-configuration-manager.h
index ff27258da..040f58295 100644
--- a/src/libide/config/ide-configuration-manager.h
+++ b/src/libide/foundry/ide-configuration-manager.h
@@ -20,12 +20,13 @@
 
 #pragma once
 
-#include <gio/gio.h>
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "ide-version-macros.h"
+#include <libide-core.h>
 
-#include "ide-object.h"
-#include "ide-types.h"
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
@@ -34,9 +35,15 @@ G_BEGIN_DECLS
 IDE_AVAILABLE_IN_3_32
 G_DECLARE_FINAL_TYPE (IdeConfigurationManager, ide_configuration_manager, IDE, CONFIGURATION_MANAGER, 
IdeObject)
 
+IDE_AVAILABLE_IN_3_32
+IdeConfigurationManager *ide_configuration_manager_from_context (IdeContext *context);
+IDE_AVAILABLE_IN_3_32
+IdeConfigurationManager *ide_configuration_manager_ref_from_context (IdeContext *context);
 IDE_AVAILABLE_IN_3_32
 IdeConfiguration *ide_configuration_manager_get_current       (IdeConfigurationManager  *self);
 IDE_AVAILABLE_IN_3_32
+IdeConfiguration *ide_configuration_manager_ref_current       (IdeConfigurationManager  *self);
+IDE_AVAILABLE_IN_3_32
 void              ide_configuration_manager_set_current       (IdeConfigurationManager  *self,
                                                                IdeConfiguration         *configuration);
 IDE_AVAILABLE_IN_3_32
diff --git a/src/libide/config/ide-configuration-private.h b/src/libide/foundry/ide-configuration-private.h
similarity index 100%
rename from src/libide/config/ide-configuration-private.h
rename to src/libide/foundry/ide-configuration-private.h
diff --git a/src/libide/config/ide-configuration-provider.c b/src/libide/foundry/ide-configuration-provider.c
similarity index 98%
rename from src/libide/config/ide-configuration-provider.c
rename to src/libide/foundry/ide-configuration-provider.c
index a662bd081..d95347a1e 100644
--- a/src/libide/config/ide-configuration-provider.c
+++ b/src/libide/foundry/ide-configuration-provider.c
@@ -22,10 +22,9 @@
 
 #include "config.h"
 
-#include "application/ide-application.h"
-#include "config/ide-configuration.h"
-#include "config/ide-configuration-manager.h"
-#include "config/ide-configuration-provider.h"
+#include "ide-configuration.h"
+#include "ide-configuration-manager.h"
+#include "ide-configuration-provider.h"
 
 G_DEFINE_INTERFACE (IdeConfigurationProvider, ide_configuration_provider, IDE_TYPE_OBJECT)
 
diff --git a/src/libide/config/ide-configuration-provider.h b/src/libide/foundry/ide-configuration-provider.h
similarity index 96%
rename from src/libide/config/ide-configuration-provider.h
rename to src/libide/foundry/ide-configuration-provider.h
index 4191ce1c4..5ff84b7c3 100644
--- a/src/libide/config/ide-configuration-provider.h
+++ b/src/libide/foundry/ide-configuration-provider.h
@@ -21,10 +21,13 @@
 
 #pragma once
 
-#include <gio/gio.h>
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "ide-types.h"
-#include "ide-version-macros.h"
+#include <libide-core.h>
+
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/libide/config/ide-configuration.c b/src/libide/foundry/ide-configuration.c
similarity index 97%
rename from src/libide/config/ide-configuration.c
rename to src/libide/foundry/ide-configuration.c
index 27fd4fd26..3efafce34 100644
--- a/src/libide/config/ide-configuration.c
+++ b/src/libide/foundry/ide-configuration.c
@@ -24,19 +24,15 @@
 
 #include <string.h>
 
-#include "ide-context.h"
-#include "ide-debug.h"
-#include "ide-enums.h"
-
-#include "application/ide-application.h"
-#include "config/ide-configuration.h"
-#include "config/ide-configuration-manager.h"
-#include "config/ide-configuration-private.h"
-#include "buildsystem/ide-environment.h"
-#include "runtimes/ide-runtime-manager.h"
-#include "runtimes/ide-runtime.h"
-#include "subprocess/ide-subprocess-launcher.h"
-#include "toolchain/ide-toolchain-manager.h"
+#include "ide-configuration-manager.h"
+#include "ide-configuration-private.h"
+#include "ide-configuration.h"
+#include "ide-foundry-enums.h"
+#include "ide-foundry-compat.h"
+#include "ide-runtime-manager.h"
+#include "ide-runtime.h"
+#include "ide-toolchain-manager.h"
+#include "ide-toolchain.h"
 
 typedef struct
 {
@@ -106,11 +102,11 @@ enum {
 
 enum {
   CHANGED,
-  LAST_SIGNAL
+  N_SIGNALS
 };
 
 static GParamSpec *properties [N_PROPS];
-static guint signals [LAST_SIGNAL];
+static guint signals [N_SIGNALS];
 
 static void
 _value_free (gpointer data)
@@ -176,7 +172,7 @@ ide_configuration_real_get_runtime (IdeConfiguration *self)
   if (priv->runtime_id != NULL)
     {
       IdeContext *context = ide_object_get_context (IDE_OBJECT (self));
-      IdeRuntimeManager *runtime_manager = ide_context_get_runtime_manager (context);
+      IdeRuntimeManager *runtime_manager = ide_runtime_manager_from_context (context);
       return ide_runtime_manager_get_runtime (runtime_manager, priv->runtime_id);;
     }
 
@@ -213,7 +209,7 @@ ide_configuration_runtime_manager_items_changed (IdeConfiguration  *self,
 
   g_assert (IDE_IS_CONFIGURATION (self));
 
-  if (ide_object_is_unloading (IDE_OBJECT (self)))
+  if (ide_object_in_destruction (IDE_OBJECT (self)))
     return;
 
   g_assert (IDE_IS_RUNTIME_MANAGER (runtime_manager));
@@ -240,7 +236,7 @@ ide_configuration_environment_changed (IdeConfiguration *self,
   g_assert (IDE_IS_CONFIGURATION (self));
   g_assert (IDE_IS_ENVIRONMENT (environment));
 
-  if (ide_object_is_unloading (IDE_OBJECT (self)))
+  if (ide_object_in_destruction (IDE_OBJECT (self)))
     return;
 
   ide_configuration_set_dirty (self, TRUE);
@@ -264,6 +260,22 @@ ide_configuration_real_set_runtime (IdeConfiguration *self,
   ide_configuration_set_runtime_id (self, runtime_id);
 }
 
+static gchar *
+ide_configuration_repr (IdeObject *object)
+{
+  IdeConfiguration *self = (IdeConfiguration *)object;
+  IdeConfigurationPrivate *priv = ide_configuration_get_instance_private (self);
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_CONFIGURATION (self));
+
+  return g_strdup_printf ("%s id=\"%s\" name=\"%s\" runtime=\"%s\"",
+                          G_OBJECT_TYPE_NAME (self),
+                          priv->id,
+                          priv->display_name,
+                          priv->runtime_id);
+}
+
 static void
 ide_configuration_finalize (GObject *object)
 {
@@ -473,11 +485,14 @@ static void
 ide_configuration_class_init (IdeConfigurationClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
 
   object_class->finalize = ide_configuration_finalize;
   object_class->get_property = ide_configuration_get_property;
   object_class->set_property = ide_configuration_set_property;
 
+  i_object_class->repr = ide_configuration_repr;
+
   klass->get_runtime = ide_configuration_real_get_runtime;
   klass->set_runtime = ide_configuration_real_set_runtime;
 
@@ -725,7 +740,7 @@ ide_configuration_set_runtime_id (IdeConfiguration *self,
           g_assert (IDE_IS_MAIN_THREAD ());
 
           context = ide_object_get_context (IDE_OBJECT (self));
-          runtime_manager = ide_context_get_runtime_manager (context);
+          runtime_manager = ide_runtime_manager_from_context (context);
           ide_configuration_runtime_manager_items_changed (self, 0, 0, 0, runtime_manager);
 
           ide_configuration_emit_changed (self);
@@ -834,7 +849,7 @@ ide_configuration_get_toolchain (IdeConfiguration *self)
   if (priv->toolchain_id != NULL)
     {
       IdeContext *context = ide_object_get_context (IDE_OBJECT (self));
-      IdeToolchainManager *toolchain_manager = ide_context_get_toolchain_manager (context);
+      IdeToolchainManager *toolchain_manager = ide_toolchain_manager_from_context (context);
       g_autoptr (IdeToolchain) toolchain = ide_toolchain_manager_get_toolchain (toolchain_manager, 
priv->toolchain_id);
 
       if (toolchain != NULL)
@@ -1694,7 +1709,7 @@ _ide_configuration_attach (IdeConfiguration *self)
       return;
     }
 
-  runtime_manager = ide_context_get_runtime_manager (context);
+  runtime_manager = ide_runtime_manager_from_context (context);
 
   g_signal_connect_object (runtime_manager,
                            "items-changed",
diff --git a/src/libide/config/ide-configuration.h b/src/libide/foundry/ide-configuration.h
similarity index 98%
rename from src/libide/config/ide-configuration.h
rename to src/libide/foundry/ide-configuration.h
index 6d26ba0f1..62344ef48 100644
--- a/src/libide/config/ide-configuration.h
+++ b/src/libide/foundry/ide-configuration.h
@@ -20,12 +20,14 @@
 
 #pragma once
 
-#include <gio/gio.h>
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "ide-version-macros.h"
+#include <libide-core.h>
+#include <libide-threading.h>
 
-#include "ide-object.h"
-#include "ide-types.h"
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/libide/devices/ide-deploy-strategy.c b/src/libide/foundry/ide-deploy-strategy.c
similarity index 99%
rename from src/libide/devices/ide-deploy-strategy.c
rename to src/libide/foundry/ide-deploy-strategy.c
index 3e54d8e98..fcfddcb40 100644
--- a/src/libide/devices/ide-deploy-strategy.c
+++ b/src/libide/foundry/ide-deploy-strategy.c
@@ -24,8 +24,8 @@
 
 #include "ide-debug.h"
 
-#include "buildsystem/ide-build-pipeline.h"
-#include "devices/ide-deploy-strategy.h"
+#include "ide-build-pipeline.h"
+#include "ide-deploy-strategy.h"
 
 G_DEFINE_ABSTRACT_TYPE (IdeDeployStrategy, ide_deploy_strategy, IDE_TYPE_OBJECT)
 
diff --git a/src/libide/devices/ide-deploy-strategy.h b/src/libide/foundry/ide-deploy-strategy.h
similarity index 95%
rename from src/libide/devices/ide-deploy-strategy.h
rename to src/libide/foundry/ide-deploy-strategy.h
index 1bbec88d4..74159f93b 100644
--- a/src/libide/devices/ide-deploy-strategy.h
+++ b/src/libide/foundry/ide-deploy-strategy.h
@@ -20,8 +20,11 @@
 
 #pragma once
 
-#include "ide-object.h"
-#include "ide-version-macros.h"
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
+
+#include <libide-core.h>
 
 G_BEGIN_DECLS
 
diff --git a/src/libide/devices/ide-device-info.c b/src/libide/foundry/ide-device-info.c
similarity index 99%
rename from src/libide/devices/ide-device-info.c
rename to src/libide/foundry/ide-device-info.c
index 73bd78705..51674cafe 100644
--- a/src/libide/devices/ide-device-info.c
+++ b/src/libide/foundry/ide-device-info.c
@@ -23,9 +23,8 @@
 #include "config.h"
 
 #include "ide-device-info.h"
-#include "ide-enums.h"
-
-#include "util/ide-posix.h"
+#include "ide-foundry-enums.h"
+#include "ide-triplet.h"
 
 struct _IdeDeviceInfo
 {
diff --git a/src/libide/devices/ide-device-info.h b/src/libide/foundry/ide-device-info.h
similarity index 89%
rename from src/libide/devices/ide-device-info.h
rename to src/libide/foundry/ide-device-info.h
index e6f194220..7b84200d7 100644
--- a/src/libide/devices/ide-device-info.h
+++ b/src/libide/foundry/ide-device-info.h
@@ -20,12 +20,13 @@
 
 #pragma once
 
-#include <gio/gio.h>
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "ide-types.h"
-#include "ide-version-macros.h"
+#include <libide-core.h>
 
-#include "util/ide-triplet.h"
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/libide/devices/ide-device-manager.c b/src/libide/foundry/ide-device-manager.c
similarity index 77%
rename from src/libide/devices/ide-device-manager.c
rename to src/libide/foundry/ide-device-manager.c
index 60da65fae..37cee92ea 100644
--- a/src/libide/devices/ide-device-manager.c
+++ b/src/libide/foundry/ide-device-manager.c
@@ -23,24 +23,19 @@
 #include "config.h"
 
 #include <glib/gi18n.h>
+#include <libide-plugins.h>
+#include <libide-threading.h>
 #include <libpeas/peas.h>
 
-#include "ide-context.h"
-#include "ide-debug.h"
-
-#include "application/ide-application.h"
-#include "buildsystem/ide-build-manager.h"
-#include "buildsystem/ide-build-pipeline.h"
-#include "devices/ide-deploy-strategy.h"
-#include "devices/ide-device.h"
-#include "devices/ide-device-manager.h"
-#include "devices/ide-device-private.h"
-#include "devices/ide-device-provider.h"
-#include "local/ide-local-device.h"
-#include "plugins/ide-extension-util.h"
-#include "threading/ide-task.h"
-#include "util/ide-glib.h"
-#include "util/ide-posix.h"
+#include "ide-build-manager.h"
+#include "ide-build-pipeline.h"
+#include "ide-deploy-strategy.h"
+#include "ide-device-manager.h"
+#include "ide-device-private.h"
+#include "ide-device-provider.h"
+#include "ide-device.h"
+#include "ide-foundry-compat.h"
+#include "ide-local-device.h"
 
 struct _IdeDeviceManager
 {
@@ -60,10 +55,8 @@ struct _IdeDeviceManager
    */
   GPtrArray *devices;
 
-  /*
-   * The providers that are registered in plugins supporting IdeDeviceProvider.
-   */
-  PeasExtensionSet *providers;
+  /* Providers that are registered in plugins supporting IdeDeviceProvider. */
+  IdeExtensionSetAdapter *providers;
 
   /*
    * Our menu that contains our list of devices for the user to select. This
@@ -78,15 +71,23 @@ struct _IdeDeviceManager
    * in the omnibar.
    */
   gdouble progress;
+
+  guint loading : 1;
 };
 
 typedef struct
 {
-  GPtrArray        *strategies;
+  IdeObjectArray   *strategies;
   IdeBuildPipeline *pipeline;
 } DeployState;
 
+typedef struct
+{
+  gint n_active;
+} InitState;
+
 static void list_model_init_interface        (GListModelInterface *iface);
+static void async_initable_init_iface        (GAsyncInitableIface *iface);
 static void ide_device_manager_action_device (IdeDeviceManager    *self,
                                               GVariant            *param);
 static void ide_device_manager_action_deploy (IdeDeviceManager    *self,
@@ -101,6 +102,7 @@ DZL_DEFINE_ACTION_GROUP (IdeDeviceManager, ide_device_manager, {
 G_DEFINE_TYPE_WITH_CODE (IdeDeviceManager, ide_device_manager, IDE_TYPE_OBJECT,
                          G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP,
                                                 ide_device_manager_init_action_group)
+                         G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_init_iface)
                          G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_init_interface))
 
 enum {
@@ -123,7 +125,7 @@ static void
 deploy_state_free (DeployState *state)
 {
   g_clear_object (&state->pipeline);
-  g_clear_pointer (&state->strategies, g_ptr_array_unref);
+  g_clear_pointer (&state->strategies, ide_object_array_unref);
   g_slice_free (DeployState, state);
 }
 
@@ -150,6 +152,24 @@ ide_device_manager_provider_device_added_cb (IdeDeviceManager  *self,
 
   IDE_TRACE_MSG ("Discovered device %s", device_id);
 
+  /* Notify user of new device if this is after initial loading */
+  if (!self->loading)
+    {
+      g_autoptr(IdeNotification) notif = NULL;
+      g_autofree gchar *title = NULL;
+
+      /* translators: %s is replaced with the external device name */
+      title = g_strdup_printf (_("Discovered device “%s”"), display_name);
+      notif = g_object_new (IDE_TYPE_NOTIFICATION,
+                            "id", "org.gnome.builder.device-manager.added",
+                            "title", title,
+                            "icon-name", icon_name,
+                            NULL);
+
+      ide_notification_attach (notif, IDE_OBJECT (self));
+      ide_notification_withdraw_in_seconds (notif, -1);
+    }
+
   /* First add the device to the array, we'll notify observers later */
   position = self->devices->len;
   g_ptr_array_add (self->devices, g_object_ref (device));
@@ -240,10 +260,10 @@ ide_device_manager_provider_load_cb (GObject      *object,
 }
 
 static void
-ide_device_manager_provider_added_cb (PeasExtensionSet *set,
-                                      PeasPluginInfo   *plugin_info,
-                                      PeasExtension    *exten,
-                                      gpointer          user_data)
+ide_device_manager_provider_added_cb (IdeExtensionSetAdapter *set,
+                                      PeasPluginInfo         *plugin_info,
+                                      PeasExtension          *exten,
+                                      gpointer                user_data)
 {
   IdeDeviceManager *self = user_data;
   IdeDeviceProvider *provider = (IdeDeviceProvider *)exten;
@@ -251,11 +271,13 @@ ide_device_manager_provider_added_cb (PeasExtensionSet *set,
 
   IDE_ENTRY;
 
-  g_assert (PEAS_IS_EXTENSION_SET (set));
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
   g_assert (IDE_IS_DEVICE_MANAGER (self));
   g_assert (plugin_info != NULL);
   g_assert (IDE_IS_DEVICE_PROVIDER (provider));
 
+  ide_object_append (IDE_OBJECT (self), IDE_OBJECT (provider));
+
   g_signal_connect_object (provider,
                            "device-added",
                            G_CALLBACK (ide_device_manager_provider_device_added_cb),
@@ -289,10 +311,10 @@ ide_device_manager_provider_added_cb (PeasExtensionSet *set,
 }
 
 static void
-ide_device_manager_provider_removed_cb (PeasExtensionSet *set,
-                                        PeasPluginInfo   *plugin_info,
-                                        PeasExtension    *exten,
-                                        gpointer          user_data)
+ide_device_manager_provider_removed_cb (IdeExtensionSetAdapter *set,
+                                        PeasPluginInfo         *plugin_info,
+                                        PeasExtension          *exten,
+                                        gpointer                user_data)
 {
   IdeDeviceManager *self = user_data;
   IdeDeviceProvider *provider = (IdeDeviceProvider *)exten;
@@ -300,7 +322,7 @@ ide_device_manager_provider_removed_cb (PeasExtensionSet *set,
 
   IDE_ENTRY;
 
-  g_assert (PEAS_IS_EXTENSION_SET (set));
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
   g_assert (IDE_IS_DEVICE_MANAGER (self));
   g_assert (plugin_info != NULL);
   g_assert (IDE_IS_DEVICE_PROVIDER (provider));
@@ -333,36 +355,9 @@ ide_device_manager_provider_removed_cb (PeasExtensionSet *set,
                                         G_CALLBACK (ide_device_manager_provider_device_removed_cb),
                                         self);
 
-  IDE_EXIT;
-}
-
-static void
-ide_device_manager_add_providers (IdeDeviceManager *self)
-{
-  IdeContext *context;
-
-  g_assert (IDE_IS_DEVICE_MANAGER (self));
-
-  context = ide_object_get_context (IDE_OBJECT (self));
-
-  self->providers = peas_extension_set_new (peas_engine_get_default (),
-                                            IDE_TYPE_DEVICE_PROVIDER,
-                                            "context", context,
-                                            NULL);
-
-  g_signal_connect (self->providers,
-                    "extension-added",
-                    G_CALLBACK (ide_device_manager_provider_added_cb),
-                    self);
+  ide_object_destroy (IDE_OBJECT (provider));
 
-  g_signal_connect (self->providers,
-                    "extension-removed",
-                    G_CALLBACK (ide_device_manager_provider_removed_cb),
-                    self);
-
-  peas_extension_set_foreach (self->providers,
-                              (PeasExtensionSetForeachFunc)ide_device_manager_provider_added_cb,
-                              self);
+  IDE_EXIT;
 }
 
 static void
@@ -371,37 +366,15 @@ ide_device_manager_add_local (IdeDeviceManager *self)
   g_autoptr(IdeDevice) device = NULL;
   g_autoptr(IdeTriplet) triplet = NULL;
   g_autofree gchar *arch = NULL;
-  IdeContext *context;
 
   g_return_if_fail (IDE_IS_DEVICE_MANAGER (self));
 
-  context = ide_object_get_context (IDE_OBJECT (self));
   triplet = ide_triplet_new_from_system ();
   device = g_object_new (IDE_TYPE_LOCAL_DEVICE,
-                         "context", context,
                          "triplet", triplet,
                          NULL);
+  ide_object_append (IDE_OBJECT (self), IDE_OBJECT (device));
   ide_device_manager_provider_device_added_cb (self, device, NULL);
-
-  arch = ide_get_system_arch ();
-
-  /*
-   * If we're running on 64-bit intel, also include a 32-bit device
-   * that allows the user to build/configure the pipeline for i386.
-   */
-  if (g_str_equal (arch, "x86_64"))
-    {
-#if 0
-      g_autoptr(IdeDevice) legacy_device = NULL;
-      g_autoptr(IdeTriplet) legacy_triplet = ide_triplet_new ("i386");
-
-      legacy_device = g_object_new (IDE_TYPE_LOCAL_DEVICE,
-                                    "triplet", legacy_triplet,
-                                    "context", context,
-                                    NULL);
-      ide_device_manager_provider_device_added_cb (self, legacy_device, NULL);
-#endif
-    }
 }
 
 static GType
@@ -433,30 +406,21 @@ ide_device_manager_get_item (GListModel *list_model,
 }
 
 static void
-ide_device_manager_constructed (GObject *object)
+ide_device_manager_destroy (IdeObject *object)
 {
   IdeDeviceManager *self = (IdeDeviceManager *)object;
 
-  g_return_if_fail (IDE_IS_DEVICE_MANAGER (self));
+  g_assert (IDE_IS_OBJECT (object));
+  g_assert (IDE_IS_MAIN_THREAD ());
 
-  G_OBJECT_CLASS (ide_device_manager_parent_class)->constructed (object);
+  ide_clear_and_destroy_object (&self->providers);
 
-  ide_device_manager_add_local (self);
-  ide_device_manager_add_providers (self);
-}
-
-static void
-ide_device_manager_dispose (GObject *object)
-{
-  IdeDeviceManager *self = (IdeDeviceManager *)object;
+  IDE_OBJECT_CLASS (ide_device_manager_parent_class)->destroy (object);
 
   if (self->devices->len > 0)
     g_ptr_array_remove_range (self->devices, 0, self->devices->len);
 
   g_clear_object (&self->device);
-  g_clear_object (&self->providers);
-
-  G_OBJECT_CLASS (ide_device_manager_parent_class)->dispose (object);
 }
 
 static void
@@ -517,13 +481,14 @@ static void
 ide_device_manager_class_init (IdeDeviceManagerClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
 
-  object_class->constructed = ide_device_manager_constructed;
-  object_class->dispose = ide_device_manager_dispose;
   object_class->finalize = ide_device_manager_finalize;
   object_class->get_property = ide_device_manager_get_property;
   object_class->set_property = ide_device_manager_set_property;
 
+  i_object_class->destroy = ide_device_manager_destroy;
+
   /**
    * IdeDeviceManager:device:
    *
@@ -731,7 +696,7 @@ ide_device_manager_action_deploy (IdeDeviceManager *self,
   g_assert (IDE_IS_DEVICE_MANAGER (self));
 
   context = ide_object_get_context (IDE_OBJECT (self));
-  build_manager = ide_context_get_build_manager (context);
+  build_manager = ide_build_manager_from_context (context);
   pipeline = ide_build_manager_get_pipeline (build_manager);
 
   if (!ide_build_pipeline_is_ready (pipeline))
@@ -763,14 +728,15 @@ collect_strategies (PeasExtensionSet *set,
                     PeasExtension    *exten,
                     gpointer          user_data)
 {
-  GPtrArray *strategies = user_data;
+  IdeObjectArray *strategies = user_data;
+  IdeDeployStrategy *strategy = (IdeDeployStrategy *)exten;
 
   g_assert (PEAS_IS_EXTENSION_SET (set));
   g_assert (plugin_info != NULL);
-  g_assert (IDE_IS_DEPLOY_STRATEGY (exten));
+  g_assert (IDE_IS_DEPLOY_STRATEGY (strategy));
   g_assert (strategies != NULL);
 
-  g_ptr_array_add (strategies, g_object_ref (exten));
+  ide_object_array_add (strategies, strategy);
 }
 
 static void
@@ -793,6 +759,8 @@ ide_device_manager_deploy_cb (GObject      *object,
   else
     ide_task_return_boolean (task, TRUE);
 
+  ide_object_destroy (IDE_OBJECT (strategy));
+
   IDE_EXIT;
 }
 
@@ -816,6 +784,7 @@ ide_device_manager_deploy_load_cb (GObject      *object,
   if (!ide_deploy_strategy_load_finish (strategy, result, &error))
     {
       g_debug ("Deploy strategy failed to load: %s", error->message);
+      ide_object_destroy (IDE_OBJECT (strategy));
       ide_device_manager_deploy_tick (task);
       IDE_EXIT;
     }
@@ -867,8 +836,7 @@ ide_device_manager_deploy_tick (IdeTask *task)
       IDE_EXIT;
     }
 
-  strategy = g_object_ref (g_ptr_array_index (state->strategies, 0));
-  g_ptr_array_remove_index (state->strategies, 0);
+  strategy = ide_object_array_steal_index (state->strategies, 0);
 
   ide_deploy_strategy_load_async (strategy,
                                   state->pipeline,
@@ -920,7 +888,6 @@ ide_device_manager_deploy_async (IdeDeviceManager    *self,
   g_autoptr(PeasExtensionSet) set = NULL;
   g_autoptr(IdeTask) task = NULL;
   DeployState *state;
-  IdeContext *context;
   IdeDevice *device;
 
   IDE_ENTRY;
@@ -960,16 +927,19 @@ ide_device_manager_deploy_async (IdeDeviceManager    *self,
 
   state = g_slice_new0 (DeployState);
   state->pipeline = g_object_ref (pipeline);
-  state->strategies = g_ptr_array_new_with_free_func (g_object_unref);
+  state->strategies = ide_object_array_new ();
   ide_task_set_task_data (task, state, deploy_state_free);
 
-  context = ide_object_get_context (IDE_OBJECT (self));
   set = peas_extension_set_new (peas_engine_get_default (),
                                 IDE_TYPE_DEPLOY_STRATEGY,
-                                "context", context,
                                 NULL);
   peas_extension_set_foreach (set, collect_strategies, state->strategies);
 
+  /* Root the addins as children of us so that they get context access */
+  for (guint i = 0; i < state->strategies->len; i++)
+    ide_object_append (IDE_OBJECT (self),
+                       ide_object_array_index (state->strategies, i));
+
   ide_device_manager_deploy_tick (task);
 
   IDE_EXIT;
@@ -1020,3 +990,148 @@ _ide_device_manager_get_menu (IdeDeviceManager *self)
 
   return self->menu;
 }
+
+static void
+ide_device_manager_init_provider_load_cb (GObject      *object,
+                                          GAsyncResult *result,
+                                          gpointer      user_data)
+{
+  IdeDeviceProvider *provider = (IdeDeviceProvider *)object;
+  g_autoptr(IdeTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+  InitState *state;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_DEVICE_PROVIDER (provider));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (IDE_IS_TASK (task));
+
+  if (!ide_device_provider_load_finish (provider, result, &error))
+    g_warning ("%s: %s", G_OBJECT_TYPE_NAME (provider), error->message);
+
+  state = ide_task_get_task_data (task);
+  state->n_active--;
+
+  if (state->n_active == 0)
+    ide_task_return_boolean (task, TRUE);
+}
+
+static void
+ide_device_manager_init_provider_cb (IdeExtensionSetAdapter *set,
+                                     PeasPluginInfo         *plugin_info,
+                                     PeasExtension          *exten,
+                                     gpointer                user_data)
+{
+  IdeDeviceProvider *provider = (IdeDeviceProvider *)exten;
+  IdeDeviceManager *self;
+  IdeTask *task = user_data;
+  InitState *state;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
+  g_assert (plugin_info != NULL);
+  g_assert (IDE_IS_DEVICE_PROVIDER (provider));
+  g_assert (IDE_IS_TASK (task));
+
+  self = ide_task_get_source_object (task);
+  state = ide_task_get_task_data (task);
+  state->n_active++;
+
+  g_signal_connect_object (provider,
+                           "device-added",
+                           G_CALLBACK (ide_device_manager_provider_device_added_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (provider,
+                           "device-removed",
+                           G_CALLBACK (ide_device_manager_provider_device_removed_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  ide_device_provider_load_async (provider,
+                                  ide_task_get_cancellable (task),
+                                  ide_device_manager_init_provider_load_cb,
+                                  g_object_ref (task));
+}
+
+static void
+ide_device_manager_init_async (GAsyncInitable      *initable,
+                               gint                 io_priority,
+                               GCancellable        *cancellable,
+                               GAsyncReadyCallback  callback,
+                               gpointer             user_data)
+{
+  IdeDeviceManager *self = (IdeDeviceManager *)initable;
+  g_autoptr(IdeTask) task = NULL;
+  InitState *state;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_DEVICE_MANAGER (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = ide_task_new (self, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, ide_device_manager_init_async);
+  ide_task_set_priority (task, io_priority);
+
+  self->loading = TRUE;
+
+  state = g_new0 (InitState, 1);
+  ide_task_set_task_data (task, state, g_free);
+
+  ide_device_manager_add_local (self);
+
+  self->providers = ide_extension_set_adapter_new (IDE_OBJECT (self),
+                                                   peas_engine_get_default (),
+                                                   IDE_TYPE_DEVICE_PROVIDER,
+                                                   NULL, NULL);
+
+  g_signal_connect (self->providers,
+                    "extension-added",
+                    G_CALLBACK (ide_device_manager_provider_added_cb),
+                    self);
+
+  g_signal_connect (self->providers,
+                    "extension-removed",
+                    G_CALLBACK (ide_device_manager_provider_removed_cb),
+                    self);
+
+  ide_extension_set_adapter_foreach (self->providers,
+                                     ide_device_manager_init_provider_cb,
+                                     task);
+
+  if (state->n_active == 0)
+    ide_task_return_boolean (task, TRUE);
+
+  IDE_EXIT;
+}
+
+static gboolean
+ide_device_manager_init_finish (GAsyncInitable  *initable,
+                                GAsyncResult    *result,
+                                GError         **error)
+{
+  IdeDeviceManager *self = (IdeDeviceManager *)initable;
+  gboolean ret;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_DEVICE_MANAGER (initable));
+  g_assert (IDE_IS_TASK (result));
+
+  self->loading = FALSE;
+
+  ret = ide_task_propagate_boolean (IDE_TASK (result), error);
+
+  IDE_RETURN (ret);
+}
+
+static void
+async_initable_init_iface (GAsyncInitableIface *iface)
+{
+  iface->init_async = ide_device_manager_init_async;
+  iface->init_finish = ide_device_manager_init_finish;
+}
diff --git a/src/libide/devices/ide-device-manager.h b/src/libide/foundry/ide-device-manager.h
similarity index 88%
rename from src/libide/devices/ide-device-manager.h
rename to src/libide/foundry/ide-device-manager.h
index 9b379f7f6..096849d0d 100644
--- a/src/libide/devices/ide-device-manager.h
+++ b/src/libide/foundry/ide-device-manager.h
@@ -20,8 +20,13 @@
 
 #pragma once
 
-#include "ide-object.h"
-#include "ide-version-macros.h"
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
+
+#include <libide-core.h>
+
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
@@ -30,6 +35,8 @@ G_BEGIN_DECLS
 IDE_AVAILABLE_IN_3_32
 G_DECLARE_FINAL_TYPE (IdeDeviceManager, ide_device_manager, IDE, DEVICE_MANAGER, IdeObject)
 
+IDE_AVAILABLE_IN_3_32
+IdeDeviceManager        *ide_device_manager_from_context        (IdeContext *context);
 IDE_AVAILABLE_IN_3_32
 gdouble    ide_device_manager_get_progress     (IdeDeviceManager     *self);
 IDE_AVAILABLE_IN_3_32
diff --git a/src/libide/devices/ide-device-private.h b/src/libide/foundry/ide-device-private.h
similarity index 100%
rename from src/libide/devices/ide-device-private.h
rename to src/libide/foundry/ide-device-private.h
diff --git a/src/libide/devices/ide-device-provider.c b/src/libide/foundry/ide-device-provider.c
similarity index 99%
rename from src/libide/devices/ide-device-provider.c
rename to src/libide/foundry/ide-device-provider.c
index c33987605..e83787a66 100644
--- a/src/libide/devices/ide-device-provider.c
+++ b/src/libide/foundry/ide-device-provider.c
@@ -22,7 +22,8 @@
 
 #include "config.h"
 
-#include "devices/ide-device-provider.h"
+#include "ide-device.h"
+#include "ide-device-provider.h"
 
 typedef struct
 {
diff --git a/src/libide/devices/ide-device-provider.h b/src/libide/foundry/ide-device-provider.h
similarity index 93%
rename from src/libide/devices/ide-device-provider.h
rename to src/libide/foundry/ide-device-provider.h
index 5b68824e9..13ebcc6be 100644
--- a/src/libide/devices/ide-device-provider.h
+++ b/src/libide/foundry/ide-device-provider.h
@@ -20,10 +20,13 @@
 
 #pragma once
 
-#include "ide-object.h"
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "devices/ide-device.h"
-#include "ide-version-macros.h"
+#include <libide-core.h>
+
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/libide/devices/ide-device.c b/src/libide/foundry/ide-device.c
similarity index 98%
rename from src/libide/devices/ide-device.c
rename to src/libide/foundry/ide-device.c
index 2b0b31fea..a5fcb2b65 100644
--- a/src/libide/devices/ide-device.c
+++ b/src/libide/foundry/ide-device.c
@@ -23,11 +23,11 @@
 #include "config.h"
 
 #include <glib/gi18n.h>
+#include <libide-threading.h>
 
-#include "ide-debug.h"
-
-#include "config/ide-configuration.h"
-#include "devices/ide-device.h"
+#include "ide-configuration.h"
+#include "ide-device.h"
+#include "ide-device-info.h"
 
 typedef struct
 {
diff --git a/src/libide/devices/ide-device.h b/src/libide/foundry/ide-device.h
similarity index 94%
rename from src/libide/devices/ide-device.h
rename to src/libide/foundry/ide-device.h
index ee83a4f73..b14a68f24 100644
--- a/src/libide/devices/ide-device.h
+++ b/src/libide/foundry/ide-device.h
@@ -20,11 +20,13 @@
 
 #pragma once
 
-#include "ide-object.h"
-#include "ide-types.h"
-#include "ide-version-macros.h"
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "devices/ide-device-info.h"
+#include <libide-core.h>
+
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
@@ -53,6 +55,7 @@ struct _IdeDeviceClass
                                            GAsyncResult         *result,
                                            GError              **error);
 
+  /*< private >*/
   gpointer _reserved[32];
 };
 
diff --git a/src/libide/foundry/ide-fallback-build-system.c b/src/libide/foundry/ide-fallback-build-system.c
new file mode 100644
index 000000000..9768dbf64
--- /dev/null
+++ b/src/libide/foundry/ide-fallback-build-system.c
@@ -0,0 +1,169 @@
+/* ide-fallback-build-system.c
+ *
+ * Copyright 2015-2019 Christian Hergert <christian hergert me>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "fallback-build-system"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "ide-fallback-build-system.h"
+
+struct _IdeFallbackBuildSystem
+{
+  IdeObject  parent_instance;
+  GFile     *project_file;
+};
+
+static void build_system_init (IdeBuildSystemInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (IdeFallbackBuildSystem,
+                         ide_fallback_build_system,
+                         IDE_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_BUILD_SYSTEM, build_system_init))
+
+enum {
+  PROP_0,
+  PROP_PROJECT_FILE,
+  LAST_PROP
+};
+
+static GParamSpec *properties [LAST_PROP];
+
+static void
+ide_fallback_build_system_finalize (GObject *object)
+{
+  IdeFallbackBuildSystem *self = (IdeFallbackBuildSystem *)object;
+
+  g_clear_object (&self->project_file);
+
+  G_OBJECT_CLASS (ide_fallback_build_system_parent_class)->finalize (object);
+}
+
+static void
+ide_fallback_build_system_get_property (GObject    *object,
+                                        guint       prop_id,
+                                        GValue     *value,
+                                        GParamSpec *pspec)
+{
+  IdeFallbackBuildSystem *self = IDE_FALLBACK_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
+ide_fallback_build_system_set_property (GObject      *object,
+                                        guint         prop_id,
+                                        const GValue *value,
+                                        GParamSpec   *pspec)
+{
+  IdeFallbackBuildSystem *self = IDE_FALLBACK_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
+ide_fallback_build_system_class_init (IdeFallbackBuildSystemClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = ide_fallback_build_system_finalize;
+  object_class->get_property = ide_fallback_build_system_get_property;
+  object_class->set_property = ide_fallback_build_system_set_property;
+
+  /**
+   * IdeFallbackBuildSystem:project-file:
+   *
+   * The "project-file" property is the primary file representing the
+   * projects build system.
+   *
+   * Since: 3.32
+   */
+  properties [PROP_PROJECT_FILE] =
+    g_param_spec_object ("project-file",
+                         "Project File",
+                         "The path of the project file.",
+                         G_TYPE_FILE,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, LAST_PROP, properties);
+}
+
+static void
+ide_fallback_build_system_init (IdeFallbackBuildSystem *self)
+{
+}
+
+static gint
+ide_fallback_build_system_get_priority (IdeBuildSystem *build_system)
+{
+  return 1000000;
+}
+
+static gchar *
+ide_fallback_build_system_get_id (IdeBuildSystem *build_system)
+{
+  return g_strdup ("fallback");
+}
+
+static gchar *
+ide_fallback_build_system_get_display_name (IdeBuildSystem *build_system)
+{
+  return g_strdup (_("Fallback"));
+}
+
+static void
+build_system_init (IdeBuildSystemInterface *iface)
+{
+  iface->get_priority = ide_fallback_build_system_get_priority;
+  iface->get_id = ide_fallback_build_system_get_id;
+  iface->get_display_name = ide_fallback_build_system_get_display_name;
+}
+
+/**
+ * ide_fallback_build_system_new:
+ *
+ * Creates a new #IdeFallbackBuildSystem.
+ *
+ * Returns: (transfer full): an #IdeBuildSystem
+ *
+ * Since: 3.32
+ */
+IdeBuildSystem *
+ide_fallback_build_system_new (void)
+{
+  return g_object_new (IDE_TYPE_FALLBACK_BUILD_SYSTEM, NULL);
+}
diff --git a/src/libide/directory/ide-directory-vcs.h b/src/libide/foundry/ide-fallback-build-system.h
similarity index 71%
rename from src/libide/directory/ide-directory-vcs.h
rename to src/libide/foundry/ide-fallback-build-system.h
index 324be3480..b336c913a 100644
--- a/src/libide/directory/ide-directory-vcs.h
+++ b/src/libide/foundry/ide-fallback-build-system.h
@@ -1,4 +1,4 @@
-/* ide-directory-vcs.h
+/* ide-fallback-build-system.h
  *
  * Copyright 2015-2019 Christian Hergert <christian hergert me>
  *
@@ -20,15 +20,16 @@
 
 #pragma once
 
-#include "ide-version-macros.h"
-
-#include "vcs/ide-vcs.h"
+#include "ide-build-system.h"
 
 G_BEGIN_DECLS
 
-#define IDE_TYPE_DIRECTORY_VCS (ide_directory_vcs_get_type())
+#define IDE_TYPE_FALLBACK_BUILD_SYSTEM (ide_fallback_build_system_get_type())
+
+IDE_AVAILABLE_IN_3_32
+G_DECLARE_FINAL_TYPE (IdeFallbackBuildSystem, ide_fallback_build_system, IDE, FALLBACK_BUILD_SYSTEM, 
IdeObject)
 
 IDE_AVAILABLE_IN_3_32
-G_DECLARE_FINAL_TYPE (IdeDirectoryVcs, ide_directory_vcs, IDE, DIRECTORY_VCS, IdeObject)
+IdeBuildSystem *ide_fallback_build_system_new (void);
 
 G_END_DECLS
diff --git a/src/libide/foundry/ide-foundry-compat.c b/src/libide/foundry/ide-foundry-compat.c
new file mode 100644
index 000000000..04051ef46
--- /dev/null
+++ b/src/libide/foundry/ide-foundry-compat.c
@@ -0,0 +1,227 @@
+/* ide-foundry-compat.c
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-foundry-compat"
+
+#include "config.h"
+
+#include "ide-build-manager.h"
+#include "ide-build-system.h"
+#include "ide-device-manager.h"
+#include "ide-configuration-manager.h"
+#include "ide-foundry-compat.h"
+#include "ide-run-manager.h"
+#include "ide-runtime-manager.h"
+#include "ide-test-manager.h"
+#include "ide-toolchain-manager.h"
+
+static gpointer
+ensure_child_typed_borrowed (IdeContext *context,
+                             GType       child_type)
+{
+  gpointer ret;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_CONTEXT (context));
+
+  if (!(ret = ide_context_peek_child_typed (context, child_type)))
+    {
+      g_autoptr(IdeObject) child = NULL;
+
+      if (!ide_context_has_project (context))
+        {
+          g_critical ("A plugin has attempted to access the %s foundry subsystem before a project has been 
loaded. "
+                      "This is not supported and may cause undesired behavior.",
+                      g_type_name (child_type));
+        }
+
+      child = ide_object_ensure_child_typed (IDE_OBJECT (context), child_type);
+      ret = ide_context_peek_child_typed (context, child_type);
+    }
+
+  return ret;
+}
+
+static gpointer
+get_child_typed_borrowed (IdeContext *context,
+                          GType       child_type)
+{
+  GObject *ret;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_CONTEXT (context));
+
+  /* We get a full ref to the child, but we want to return a borrowed
+   * reference to the manager. Since we're on the main thread, we can
+   * guarantee that no destroy will happen (since that has to happen
+   * in the main thread).
+   */
+  if ((ret = ide_object_get_child_typed (IDE_OBJECT (context), child_type)))
+    g_object_unref (ret);
+
+  return ret;
+}
+
+/**
+ * ide_build_manager_from_context:
+ * @context: a #IdeContext
+ *
+ * Returns: (transfer none): an #IdeBuildManager
+ *
+ * Since: 3.32
+ */
+IdeBuildManager *
+ide_build_manager_from_context (IdeContext *context)
+{
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+  return ensure_child_typed_borrowed (context, IDE_TYPE_BUILD_MANAGER);
+}
+
+/**
+ * ide_build_manager_ref_from_context:
+ * @context: a #IdeContext
+ *
+ * Returns: (transfer full): an #IdeBuildManager
+ *
+ * Since: 3.32
+ */
+IdeBuildManager *
+ide_build_manager_ref_from_context (IdeContext *context)
+{
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+  return ide_object_ensure_child_typed (IDE_OBJECT (context), IDE_TYPE_BUILD_MANAGER);
+}
+
+/**
+ * ide_build_system_from_context:
+ * @context: a #IdeContext
+ *
+ * Gets the build system for the context. If no build system has been
+ * registered, then this returns %NULL.
+ *
+ * Returns: (transfer none) (nullable): an #IdeBuildSystem
+ *
+ * Since: 3.32
+ */
+IdeBuildSystem *
+ide_build_system_from_context (IdeContext *context)
+{
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+  return get_child_typed_borrowed (context, IDE_TYPE_BUILD_SYSTEM);
+}
+
+/**
+ * ide_configuration_manager_from_context:
+ * @context: a #IdeContext
+ *
+ * Returns: (transfer none): an #IdeConfigurationManager
+ *
+ * Since: 3.32
+ */
+IdeConfigurationManager *
+ide_configuration_manager_from_context (IdeContext *context)
+{
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+  return ensure_child_typed_borrowed (context, IDE_TYPE_CONFIGURATION_MANAGER);
+}
+
+/**
+ * ide_device_manager_from_context:
+ * @context: a #IdeContext
+ *
+ * Returns: (transfer none): an #IdeDeviceManager
+ *
+ * Since: 3.32
+ */
+IdeDeviceManager *
+ide_device_manager_from_context (IdeContext *context)
+{
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+  return ensure_child_typed_borrowed (context, IDE_TYPE_DEVICE_MANAGER);
+}
+
+/**
+ * ide_toolchain_manager_from_context:
+ * @context: a #IdeContext
+ *
+ * Returns: (transfer none): an #IdeToolchainManager
+ *
+ * Since: 3.32
+ */
+IdeToolchainManager *
+ide_toolchain_manager_from_context (IdeContext *context)
+{
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+  return ensure_child_typed_borrowed (context, IDE_TYPE_TOOLCHAIN_MANAGER);
+}
+
+/**
+ * ide_run_manager_from_context:
+ * @context: a #IdeContext
+ *
+ * Returns: (transfer none): an #IdeRunManager
+ *
+ * Since: 3.32
+ */
+IdeRunManager *
+ide_run_manager_from_context (IdeContext *context)
+{
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+  return ensure_child_typed_borrowed (context, IDE_TYPE_RUN_MANAGER);
+}
+
+/**
+ * ide_runtime_manager_from_context:
+ * @context: a #IdeContext
+ *
+ * Returns: (transfer none): an #IdeRuntimeManager
+ *
+ * Since: 3.32
+ */
+IdeRuntimeManager *
+ide_runtime_manager_from_context (IdeContext *context)
+{
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+  return ensure_child_typed_borrowed (context, IDE_TYPE_RUNTIME_MANAGER);
+}
+
+/**
+ * ide_test_manager_from_context:
+ * @context: a #IdeContext
+ *
+ * Returns: (transfer none): an #IdeTestManager
+ *
+ * Since: 3.32
+ */
+IdeTestManager *
+ide_test_manager_from_context (IdeContext *context)
+{
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+  return ensure_child_typed_borrowed (context, IDE_TYPE_TEST_MANAGER);
+}
diff --git a/src/libide/directory/ide-directory-build-system.h b/src/libide/foundry/ide-foundry-compat.h
similarity index 67%
rename from src/libide/directory/ide-directory-build-system.h
rename to src/libide/foundry/ide-foundry-compat.h
index 4426fc1df..a8acb5e00 100644
--- a/src/libide/directory/ide-directory-build-system.h
+++ b/src/libide/foundry/ide-foundry-compat.h
@@ -1,6 +1,6 @@
-/* ide-directory-build-system.h
+/* ide-foundry-compat.h
  *
- * Copyright 2015-2019 Christian Hergert <christian hergert me>
+ * Copyright 2018-2019 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
@@ -20,15 +20,17 @@
 
 #pragma once
 
-#include "ide-version-macros.h"
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "buildsystem/ide-build-system.h"
+#include <libide-core.h>
 
-G_BEGIN_DECLS
+#include "ide-foundry-types.h"
 
-#define IDE_TYPE_DIRECTORY_BUILD_SYSTEM (ide_directory_build_system_get_type())
+G_BEGIN_DECLS
 
 IDE_AVAILABLE_IN_3_32
-G_DECLARE_FINAL_TYPE (IdeDirectoryBuildSystem, ide_directory_build_system, IDE, DIRECTORY_BUILD_SYSTEM, 
IdeObject)
+IdeToolchainManager     *ide_toolchain_manager_from_context     (IdeContext *context);
 
 G_END_DECLS
diff --git a/src/libide/foundry/ide-foundry-init.c b/src/libide/foundry/ide-foundry-init.c
new file mode 100644
index 000000000..91a04a6ca
--- /dev/null
+++ b/src/libide/foundry/ide-foundry-init.c
@@ -0,0 +1,161 @@
+/* ide-foundry-init.c
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-foundry-init"
+
+#include "config.h"
+
+#include <libide-threading.h>
+
+#include "ide-build-manager.h"
+#include "ide-device-manager.h"
+#include "ide-configuration-manager.h"
+#include "ide-foundry-init.h"
+#include "ide-run-manager.h"
+#include "ide-runtime-manager.h"
+#include "ide-test-manager.h"
+#include "ide-toolchain-manager.h"
+
+typedef struct
+{
+  GQueue to_init;
+} FoundryInit;
+
+static void
+foundry_init_free (FoundryInit *state)
+{
+  g_queue_foreach (&state->to_init, (GFunc)g_object_unref, NULL);
+  g_queue_clear (&state->to_init);
+  g_slice_free (FoundryInit, state);
+}
+
+static void
+ide_foundry_init_async_cb (GObject      *init_object,
+                           GAsyncResult *result,
+                           gpointer      user_data)
+{
+  GAsyncInitable *initable = (GAsyncInitable *)init_object;
+  g_autoptr(IdeTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+  FoundryInit *state;
+  GCancellable *cancellable;
+
+  g_assert (G_IS_ASYNC_INITABLE (initable));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (IDE_IS_TASK (task));
+
+  if (!g_async_initable_init_finish (initable, result, &error))
+    g_warning ("Failed to init %s: %s",
+               G_OBJECT_TYPE_NAME (initable), error->message);
+
+  state = ide_task_get_task_data (task);
+  cancellable = ide_task_get_cancellable (task);
+
+  while (state->to_init.head)
+    {
+      g_autoptr(IdeObject) object = g_queue_pop_head (&state->to_init);
+
+      if (G_IS_ASYNC_INITABLE (object))
+        {
+          g_async_initable_init_async (G_ASYNC_INITABLE (object),
+                                       G_PRIORITY_DEFAULT,
+                                       cancellable,
+                                       ide_foundry_init_async_cb,
+                                       g_steal_pointer (&task));
+          return;
+        }
+
+      if (G_IS_INITABLE (object))
+        g_initable_init (G_INITABLE (object), NULL, NULL);
+    }
+
+  ide_task_return_boolean (task, TRUE);
+}
+
+void
+_ide_foundry_init_async (IdeContext          *context,
+                         GCancellable        *cancellable,
+                         GAsyncReadyCallback  callback,
+                         gpointer             user_data)
+{
+  g_autoptr(IdeTask) task = NULL;
+  FoundryInit *state;
+  GType foundry_types[] = {
+    IDE_TYPE_DEVICE_MANAGER,
+    IDE_TYPE_RUNTIME_MANAGER,
+    IDE_TYPE_TOOLCHAIN_MANAGER,
+    IDE_TYPE_CONFIGURATION_MANAGER,
+    IDE_TYPE_BUILD_MANAGER,
+    IDE_TYPE_RUN_MANAGER,
+    IDE_TYPE_TEST_MANAGER,
+  };
+
+  g_return_if_fail (IDE_IS_CONTEXT (context));
+
+  state = g_slice_new0 (FoundryInit);
+  g_queue_init (&state->to_init);
+
+  task = ide_task_new (context, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, _ide_foundry_init_async);
+  ide_task_set_task_data (task, state, foundry_init_free);
+
+  for (guint i = 0; i < G_N_ELEMENTS (foundry_types); i++)
+    {
+      g_autoptr(IdeObject) object = NULL;
+
+      /* Skip if plugins already forced this subsystem to load */
+      if ((object = ide_object_get_child_typed (IDE_OBJECT (context), foundry_types[i])))
+        continue;
+
+      object = g_object_new (foundry_types[i], NULL);
+      ide_object_append (IDE_OBJECT (context), object);
+      g_queue_push_tail (&state->to_init, g_steal_pointer (&object));
+    }
+
+  while (state->to_init.head)
+    {
+      g_autoptr(IdeObject) object = g_queue_pop_head (&state->to_init);
+
+      if (G_IS_ASYNC_INITABLE (object))
+        {
+          g_async_initable_init_async (G_ASYNC_INITABLE (object),
+                                       G_PRIORITY_DEFAULT,
+                                       NULL,
+                                       ide_foundry_init_async_cb,
+                                       g_steal_pointer (&task));
+          return;
+        }
+
+      if (G_IS_INITABLE (object))
+        g_initable_init (G_INITABLE (object), NULL, NULL);
+    }
+
+  ide_task_return_boolean (task, TRUE);
+}
+
+gboolean
+_ide_foundry_init_finish (GAsyncResult  *result,
+                          GError       **error)
+{
+  g_return_val_if_fail (IDE_IS_MAIN_THREAD (), FALSE);
+  g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
+
+  return ide_task_propagate_boolean (IDE_TASK (result), error);
+}
diff --git a/src/libide/foundry/ide-foundry-init.h b/src/libide/foundry/ide-foundry-init.h
new file mode 100644
index 000000000..a12915b16
--- /dev/null
+++ b/src/libide/foundry/ide-foundry-init.h
@@ -0,0 +1,34 @@
+/* ide-foundry-init.h
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+void     _ide_foundry_init_async  (IdeContext           *context,
+                                   GCancellable         *cancellable,
+                                   GAsyncReadyCallback   callback,
+                                   gpointer              user_data);
+gboolean _ide_foundry_init_finish (GAsyncResult         *result,
+                                   GError              **error);
+
+G_END_DECLS
diff --git a/src/libide/foundry/ide-foundry-types.h b/src/libide/foundry/ide-foundry-types.h
new file mode 100644
index 000000000..442f730e2
--- /dev/null
+++ b/src/libide/foundry/ide-foundry-types.h
@@ -0,0 +1,71 @@
+/* ide-foundry-types.h
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _IdeBuildLog IdeBuildLog;
+typedef struct _IdeBuildManager IdeBuildManager;
+typedef struct _IdeBuildPipeline IdeBuildPipeline;
+typedef struct _IdeBuildPipelineAddin IdeBuildPipelineAddin;
+typedef struct _IdeBuildStage IdeBuildStage;
+typedef struct _IdeBuildStageLauncher IdeBuildStageLauncher;
+typedef struct _IdeBuildStageMkdirs IdeBuildStageMkdirs;
+typedef struct _IdeBuildStageTransfer IdeBuildStageTransfer;
+typedef struct _IdeBuildSystem IdeBuildSystem;
+typedef struct _IdeBuildSystemDiscovery IdeBuildSystemDiscovery;
+typedef struct _IdeBuildTarget IdeBuildTarget;
+typedef struct _IdeBuildTargetProvider IdeBuildTargetProvider;
+typedef struct _IdeCompileCommands IdeCompileCommands;
+typedef struct _IdeConfiguration IdeConfiguration;
+typedef struct _IdeConfigurationProvider IdeConfigurationProvider;
+typedef struct _IdeConfigurationManager IdeConfigurationManager;
+typedef struct _IdeDependencyUpdater IdeDependencyUpdater;
+typedef struct _IdeDeployStrategy IdeDeployStrategy;
+typedef struct _IdeDevice IdeDevice;
+typedef struct _IdeDeviceInfo IdeDeviceInfo;
+typedef struct _IdeDeviceManager IdeDeviceManager;
+typedef struct _IdeDeviceProvider IdeDeviceProvider;
+typedef struct _IdeLocalDevice IdeLocalDevice;
+typedef struct _IdeRunButton IdeRunButton;
+typedef struct _IdeRunManager IdeRunManager;
+typedef struct _IdeRunner IdeRunner;
+typedef struct _IdeRunnerAddin IdeRunnerAddin;
+typedef struct _IdeRuntime IdeRuntime;
+typedef struct _IdeRuntimeManager IdeRuntimeManager;
+typedef struct _IdeRuntimeProvider IdeRuntimeProvider;
+typedef struct _IdeSimpleBuildTarget IdeSimpleBuildTarget;
+typedef struct _IdeSimpleToolchain IdeSimpleToolchain;
+typedef struct _IdeTriplet IdeTriplet;
+typedef struct _IdeTest IdeTest;
+typedef struct _IdeTestManager IdeTestManager;
+typedef struct _IdeTestProvider IdeTestProvider;
+typedef struct _IdeToolchain IdeToolchain;
+typedef struct _IdeToolchainManager IdeToolchainManager;
+typedef struct _IdeToolchainProvider IdeToolchainProvider;
+
+G_END_DECLS
diff --git a/src/libide/local/ide-local-device.c b/src/libide/foundry/ide-local-device.c
similarity index 97%
rename from src/libide/local/ide-local-device.c
rename to src/libide/foundry/ide-local-device.c
index a8420d9cf..50cc16a52 100644
--- a/src/libide/local/ide-local-device.c
+++ b/src/libide/foundry/ide-local-device.c
@@ -23,13 +23,14 @@
 #include "config.h"
 
 #include <glib/gi18n.h>
+#include <libide-threading.h>
 #include <string.h>
 #include <sys/utsname.h>
 
-#include "local/ide-local-device.h"
-#include "util/ide-posix.h"
-#include "util/ide-triplet.h"
-#include "threading/ide-task.h"
+#include "ide-local-device.h"
+#include "ide-device.h"
+#include "ide-device-info.h"
+#include "ide-triplet.h"
 
 typedef struct
 {
diff --git a/src/libide/local/ide-local-device.h b/src/libide/foundry/ide-local-device.h
similarity index 85%
rename from src/libide/local/ide-local-device.h
rename to src/libide/foundry/ide-local-device.h
index 98d361963..1f4e5f1b3 100644
--- a/src/libide/local/ide-local-device.h
+++ b/src/libide/foundry/ide-local-device.h
@@ -20,9 +20,13 @@
 
 #pragma once
 
-#include "ide-version-macros.h"
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "devices/ide-device.h"
+#include <libide-core.h>
+
+#include "ide-device.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/libide/runner/ide-run-manager-private.h b/src/libide/foundry/ide-run-manager-private.h
similarity index 97%
rename from src/libide/runner/ide-run-manager-private.h
rename to src/libide/foundry/ide-run-manager-private.h
index cb78c1e0c..18c26d27b 100644
--- a/src/libide/runner/ide-run-manager-private.h
+++ b/src/libide/foundry/ide-run-manager-private.h
@@ -20,7 +20,7 @@
 
 #pragma once
 
-#include "runner/ide-run-manager.h"
+#include "ide-run-manager.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/libide/runner/ide-run-manager.c b/src/libide/foundry/ide-run-manager.c
similarity index 90%
rename from src/libide/runner/ide-run-manager.c
rename to src/libide/foundry/ide-run-manager.c
index e1ea53496..82e254fb9 100644
--- a/src/libide/runner/ide-run-manager.c
+++ b/src/libide/foundry/ide-run-manager.c
@@ -23,25 +23,21 @@
 #include "config.h"
 
 #include <glib/gi18n.h>
+#include <libide-threading.h>
 #include <libpeas/peas.h>
 #include <libpeas/peas-autocleanups.h>
 
-#include "ide-context.h"
-#include "ide-debug.h"
-
-#include "buildsystem/ide-build-manager.h"
-#include "buildsystem/ide-build-system.h"
-#include "buildsystem/ide-build-target.h"
-#include "buildsystem/ide-build-target-provider.h"
-#include "config/ide-configuration.h"
-#include "config/ide-configuration-manager.h"
-#include "buildsystem/ide-environment.h"
-#include "runner/ide-run-manager.h"
-#include "runner/ide-run-manager-private.h"
-#include "runner/ide-runner.h"
-#include "runtimes/ide-runtime.h"
-#include "threading/ide-task.h"
-#include "util/ide-glib.h"
+#include "ide-build-manager.h"
+#include "ide-build-system.h"
+#include "ide-build-target-provider.h"
+#include "ide-build-target.h"
+#include "ide-configuration-manager.h"
+#include "ide-configuration.h"
+#include "ide-foundry-compat.h"
+#include "ide-run-manager-private.h"
+#include "ide-run-manager.h"
+#include "ide-runner.h"
+#include "ide-runtime.h"
 
 struct _IdeRunManager
 {
@@ -49,6 +45,7 @@ struct _IdeRunManager
 
   GCancellable            *cancellable;
   IdeBuildTarget          *build_target;
+  IdeNotification         *notif;
 
   const IdeRunHandlerInfo *handler;
   GList                   *handlers;
@@ -150,7 +147,7 @@ ide_run_manager_dispose (GObject *object)
   self->handler = NULL;
 
   g_clear_object (&self->cancellable);
-  g_clear_object (&self->build_target);
+  ide_clear_and_destroy_object (&self->build_target);
 
   g_list_free_full (self->handlers, ide_run_handler_info_free);
   self->handlers = NULL;
@@ -168,7 +165,7 @@ ide_run_manager_update_action_enabled (IdeRunManager *self)
   g_assert (IDE_IS_RUN_MANAGER (self));
 
   context = ide_object_get_context (IDE_OBJECT (self));
-  build_manager = ide_context_get_build_manager (context);
+  build_manager = ide_build_manager_from_context (context);
   can_build = ide_build_manager_get_can_build (build_manager);
 
   ide_run_manager_set_action_enabled (self, "run",
@@ -209,7 +206,7 @@ initable_init (GInitable     *initable,
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
   context = ide_object_get_context (IDE_OBJECT (self));
-  build_manager = ide_context_get_build_manager (context);
+  build_manager = ide_build_manager_from_context (context);
 
   g_signal_connect_object (build_manager,
                            "notify::can-build",
@@ -400,6 +397,12 @@ ide_run_manager_run_cb (GObject      *object,
 
   self = ide_task_get_source_object (task);
 
+  if (self->notif != NULL)
+    {
+      ide_notification_withdraw (self->notif);
+      g_clear_object (&self->notif);
+    }
+
   if (!ide_runner_run_finish (runner, result, &error))
     ide_task_return_error (task, g_steal_pointer (&error));
   else
@@ -407,6 +410,8 @@ ide_run_manager_run_cb (GObject      *object,
 
   g_signal_emit (self, signals [STOPPED], 0);
 
+  ide_object_destroy (IDE_OBJECT (runner));
+
   IDE_EXIT;
 }
 
@@ -414,6 +419,8 @@ static void
 do_run_async (IdeRunManager *self,
               IdeTask       *task)
 {
+  g_autofree gchar *name = NULL;
+  g_autofree gchar *title = NULL;
   IdeBuildTarget *build_target;
   IdeContext *context;
   IdeConfigurationManager *config_manager;
@@ -435,7 +442,7 @@ do_run_async (IdeRunManager *self,
   g_assert (IDE_IS_BUILD_TARGET (build_target));
   g_assert (IDE_IS_CONTEXT (context));
 
-  config_manager = ide_context_get_configuration_manager (context);
+  config_manager = ide_configuration_manager_from_context (context);
   config = ide_configuration_manager_get_current (config_manager);
   runtime = ide_configuration_get_runtime (config);
 
@@ -483,12 +490,25 @@ do_run_async (IdeRunManager *self,
   if (ide_runner_get_failed (runner))
     {
       ide_task_return_new_error (task,
-                                 G_IO_ERROR,
-                                 G_IO_ERROR_FAILED,
+                                 IDE_RUNTIME_ERROR,
+                                 IDE_RUNTIME_ERROR_SPAWN_FAILED,
                                  "Failed to execute the application");
       IDE_EXIT;
     }
 
+  if (self->notif != NULL)
+    {
+      ide_notification_withdraw (self->notif);
+      g_clear_object (&self->notif);
+    }
+
+  self->notif = ide_notification_new ();
+  name = ide_build_target_get_name (build_target);
+  /* translators: %s is replaced with the name of the users executable */
+  title = g_strdup_printf (_("Running %s…"), name);
+  ide_notification_set_title (self->notif, title);
+  ide_notification_attach (self->notif, IDE_OBJECT (self));
+
   ide_runner_run_async (runner,
                         cancellable,
                         ide_run_manager_run_cb,
@@ -551,7 +571,16 @@ ide_run_manager_install_cb (GObject      *object,
 
   if (!ide_build_manager_execute_finish (build_manager, result, &error))
     {
-      ide_task_return_error (task, g_steal_pointer (&error));
+      /* We want to let the consumer know there was a build error
+       * (but don't need to pass the specific error code) so that
+       * they have an error code to check against.
+       */
+      ide_task_return_new_error (task,
+                                 IDE_RUNTIME_ERROR,
+                                 IDE_RUNTIME_ERROR_BUILD_FAILED,
+                                 /* translators: %s is replaced with the specific error reason */
+                                 _("The build target failed to build: %s"),
+                                 error->message);
       IDE_EXIT;
     }
 
@@ -608,7 +637,7 @@ ide_run_manager_do_install_before_run (IdeRunManager *self,
   g_assert (IDE_IS_TASK (task));
 
   context = ide_object_get_context (IDE_OBJECT (self));
-  build_manager = ide_context_get_build_manager (context);
+  build_manager = ide_build_manager_from_context (context);
 
   /*
    * First we need to make sure the target is up to date and installed
@@ -626,6 +655,7 @@ ide_run_manager_do_install_before_run (IdeRunManager *self,
 
   ide_build_manager_execute_async (build_manager,
                                    IDE_BUILD_PHASE_INSTALL,
+                                   NULL,
                                    ide_task_get_cancellable (task),
                                    ide_run_manager_install_cb,
                                    g_object_ref (task));
@@ -848,8 +878,16 @@ ide_run_manager_set_build_target (IdeRunManager  *self,
   g_return_if_fail (IDE_IS_RUN_MANAGER (self));
   g_return_if_fail (IDE_IS_BUILD_TARGET (build_target));
 
-  if (g_set_object (&self->build_target, build_target))
-    g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUILD_TARGET]);
+  if (build_target == self->build_target)
+    return;
+
+  if (self->build_target)
+    ide_clear_and_destroy_object (&self->build_target);
+
+  if (build_target)
+    self->build_target = g_object_ref (build_target);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUILD_TARGET]);
 }
 
 static gint
@@ -886,6 +924,7 @@ ide_run_manager_provider_get_targets_cb (GObject      *object,
   g_autoptr(IdeTask) task = user_data;
   g_autoptr(GPtrArray) ret = NULL;
   g_autoptr(GError) error = NULL;
+  IdeRunManager *self;
   DiscoverState *state;
 
   IDE_ENTRY;
@@ -894,8 +933,10 @@ ide_run_manager_provider_get_targets_cb (GObject      *object,
   g_assert (G_IS_ASYNC_RESULT (result));
   g_assert (IDE_IS_TASK (task));
 
+  self = ide_task_get_source_object (task);
   state = ide_task_get_task_data (task);
 
+  g_assert (IDE_IS_RUN_MANAGER (self));
   g_assert (state != NULL);
   g_assert (state->active > 0);
   g_assert (g_list_find (state->providers, provider) != NULL);
@@ -909,10 +950,14 @@ ide_run_manager_provider_get_targets_cb (GObject      *object,
         {
           IdeBuildTarget *target = g_ptr_array_index (ret, i);
 
+          ide_object_append (IDE_OBJECT (self), IDE_OBJECT (target));
+
           g_ptr_array_add (state->results, g_object_ref (target));
         }
     }
 
+  ide_object_destroy (IDE_OBJECT (provider));
+
   state->active--;
 
   if (state->active > 0)
@@ -924,9 +969,9 @@ ide_run_manager_provider_get_targets_cb (GObject      *object,
         ide_task_return_error (task, g_steal_pointer (&error));
       else
         ide_task_return_new_error (task,
-                                   G_IO_ERROR,
-                                   G_IO_ERROR_NOT_FOUND,
-                                   "Failed to locate a build target");
+                                   IDE_RUNTIME_ERROR,
+                                   IDE_RUNTIME_ERROR_TARGET_NOT_FOUND,
+                                   _("Failed to locate a build target"));
       IDE_EXIT;
     }
 
@@ -948,7 +993,6 @@ ide_run_manager_discover_default_target_async (IdeRunManager       *self,
   g_autoptr(PeasExtensionSet) set = NULL;
   g_autoptr(IdeTask) task = NULL;
   DiscoverState *state;
-  IdeContext *context;
 
   IDE_ENTRY;
 
@@ -959,20 +1003,20 @@ ide_run_manager_discover_default_target_async (IdeRunManager       *self,
   ide_task_set_source_tag (task, ide_run_manager_discover_default_target_async);
   ide_task_set_priority (task, G_PRIORITY_LOW);
 
-  context = ide_object_get_context (IDE_OBJECT (self));
-
   set = peas_extension_set_new (peas_engine_get_default (),
                                 IDE_TYPE_BUILD_TARGET_PROVIDER,
-                                "context", context,
                                 NULL);
 
   state = g_slice_new0 (DiscoverState);
-  state->results = g_ptr_array_new_with_free_func (g_object_unref);
+  state->results = g_ptr_array_new_with_free_func ((GDestroyNotify)ide_object_unref_and_destroy);
   state->providers = NULL;
   state->active = 0;
 
   peas_extension_set_foreach (set, collect_extensions, state);
 
+  for (const GList *iter = state->providers; iter; iter = iter->next)
+    ide_object_append (IDE_OBJECT (self), IDE_OBJECT (iter->data));
+
   ide_task_set_task_data (task, state, discover_state_free);
 
   for (const GList *iter = state->providers; iter != NULL; iter = iter->next)
@@ -987,9 +1031,9 @@ ide_run_manager_discover_default_target_async (IdeRunManager       *self,
 
   if (state->active == 0)
     ide_task_return_new_error (task,
-                               G_IO_ERROR,
-                               G_IO_ERROR_NOT_FOUND,
-                               "Failed to locate a build target");
+                               IDE_RUNTIME_ERROR,
+                               IDE_RUNTIME_ERROR_TARGET_NOT_FOUND,
+                               _("Failed to locate a build target"));
 
   IDE_EXIT;
 }
@@ -1093,7 +1137,7 @@ ide_run_manager_actions_run_with_handler (IdeRunManager *self,
   }
 
   /* Use specified handler, if provided */
-  if (!dzl_str_empty0 (handler))
+  if (!ide_str_empty0 (handler))
     ide_run_manager_set_handler (self, handler);
 
   ide_run_manager_run_async (self,
diff --git a/src/libide/runner/ide-run-manager.h b/src/libide/foundry/ide-run-manager.h
similarity index 92%
rename from src/libide/runner/ide-run-manager.h
rename to src/libide/foundry/ide-run-manager.h
index ac22043a4..3889bb9c1 100644
--- a/src/libide/runner/ide-run-manager.h
+++ b/src/libide/foundry/ide-run-manager.h
@@ -20,12 +20,13 @@
 
 #pragma once
 
-#include "ide-version-macros.h"
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "ide-object.h"
+#include <libide-core.h>
 
-#include "buildsystem/ide-build-target.h"
-#include "runner/ide-runner.h"
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
@@ -38,6 +39,8 @@ typedef void (*IdeRunHandler) (IdeRunManager *self,
                                IdeRunner     *runner,
                                gpointer       user_data);
 
+IDE_AVAILABLE_IN_3_32
+IdeRunManager  *ide_run_manager_from_context                   (IdeContext           *context);
 IDE_AVAILABLE_IN_3_32
 IdeBuildTarget *ide_run_manager_get_build_target               (IdeRunManager        *self);
 IDE_AVAILABLE_IN_3_32
@@ -81,7 +84,7 @@ void            ide_run_manager_discover_default_target_async  (IdeRunManager
                                                                 gpointer              user_data);
 IDE_AVAILABLE_IN_3_32
 IdeBuildTarget *ide_run_manager_discover_default_target_finish (IdeRunManager        *self,
-                                                                GAsyncResult        *result,
+                                                                GAsyncResult         *result,
                                                                 GError              **error);
 
 G_END_DECLS
diff --git a/src/libide/runner/ide-runner-addin.c b/src/libide/foundry/ide-runner-addin.c
similarity index 98%
rename from src/libide/runner/ide-runner-addin.c
rename to src/libide/foundry/ide-runner-addin.c
index 33b5ab867..e95223eb5 100644
--- a/src/libide/runner/ide-runner-addin.c
+++ b/src/libide/foundry/ide-runner-addin.c
@@ -22,8 +22,10 @@
 
 #include "config.h"
 
-#include "runner/ide-runner-addin.h"
-#include "threading/ide-task.h"
+#include <libide-threading.h>
+
+#include "ide-runner.h"
+#include "ide-runner-addin.h"
 
 G_DEFINE_INTERFACE (IdeRunnerAddin, ide_runner_addin, G_TYPE_OBJECT)
 
diff --git a/src/libide/runner/ide-runner-addin.h b/src/libide/foundry/ide-runner-addin.h
similarity index 94%
rename from src/libide/runner/ide-runner-addin.h
rename to src/libide/foundry/ide-runner-addin.h
index caed846af..41daf8ca7 100644
--- a/src/libide/runner/ide-runner-addin.h
+++ b/src/libide/foundry/ide-runner-addin.h
@@ -20,12 +20,13 @@
 
 #pragma once
 
-#include <gio/gio.h>
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "ide-version-macros.h"
+#include <libide-core.h>
 
-#include "ide-types.h"
-#include "runner/ide-runner.h"
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/libide/runner/ide-runner.c b/src/libide/foundry/ide-runner.c
similarity index 98%
rename from src/libide/runner/ide-runner.c
rename to src/libide/foundry/ide-runner.c
index 77b4d8294..239139669 100644
--- a/src/libide/runner/ide-runner.c
+++ b/src/libide/foundry/ide-runner.c
@@ -25,21 +25,18 @@
 #include <dazzle.h>
 #include <errno.h>
 #include <glib/gi18n.h>
+#include <libide-threading.h>
 #include <libpeas/peas.h>
 #include <stdlib.h>
 #include <unistd.h>
 
-#include "ide-context.h"
-#include "ide-debug.h"
-
-#include "config/ide-configuration.h"
-#include "config/ide-configuration-manager.h"
-#include "runner/ide-runner.h"
-#include "runner/ide-runner-addin.h"
-#include "runtimes/ide-runtime.h"
-#include "subprocess/ide-subprocess.h"
-#include "subprocess/ide-subprocess-launcher.h"
-#include "threading/ide-task.h"
+#include "ide-build-target.h"
+#include "ide-configuration-manager.h"
+#include "ide-configuration.h"
+#include "ide-foundry-compat.h"
+#include "ide-runner-addin.h"
+#include "ide-runner.h"
+#include "ide-runtime.h"
 
 typedef struct
 {
@@ -199,7 +196,7 @@ ide_runner_real_create_launcher (IdeRunner *self)
   g_assert (IDE_IS_RUNNER (self));
 
   context = ide_object_get_context (IDE_OBJECT (self));
-  config_manager = ide_context_get_configuration_manager (context);
+  config_manager = ide_configuration_manager_from_context (context);
   config = ide_configuration_manager_get_current (config_manager);
   runtime = ide_configuration_get_runtime (config);
 
@@ -237,7 +234,7 @@ ide_runner_real_run_async (IdeRunner           *self,
   ide_task_set_source_tag (task, ide_runner_real_run_async);
 
   context = ide_object_get_context (IDE_OBJECT (self));
-  config_manager = ide_context_get_configuration_manager (context);
+  config_manager = ide_configuration_manager_from_context (context);
   config = ide_configuration_manager_get_current (config_manager);
   runtime = ide_configuration_get_runtime (config);
 
@@ -1110,7 +1107,6 @@ ide_runner_new (IdeContext *context)
   g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
 
   return g_object_new (IDE_TYPE_RUNNER,
-                       "context", context,
                        NULL);
 }
 
@@ -1301,7 +1297,7 @@ ide_runner_get_runtime (IdeRunner *self)
     return IDE_RUNNER_GET_CLASS (self)->get_runtime (self);
 
   context = ide_object_get_context (IDE_OBJECT (self));
-  config_manager = ide_context_get_configuration_manager (context);
+  config_manager = ide_configuration_manager_from_context (context);
   config = ide_configuration_manager_get_current (config_manager);
   runtime = ide_configuration_get_runtime (config);
 
@@ -1374,7 +1370,7 @@ ide_runner_set_cwd (IdeRunner   *self,
 
   g_return_if_fail (IDE_IS_RUNNER (self));
 
-  if (!dzl_str_equal0 (priv->cwd, cwd))
+  if (!ide_str_equal0 (priv->cwd, cwd))
     {
       g_free (priv->cwd);
       priv->cwd = g_strdup (cwd);
diff --git a/src/libide/runner/ide-runner.h b/src/libide/foundry/ide-runner.h
similarity index 95%
rename from src/libide/runner/ide-runner.h
rename to src/libide/foundry/ide-runner.h
index a3898a8b6..838f8521a 100644
--- a/src/libide/runner/ide-runner.h
+++ b/src/libide/foundry/ide-runner.h
@@ -20,12 +20,14 @@
 
 #pragma once
 
-#include <gio/gio.h>
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "ide-version-macros.h"
+#include <libide-core.h>
+#include <libide-threading.h>
 
-#include "ide-object.h"
-#include "buildsystem/ide-environment.h"
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
@@ -57,13 +59,7 @@ struct _IdeRunnerClass
   IdeRuntime            *(*get_runtime)     (IdeRunner             *self);
 
   /*< private >*/
-  gpointer _reserved1;
-  gpointer _reserved2;
-  gpointer _reserved3;
-  gpointer _reserved4;
-  gpointer _reserved5;
-  gpointer _reserved6;
-  gpointer _reserved7;
+  gpointer _reserved[16];
 };
 
 IDE_AVAILABLE_IN_3_32
diff --git a/src/libide/runtimes/ide-runtime-manager.c b/src/libide/foundry/ide-runtime-manager.c
similarity index 79%
rename from src/libide/runtimes/ide-runtime-manager.c
rename to src/libide/foundry/ide-runtime-manager.c
index 9be3b5923..6fbc115e3 100644
--- a/src/libide/runtimes/ide-runtime-manager.c
+++ b/src/libide/foundry/ide-runtime-manager.c
@@ -23,26 +23,25 @@
 #include "config.h"
 
 #include <glib/gi18n.h>
+#include <libide-plugins.h>
+#include <libide-threading.h>
 #include <libpeas/peas.h>
 
-#include "ide-context.h"
-#include "ide-debug.h"
-
-#include "buildsystem/ide-build-private.h"
-#include "config/ide-configuration.h"
-#include "devices/ide-device.h"
-#include "runtimes/ide-runtime.h"
-#include "runtimes/ide-runtime-manager.h"
-#include "runtimes/ide-runtime-private.h"
-#include "runtimes/ide-runtime-provider.h"
-#include "threading/ide-task.h"
+#include "ide-build-pipeline.h"
+#include "ide-build-private.h"
+#include "ide-configuration.h"
+#include "ide-device.h"
+#include "ide-runtime.h"
+#include "ide-runtime-manager.h"
+#include "ide-runtime-private.h"
+#include "ide-runtime-provider.h"
 
 struct _IdeRuntimeManager
 {
-  IdeObject         parent_instance;
-  PeasExtensionSet *extensions;
-  GPtrArray        *runtimes;
-  guint             unloading : 1;
+  IdeObject               parent_instance;
+  IdeExtensionSetAdapter *extensions;
+  GPtrArray              *runtimes;
+  guint                   unloading : 1;
 };
 
 typedef struct
@@ -73,15 +72,16 @@ prepare_state_free (PrepareState *state)
 }
 
 static void
-ide_runtime_manager_extension_added (PeasExtensionSet *set,
-                                     PeasPluginInfo   *plugin_info,
-                                     PeasExtension    *exten,
-                                     gpointer          user_data)
+ide_runtime_manager_extension_added (IdeExtensionSetAdapter *set,
+                                     PeasPluginInfo         *plugin_info,
+                                     PeasExtension          *exten,
+                                     gpointer                user_data)
 {
   IdeRuntimeManager *self = user_data;
   IdeRuntimeProvider *provider = (IdeRuntimeProvider *)exten;
 
-  g_assert (PEAS_IS_EXTENSION_SET (set));
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
   g_assert (plugin_info != NULL);
   g_assert (IDE_IS_RUNTIME_PROVIDER (provider));
 
@@ -89,15 +89,16 @@ ide_runtime_manager_extension_added (PeasExtensionSet *set,
 }
 
 static void
-ide_runtime_manager_extension_removed (PeasExtensionSet *set,
-                                       PeasPluginInfo   *plugin_info,
-                                       PeasExtension    *exten,
-                                       gpointer          user_data)
+ide_runtime_manager_extension_removed (IdeExtensionSetAdapter *set,
+                                       PeasPluginInfo         *plugin_info,
+                                       PeasExtension          *exten,
+                                       gpointer                user_data)
 {
   IdeRuntimeManager *self = user_data;
   IdeRuntimeProvider *provider = (IdeRuntimeProvider *)exten;
 
-  g_assert (PEAS_IS_EXTENSION_SET (set));
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
   g_assert (plugin_info != NULL);
   g_assert (IDE_IS_RUNTIME_PROVIDER (provider));
 
@@ -110,15 +111,19 @@ ide_runtime_manager_initable_init (GInitable     *initable,
                                    GError       **error)
 {
   IdeRuntimeManager *self = (IdeRuntimeManager *)initable;
+  g_autoptr(IdeRuntime) host = NULL;
   IdeContext *context;
 
   g_assert (IDE_IS_RUNTIME_MANAGER (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
   context = ide_object_get_context (IDE_OBJECT (self));
   g_assert (IDE_IS_CONTEXT (context));
 
-  self->extensions = peas_extension_set_new (peas_engine_get_default (),
-                                             IDE_TYPE_RUNTIME_PROVIDER,
-                                             NULL);
+  self->extensions = ide_extension_set_adapter_new (IDE_OBJECT (self),
+                                                    peas_engine_get_default (),
+                                                    IDE_TYPE_RUNTIME_PROVIDER,
+                                                    NULL, NULL);
 
   g_signal_connect (self->extensions,
                     "extension-added",
@@ -130,11 +135,14 @@ ide_runtime_manager_initable_init (GInitable     *initable,
                     G_CALLBACK (ide_runtime_manager_extension_removed),
                     self);
 
-  peas_extension_set_foreach (self->extensions,
-                              ide_runtime_manager_extension_added,
-                              self);
+  ide_extension_set_adapter_foreach (self->extensions,
+                                     ide_runtime_manager_extension_added,
+                                     self);
+
+  host = ide_runtime_new ("host", _("Use host operating system"));
+  ide_object_append (IDE_OBJECT (self), IDE_OBJECT (host));
 
-  ide_runtime_manager_add (self, ide_runtime_new (context, "host", _("Host operating system")));
+  ide_runtime_manager_add (self, host);
 
   return TRUE;
 }
@@ -145,32 +153,25 @@ initable_iface_init (GInitableIface *iface)
   iface->init = ide_runtime_manager_initable_init;
 }
 
-void
-_ide_runtime_manager_unload (IdeRuntimeManager *self)
-{
-  g_return_if_fail (IDE_IS_RUNTIME_MANAGER (self));
-
-  self->unloading = TRUE;
-  g_clear_object (&self->extensions);
-}
-
 static void
-ide_runtime_manager_dispose (GObject *object)
+ide_runtime_manager_destroy (IdeObject *object)
 {
   IdeRuntimeManager *self = (IdeRuntimeManager *)object;
 
-  _ide_runtime_manager_unload (self);
+  self->unloading = TRUE;
+
+  ide_clear_and_destroy_object (&self->extensions);
   g_clear_pointer (&self->runtimes, g_ptr_array_unref);
 
-  G_OBJECT_CLASS (ide_runtime_manager_parent_class)->dispose (object);
+  IDE_OBJECT_CLASS (ide_runtime_manager_parent_class)->destroy (object);
 }
 
 static void
 ide_runtime_manager_class_init (IdeRuntimeManagerClass *klass)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
 
-  object_class->dispose = ide_runtime_manager_dispose;
+  i_object_class->destroy = ide_runtime_manager_destroy;
 }
 
 static void
@@ -243,7 +244,7 @@ ide_runtime_manager_remove (IdeRuntimeManager *self,
       if (runtime == item)
         {
           g_ptr_array_remove_index (self->runtimes, i);
-          if (!ide_object_is_unloading (IDE_OBJECT (self)))
+          if (!ide_object_in_destruction (IDE_OBJECT (self)))
             g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
           break;
         }
@@ -283,12 +284,13 @@ ide_runtime_manager_get_runtime (IdeRuntimeManager *self,
 }
 
 static void
-install_lookup_cb (PeasExtensionSet   *set,
-                   PeasPluginInfo     *plugin,
-                   IdeRuntimeProvider *provider,
-                   InstallLookup      *lookup)
+install_lookup_cb (IdeExtensionSetAdapter *set,
+                   PeasPluginInfo         *plugin,
+                   IdeRuntimeProvider     *provider,
+                   InstallLookup          *lookup)
 {
-  g_assert (PEAS_IS_EXTENSION_SET (set));
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
   g_assert (plugin != NULL);
   g_assert (IDE_IS_RUNTIME_PROVIDER (provider));
   g_assert (lookup != NULL);
@@ -378,9 +380,9 @@ _ide_runtime_manager_prepare_async (IdeRuntimeManager   *self,
    */
 
   lookup.runtime_id = runtime_id;
-  peas_extension_set_foreach (self->extensions,
-                              (PeasExtensionSetForeachFunc) install_lookup_cb,
-                              &lookup);
+  ide_extension_set_adapter_foreach (self->extensions,
+                                     (IdeExtensionSetAdapterForeachFunc) install_lookup_cb,
+                                     &lookup);
 
   if (lookup.provider == NULL)
     ide_task_return_new_error (task,
diff --git a/src/libide/runtimes/ide-runtime-manager.h b/src/libide/foundry/ide-runtime-manager.h
similarity index 83%
rename from src/libide/runtimes/ide-runtime-manager.h
rename to src/libide/foundry/ide-runtime-manager.h
index 3c0c3520d..e63b011b6 100644
--- a/src/libide/runtimes/ide-runtime-manager.h
+++ b/src/libide/foundry/ide-runtime-manager.h
@@ -20,8 +20,13 @@
 
 #pragma once
 
-#include "ide-object.h"
-#include "ide-version-macros.h"
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
+
+#include <libide-core.h>
+
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
@@ -30,6 +35,8 @@ G_BEGIN_DECLS
 IDE_AVAILABLE_IN_3_32
 G_DECLARE_FINAL_TYPE (IdeRuntimeManager, ide_runtime_manager, IDE, RUNTIME_MANAGER, IdeObject)
 
+IDE_AVAILABLE_IN_3_32
+IdeRuntimeManager       *ide_runtime_manager_from_context       (IdeContext *context);
 IDE_AVAILABLE_IN_3_32
 IdeRuntime *ide_runtime_manager_get_runtime (IdeRuntimeManager    *self,
                                              const gchar          *id);
diff --git a/src/libide/runtimes/ide-runtime-private.h b/src/libide/foundry/ide-runtime-private.h
similarity index 94%
rename from src/libide/runtimes/ide-runtime-private.h
rename to src/libide/foundry/ide-runtime-private.h
index 4ff04401a..3809c5bad 100644
--- a/src/libide/runtimes/ide-runtime-private.h
+++ b/src/libide/foundry/ide-runtime-private.h
@@ -20,8 +20,7 @@
 
 #pragma once
 
-#include "buildsystem/ide-build-pipeline.h"
-#include "runtimes/ide-runtime-manager.h"
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/libide/runtimes/ide-runtime-provider.c b/src/libide/foundry/ide-runtime-provider.c
similarity index 96%
rename from src/libide/runtimes/ide-runtime-provider.c
rename to src/libide/foundry/ide-runtime-provider.c
index 052bd438f..60568ee5b 100644
--- a/src/libide/runtimes/ide-runtime-provider.c
+++ b/src/libide/foundry/ide-runtime-provider.c
@@ -22,17 +22,16 @@
 
 #include "config.h"
 
-#include "ide-context.h"
-#include "ide-debug.h"
+#include <libide-threading.h>
 
-#include "buildsystem/ide-build-pipeline.h"
-#include "config/ide-configuration.h"
-#include "runtimes/ide-runtime.h"
-#include "runtimes/ide-runtime-manager.h"
-#include "runtimes/ide-runtime-provider.h"
-#include "threading/ide-task.h"
+#include "ide-build-pipeline.h"
+#include "ide-configuration.h"
+#include "ide-foundry-compat.h"
+#include "ide-runtime.h"
+#include "ide-runtime-manager.h"
+#include "ide-runtime-provider.h"
 
-G_DEFINE_INTERFACE (IdeRuntimeProvider, ide_runtime_provider, G_TYPE_OBJECT)
+G_DEFINE_INTERFACE (IdeRuntimeProvider, ide_runtime_provider, IDE_TYPE_OBJECT)
 
 static void
 ide_runtime_provider_real_load (IdeRuntimeProvider *self,
@@ -101,7 +100,7 @@ ide_runtime_provider_real_bootstrap_cb (GObject      *object,
 
   runtime_id = ide_task_get_task_data (task);
   context = ide_object_get_context (IDE_OBJECT (self));
-  runtime_manager = ide_context_get_runtime_manager (context);
+  runtime_manager = ide_runtime_manager_from_context (context);
   runtime = ide_runtime_manager_get_runtime (runtime_manager, runtime_id);
 
   if (runtime == NULL)
diff --git a/src/libide/runtimes/ide-runtime-provider.h b/src/libide/foundry/ide-runtime-provider.h
similarity index 95%
rename from src/libide/runtimes/ide-runtime-provider.h
rename to src/libide/foundry/ide-runtime-provider.h
index 0899b89a4..a249d4280 100644
--- a/src/libide/runtimes/ide-runtime-provider.h
+++ b/src/libide/foundry/ide-runtime-provider.h
@@ -20,18 +20,20 @@
 
 #pragma once
 
-#include <gio/gio.h>
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "ide-version-macros.h"
+#include <libide-core.h>
 
-#include "ide-types.h"
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
 #define IDE_TYPE_RUNTIME_PROVIDER (ide_runtime_provider_get_type ())
 
 IDE_AVAILABLE_IN_3_32
-G_DECLARE_INTERFACE (IdeRuntimeProvider, ide_runtime_provider, IDE, RUNTIME_PROVIDER, GObject)
+G_DECLARE_INTERFACE (IdeRuntimeProvider, ide_runtime_provider, IDE, RUNTIME_PROVIDER, IdeObject)
 
 struct _IdeRuntimeProviderInterface
 {
diff --git a/src/libide/runtimes/ide-runtime.c b/src/libide/foundry/ide-runtime.c
similarity index 88%
rename from src/libide/runtimes/ide-runtime.c
rename to src/libide/foundry/ide-runtime.c
index 98d577c15..a46b5961e 100644
--- a/src/libide/runtimes/ide-runtime.c
+++ b/src/libide/foundry/ide-runtime.c
@@ -23,22 +23,21 @@
 #include "config.h"
 
 #include <dazzle.h>
+#include <glib/gi18n.h>
+#include <libide-threading.h>
 #include <string.h>
 
-#include "ide-context.h"
-#include "ide-debug.h"
-
-#include "config/ide-configuration.h"
-#include "projects/ide-project.h"
-#include "runtimes/ide-runtime.h"
-#include "subprocess/ide-subprocess.h"
-#include "subprocess/ide-subprocess-launcher.h"
-#include "util/ide-flatpak.h"
-#include "util/ide-posix.h"
+#include "ide-build-target.h"
+#include "ide-configuration.h"
+#include "ide-runtime.h"
+#include "ide-runner.h"
+#include "ide-toolchain.h"
+#include "ide-triplet.h"
 
 typedef struct
 {
   gchar *id;
+  gchar *category;
   gchar *display_name;
 } IdeRuntimePrivate;
 
@@ -47,6 +46,7 @@ G_DEFINE_TYPE_WITH_PRIVATE (IdeRuntime, ide_runtime, IDE_TYPE_OBJECT)
 enum {
   PROP_0,
   PROP_ID,
+  PROP_CATEGORY,
   PROP_DISPLAY_NAME,
   N_PROPS
 };
@@ -148,13 +148,11 @@ ide_runtime_real_prepare_configuration (IdeRuntime       *self,
   if (NULL == ide_configuration_get_prefix (configuration))
     {
       g_autofree gchar *install_path = NULL;
+      g_autofree gchar *project_id = NULL;
       IdeContext *context;
-      IdeProject *project;
-      const gchar *project_id;
 
       context = ide_object_get_context (IDE_OBJECT (self));
-      project = ide_context_get_project (context);
-      project_id = ide_project_get_id (project);
+      project_id = ide_context_dup_project_id (context);
 
       install_path = g_build_filename (g_get_user_cache_dir (),
                                        "gnome-builder",
@@ -187,7 +185,9 @@ ide_runtime_real_create_runner (IdeRuntime     *self,
   runner = ide_runner_new (context);
   g_assert (IDE_IS_RUNNER (runner));
 
-  if (dzl_str_equal0 (priv->id, "host"))
+  ide_object_append (IDE_OBJECT (self), IDE_OBJECT (runner));
+
+  if (ide_str_equal0 (priv->id, "host"))
     ide_runner_set_run_on_host (runner, TRUE);
 
   if (build_target != NULL)
@@ -269,6 +269,21 @@ ide_runtime_real_translate_file (IdeRuntime *self,
   return NULL;
 }
 
+static gchar *
+ide_runtime_repr (IdeObject *object)
+{
+  IdeRuntime *self = (IdeRuntime *)object;
+  IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_RUNTIME (self));
+
+  return g_strdup_printf ("%s id=\"%s\" display-name=\"%s\"",
+                          G_OBJECT_TYPE_NAME (self),
+                          priv->id ?: "",
+                          priv->display_name ?: "");
+}
+
 static void
 ide_runtime_finalize (GObject *object)
 {
@@ -295,6 +310,10 @@ ide_runtime_get_property (GObject    *object,
       g_value_set_string (value, ide_runtime_get_id (self));
       break;
 
+    case PROP_CATEGORY:
+      g_value_set_string (value, ide_runtime_get_category (self));
+      break;
+
     case PROP_DISPLAY_NAME:
       g_value_set_string (value, ide_runtime_get_display_name (self));
       break;
@@ -318,6 +337,10 @@ ide_runtime_set_property (GObject      *object,
       ide_runtime_set_id (self, g_value_get_string (value));
       break;
 
+    case PROP_CATEGORY:
+      ide_runtime_set_category (self, g_value_get_string (value));
+      break;
+
     case PROP_DISPLAY_NAME:
       ide_runtime_set_display_name (self, g_value_get_string (value));
       break;
@@ -331,11 +354,14 @@ static void
 ide_runtime_class_init (IdeRuntimeClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
 
   object_class->finalize = ide_runtime_finalize;
   object_class->get_property = ide_runtime_get_property;
   object_class->set_property = ide_runtime_set_property;
 
+  i_object_class->repr = ide_runtime_repr;
+
   klass->create_launcher = ide_runtime_real_create_launcher;
   klass->create_runner = ide_runtime_real_create_runner;
   klass->contains_program_in_path = ide_runtime_real_contains_program_in_path;
@@ -349,6 +375,13 @@ ide_runtime_class_init (IdeRuntimeClass *klass)
                          NULL,
                          (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
 
+  properties [PROP_CATEGORY] =
+    g_param_spec_string ("category",
+                         "Category",
+                         "The runtime's category",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
   properties [PROP_DISPLAY_NAME] =
     g_param_spec_string ("display-name",
                          "Display Name",
@@ -383,7 +416,7 @@ ide_runtime_set_id (IdeRuntime  *self,
   g_return_if_fail (IDE_IS_RUNTIME (self));
   g_return_if_fail (id != NULL);
 
-  if (0 != g_strcmp0 (id, priv->id))
+  if (!ide_str_equal0 (id, priv->id))
     {
       g_free (priv->id);
       priv->id = g_strdup (id);
@@ -391,6 +424,36 @@ ide_runtime_set_id (IdeRuntime  *self,
     }
 }
 
+const gchar *
+ide_runtime_get_category (IdeRuntime  *self)
+{
+  IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
+
+  g_return_val_if_fail (IDE_IS_RUNTIME (self), NULL);
+  g_return_val_if_fail (priv->category != NULL, "Host System");
+
+  return priv->category;
+}
+
+void
+ide_runtime_set_category (IdeRuntime  *self,
+                          const gchar *category)
+{
+  IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
+
+  g_return_if_fail (IDE_IS_RUNTIME (self));
+
+  if (category == NULL)
+    category = _("Host System");
+
+  if (!ide_str_equal0 (category, priv->category))
+    {
+      g_free (priv->category);
+      priv->category = g_strdup (category);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CATEGORY]);
+    }
+}
+
 const gchar *
 ide_runtime_get_display_name (IdeRuntime *self)
 {
@@ -419,16 +482,13 @@ ide_runtime_set_display_name (IdeRuntime  *self,
 }
 
 IdeRuntime *
-ide_runtime_new (IdeContext  *context,
-                 const gchar *id,
+ide_runtime_new (const gchar *id,
                  const gchar *display_name)
 {
-  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
   g_return_val_if_fail (id != NULL, NULL);
   g_return_val_if_fail (display_name != NULL, NULL);
 
   return g_object_new (IDE_TYPE_RUNTIME,
-                       "context", context,
                        "id", id,
                        "display-name", display_name,
                        NULL);
diff --git a/src/libide/runtimes/ide-runtime.h b/src/libide/foundry/ide-runtime.h
similarity index 87%
rename from src/libide/runtimes/ide-runtime.h
rename to src/libide/foundry/ide-runtime.h
index 9560b8236..289753f23 100644
--- a/src/libide/runtimes/ide-runtime.h
+++ b/src/libide/foundry/ide-runtime.h
@@ -20,23 +20,23 @@
 
 #pragma once
 
-#include <gio/gio.h>
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "ide-version-macros.h"
+#include <libide-core.h>
 
-#include "ide-object.h"
-
-#include "buildsystem/ide-build-target.h"
-#include "runner/ide-runner.h"
-#include "subprocess/ide-subprocess-launcher.h"
-#include "toolchain/ide-toolchain.h"
-#include "util/ide-triplet.h"
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
 typedef enum
 {
-  IDE_RUNTIME_ERROR_NO_SUCH_RUNTIME = 1,
+  IDE_RUNTIME_ERROR_UNKNOWN = 0,
+  IDE_RUNTIME_ERROR_NO_SUCH_RUNTIME,
+  IDE_RUNTIME_ERROR_BUILD_FAILED,
+  IDE_RUNTIME_ERROR_TARGET_NOT_FOUND,
+  IDE_RUNTIME_ERROR_SPAWN_FAILED,
 } IdeRuntimeError;
 
 #define IDE_TYPE_RUNTIME (ide_runtime_get_type())
@@ -65,6 +65,7 @@ struct _IdeRuntimeClass
   gboolean                (*supports_toolchain)       (IdeRuntime           *self,
                                                        IdeToolchain         *toolchain);
 
+  /*< private >*/
   gpointer _reserved[12];
 };
 
@@ -84,8 +85,7 @@ IDE_AVAILABLE_IN_3_32
 void                   ide_runtime_prepare_configuration    (IdeRuntime           *self,
                                                              IdeConfiguration     *configuration);
 IDE_AVAILABLE_IN_3_32
-IdeRuntime            *ide_runtime_new                      (IdeContext           *context,
-                                                             const gchar          *id,
+IdeRuntime            *ide_runtime_new                      (const gchar          *id,
                                                              const gchar          *title);
 IDE_AVAILABLE_IN_3_32
 const gchar           *ide_runtime_get_id                   (IdeRuntime           *self);
@@ -93,6 +93,11 @@ IDE_AVAILABLE_IN_3_32
 void                   ide_runtime_set_id                   (IdeRuntime           *self,
                                                              const gchar          *id);
 IDE_AVAILABLE_IN_3_32
+const gchar           *ide_runtime_get_category             (IdeRuntime           *self);
+IDE_AVAILABLE_IN_3_32
+void                   ide_runtime_set_category             (IdeRuntime           *self,
+                                                             const gchar          *category);
+IDE_AVAILABLE_IN_3_32
 const gchar           *ide_runtime_get_display_name         (IdeRuntime           *self);
 IDE_AVAILABLE_IN_3_32
 void                   ide_runtime_set_display_name         (IdeRuntime           *self,
diff --git a/src/libide/toolchain/ide-simple-toolchain.c b/src/libide/foundry/ide-simple-toolchain.c
similarity index 95%
rename from src/libide/toolchain/ide-simple-toolchain.c
rename to src/libide/foundry/ide-simple-toolchain.c
index 6e7fec89b..b68389840 100644
--- a/src/libide/toolchain/ide-simple-toolchain.c
+++ b/src/libide/foundry/ide-simple-toolchain.c
@@ -24,9 +24,7 @@
 
 #include "config.h"
 
-#include "ide-context.h"
-
-#include "toolchain/ide-simple-toolchain.h"
+#include "ide-simple-toolchain.h"
 
 typedef struct
 {
@@ -36,15 +34,12 @@ typedef struct
 G_DEFINE_TYPE_WITH_PRIVATE (IdeSimpleToolchain, ide_simple_toolchain, IDE_TYPE_TOOLCHAIN)
 
 IdeSimpleToolchain *
-ide_simple_toolchain_new (IdeContext   *context,
-                          const gchar  *id,
+ide_simple_toolchain_new (const gchar  *id,
                           const gchar  *display_name)
 {
-  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
   g_return_val_if_fail (id != NULL, NULL);
 
   return g_object_new (IDE_TYPE_SIMPLE_TOOLCHAIN,
-                       "context", context,
                        "id", id,
                        "display-name", display_name,
                        NULL);
diff --git a/src/libide/toolchain/ide-simple-toolchain.h b/src/libide/foundry/ide-simple-toolchain.h
similarity index 88%
rename from src/libide/toolchain/ide-simple-toolchain.h
rename to src/libide/foundry/ide-simple-toolchain.h
index 68d91c250..8d0eac82f 100644
--- a/src/libide/toolchain/ide-simple-toolchain.h
+++ b/src/libide/foundry/ide-simple-toolchain.h
@@ -22,9 +22,13 @@
 
 #pragma once
 
-#include "ide-version-macros.h"
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "toolchain/ide-toolchain.h"
+#include <libide-core.h>
+
+#include "ide-toolchain.h"
 
 G_BEGIN_DECLS
 
@@ -42,8 +46,7 @@ struct _IdeSimpleToolchainClass
 };
 
 IDE_AVAILABLE_IN_3_32
-IdeSimpleToolchain  *ide_simple_toolchain_new                    (IdeContext          *context,
-                                                                  const gchar         *id,
+IdeSimpleToolchain  *ide_simple_toolchain_new                    (const gchar         *id,
                                                                   const gchar         *display_name);
 IDE_AVAILABLE_IN_3_32
 void                 ide_simple_toolchain_set_tool_for_language  (IdeSimpleToolchain  *self,
diff --git a/src/libide/testing/ide-test-manager.c b/src/libide/foundry/ide-test-manager.c
similarity index 81%
rename from src/libide/testing/ide-test-manager.c
rename to src/libide/foundry/ide-test-manager.c
index c5273c270..acd79b155 100644
--- a/src/libide/testing/ide-test-manager.c
+++ b/src/libide/foundry/ide-test-manager.c
@@ -23,16 +23,15 @@
 #include "config.h"
 
 #include <dazzle.h>
+#include <libide-threading.h>
 #include <libpeas/peas.h>
 
-#include "ide-context.h"
-#include "ide-debug.h"
-
-#include "buildsystem/ide-build-manager.h"
-#include "buildsystem/ide-build-pipeline.h"
-#include "testing/ide-test-manager.h"
-#include "testing/ide-test-private.h"
-#include "testing/ide-test-provider.h"
+#include "ide-build-manager.h"
+#include "ide-build-pipeline.h"
+#include "ide-foundry-compat.h"
+#include "ide-test-manager.h"
+#include "ide-test-private.h"
+#include "ide-test-provider.h"
 
 #define MAX_UNIT_TESTS 4
 
@@ -193,7 +192,7 @@ ide_test_manager_locate_group (IdeTestManager *self,
                               IDE_TEST_COLUMN_GROUP, &row_group,
                               -1);
 
-          if (dzl_str_equal0 (row_group, group))
+          if (ide_str_equal0 (row_group, group))
             return;
         }
       while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->tests_store), iter));
@@ -419,6 +418,8 @@ ide_test_manager_provider_added (PeasExtensionSet *set,
   len = g_list_model_get_n_items (G_LIST_MODEL (provider));
   ide_test_manager_provider_items_changed (self, 0, 0, len, provider);
 
+  ide_object_append (IDE_OBJECT (self), IDE_OBJECT (provider));
+
   IDE_EXIT;
 }
 
@@ -456,6 +457,8 @@ ide_test_manager_provider_removed (PeasExtensionSet *set,
                                         G_CALLBACK (ide_test_manager_provider_notify_loading),
                                         self);
 
+  ide_object_destroy (IDE_OBJECT (provider));
+
   IDE_EXIT;
 }
 
@@ -465,18 +468,14 @@ ide_test_manager_initiable_init (GInitable     *initable,
                                  GError       **error)
 {
   IdeTestManager *self = (IdeTestManager *)initable;
-  IdeContext *context;
 
   IDE_ENTRY;
 
   g_assert (IDE_IS_TEST_MANAGER (self));
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  context = ide_object_get_context (IDE_OBJECT (self));
-
   self->providers = peas_extension_set_new (peas_engine_get_default (),
                                             IDE_TYPE_TEST_PROVIDER,
-                                            "context", context,
                                             NULL);
 
   g_signal_connect (self->providers,
@@ -718,7 +717,7 @@ ide_test_manager_run_async (IdeTestManager      *self,
   g_task_set_source_tag (task, ide_test_manager_run_async);
 
   context = ide_object_get_context (IDE_OBJECT (self));
-  build_manager = ide_context_get_build_manager (context);
+  build_manager = ide_build_manager_from_context (context);
   pipeline = ide_build_manager_get_pipeline (build_manager);
 
   if (pipeline == NULL)
@@ -839,3 +838,184 @@ ide_test_manager_get_loading (IdeTestManager *self)
 
   return loading;
 }
+
+/**
+ * ide_test_manager_get_tests:
+ * @self: a #IdeTestManager
+ * @path: (nullable): the path to the test or %NULL for the root path
+ *
+ * Locates and returns any #IdeTest that is found as a direct child
+ * of @path.
+ *
+ * Returns: (transfer full) (element-type IdeTest): an array of #IdeTest
+ *
+ * Since: 3.32
+ */
+GPtrArray *
+ide_test_manager_get_tests (IdeTestManager *self,
+                            const gchar    *path)
+{
+  GPtrArray *ret;
+  GtkTreeIter iter;
+
+  g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
+  g_return_val_if_fail (IDE_IS_TEST_MANAGER (self), NULL);
+
+  ret = g_ptr_array_new ();
+
+  if (path == NULL)
+    {
+      if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->tests_store), &iter))
+        goto failure;
+    }
+  else
+    {
+      GtkTreeIter parent;
+
+      ide_test_manager_locate_group (self, &parent, path);
+
+      if (!gtk_tree_model_iter_children (GTK_TREE_MODEL (self->tests_store), &iter, &parent))
+        goto failure;
+    }
+
+  do
+    {
+      IdeTest *test = NULL;
+
+      gtk_tree_model_get (GTK_TREE_MODEL (self->tests_store), &iter,
+                          IDE_TEST_COLUMN_TEST, &test,
+                          -1);
+      if (test != NULL)
+        g_ptr_array_add (ret, g_steal_pointer (&test));
+    }
+  while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->tests_store), &iter));
+
+failure:
+  return g_steal_pointer (&ret);
+}
+
+/**
+ * ide_test_manager_get_folders:
+ * @self: a #IdeTestManager
+ * @path: (nullable): the path to the test or %NULL for the root path
+ *
+ * Gets the sub-paths of @path that are not individual tests.
+ *
+ * Returns: (transfer full) (array zero-terminated=1): an array of strings
+ *   describing available sub-paths to @path.
+ *
+ * Since: 3.32
+ */
+gchar **
+ide_test_manager_get_folders (IdeTestManager *self,
+                              const gchar    *path)
+{
+  static const gchar *empty[] = { NULL };
+  GPtrArray *ret;
+  GtkTreeIter iter;
+
+  g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
+  g_return_val_if_fail (IDE_IS_TEST_MANAGER (self), NULL);
+
+  ret = g_ptr_array_new ();
+
+  if (path == NULL)
+    {
+      if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->tests_store), &iter))
+        return g_strdupv ((gchar **)empty);
+    }
+  else
+    {
+      GtkTreeIter parent;
+
+      ide_test_manager_locate_group (self, &parent, path);
+
+      if (!gtk_tree_model_iter_children (GTK_TREE_MODEL (self->tests_store), &iter, &parent))
+        return g_strdupv ((gchar **)empty);
+    }
+
+  do
+    {
+      gchar *group = NULL;
+
+      gtk_tree_model_get (GTK_TREE_MODEL (self->tests_store), &iter,
+                          IDE_TEST_COLUMN_GROUP, &group,
+                          -1);
+      if (group != NULL)
+        g_ptr_array_add (ret, g_steal_pointer (&group));
+    }
+  while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->tests_store), &iter));
+
+  g_ptr_array_add (ret, NULL);
+
+  return (gchar **)g_ptr_array_free (ret, FALSE);
+}
+
+static void
+ide_test_manager_ensure_loaded_cb (IdeTestManager *self,
+                                   GParamSpec     *pspec,
+                                   IdeTask        *task)
+{
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_TEST_MANAGER (self));
+  g_assert (IDE_IS_TASK (task));
+
+  if (!ide_test_manager_get_loading (self))
+    {
+      g_signal_handlers_disconnect_by_func (self,
+                                            G_CALLBACK (ide_test_manager_ensure_loaded_cb),
+                                            task);
+      ide_task_return_boolean (task, TRUE);
+    }
+}
+
+/**
+ * ide_test_manager_ensure_loaded_async:
+ * @self: a #IdeTestManager
+ *
+ * Calls @callback after the test manager has loaded tests.
+ *
+ * If the test manager has already loaded tests, then @callback will
+ * be called after returning to the main loop.
+ *
+ * Since: 3.32
+ */
+void
+ide_test_manager_ensure_loaded_async (IdeTestManager      *self,
+                                      GCancellable        *cancellable,
+                                      GAsyncReadyCallback  callback,
+                                      gpointer             user_data)
+{
+  g_autoptr(IdeTask) task = NULL;
+
+  g_return_if_fail (IDE_IS_TEST_MANAGER (self));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = ide_task_new (self, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, ide_test_manager_ensure_loaded_async);
+
+  if (ide_test_manager_get_loading (self))
+    {
+      g_signal_connect_data (self,
+                             "notify::loading",
+                             G_CALLBACK (ide_test_manager_ensure_loaded_cb),
+                             g_steal_pointer (&task),
+                             (GClosureNotify)g_object_unref,
+                             0);
+      return;
+    }
+
+  ide_task_return_boolean (task, TRUE);
+}
+
+gboolean
+ide_test_manager_ensure_loaded_finish (IdeTestManager  *self,
+                                       GAsyncResult    *result,
+                                       GError         **error)
+{
+  g_return_val_if_fail (IDE_IS_MAIN_THREAD (), FALSE);
+  g_return_val_if_fail (IDE_IS_TEST_MANAGER (self), FALSE);
+  g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
+
+  return ide_task_propagate_boolean (IDE_TASK (result), error);
+}
diff --git a/src/libide/foundry/ide-test-manager.h b/src/libide/foundry/ide-test-manager.h
new file mode 100644
index 000000000..5336cc758
--- /dev/null
+++ b/src/libide/foundry/ide-test-manager.h
@@ -0,0 +1,77 @@
+/* ide-test-manager.h
+ *
+ * Copyright 2017-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
+
+#include <libide-core.h>
+
+#include "ide-foundry-types.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_TEST_MANAGER (ide_test_manager_get_type())
+
+IDE_AVAILABLE_IN_3_32
+G_DECLARE_FINAL_TYPE (IdeTestManager, ide_test_manager, IDE, TEST_MANAGER, IdeObject)
+
+IDE_AVAILABLE_IN_3_32
+IdeTestManager          *ide_test_manager_from_context          (IdeContext *context);
+IDE_AVAILABLE_IN_3_32
+gboolean    ide_test_manager_get_loading          (IdeTestManager       *self);
+IDE_AVAILABLE_IN_3_32
+void        ide_test_manager_run_async            (IdeTestManager       *self,
+                                                   IdeTest              *test,
+                                                   GCancellable         *cancellable,
+                                                   GAsyncReadyCallback   callback,
+                                                   gpointer              user_data);
+IDE_AVAILABLE_IN_3_32
+gboolean    ide_test_manager_run_finish           (IdeTestManager       *self,
+                                                   GAsyncResult         *result,
+                                                   GError              **error);
+IDE_AVAILABLE_IN_3_32
+void        ide_test_manager_run_all_async        (IdeTestManager       *self,
+                                                   GCancellable         *cancellable,
+                                                   GAsyncReadyCallback   callback,
+                                                   gpointer              user_data);
+IDE_AVAILABLE_IN_3_32
+gboolean    ide_test_manager_run_all_finish       (IdeTestManager       *self,
+                                                   GAsyncResult         *result,
+                                                   GError              **error);
+IDE_AVAILABLE_IN_3_32
+GPtrArray  *ide_test_manager_get_tests            (IdeTestManager       *self,
+                                                   const gchar          *path);
+IDE_AVAILABLE_IN_3_32
+gchar     **ide_test_manager_get_folders          (IdeTestManager       *self,
+                                                   const gchar          *path);
+IDE_AVAILABLE_IN_3_32
+void        ide_test_manager_ensure_loaded_async  (IdeTestManager       *self,
+                                                   GCancellable         *cancellable,
+                                                   GAsyncReadyCallback   callback,
+                                                   gpointer              user_data);
+IDE_AVAILABLE_IN_3_32
+gboolean    ide_test_manager_ensure_loaded_finish (IdeTestManager       *self,
+                                                   GAsyncResult         *result,
+                                                   GError              **error);
+
+G_END_DECLS
diff --git a/src/libide/testing/ide-test-private.h b/src/libide/foundry/ide-test-private.h
similarity index 74%
rename from src/libide/testing/ide-test-private.h
rename to src/libide/foundry/ide-test-private.h
index 9bc290405..744cc2742 100644
--- a/src/libide/testing/ide-test-private.h
+++ b/src/libide/foundry/ide-test-private.h
@@ -34,10 +34,10 @@ typedef enum
   IDE_TEST_COLUMN_TEST,
 } IdeTestColumn;
 
-G_GNUC_INTERNAL GtkTreeModel    *_ide_test_manager_get_model (IdeTestManager  *self);
-G_GNUC_INTERNAL void             _ide_test_set_provider      (IdeTest         *self,
-                                                              IdeTestProvider *provider);
-G_GNUC_INTERNAL IdeTestProvider *_ide_test_get_provider      (IdeTest         *self);
+GtkTreeModel    *_ide_test_manager_get_model (IdeTestManager  *self);
+void             _ide_test_set_provider      (IdeTest         *self,
+                                                               IdeTestProvider *provider);
+IdeTestProvider *_ide_test_get_provider      (IdeTest         *self);
 
 
 G_END_DECLS
diff --git a/src/libide/testing/ide-test-provider.c b/src/libide/foundry/ide-test-provider.c
similarity index 99%
rename from src/libide/testing/ide-test-provider.c
rename to src/libide/foundry/ide-test-provider.c
index 7adf25469..0fe462c00 100644
--- a/src/libide/testing/ide-test-provider.c
+++ b/src/libide/foundry/ide-test-provider.c
@@ -22,8 +22,9 @@
 
 #include "config.h"
 
-#include "testing/ide-test-provider.h"
-#include "testing/ide-test-private.h"
+#include "ide-build-pipeline.h"
+#include "ide-test-provider.h"
+#include "ide-test-private.h"
 
 typedef struct
 {
diff --git a/src/libide/testing/ide-test-provider.h b/src/libide/foundry/ide-test-provider.h
similarity index 90%
rename from src/libide/testing/ide-test-provider.h
rename to src/libide/foundry/ide-test-provider.h
index 03318df05..cec3eba1f 100644
--- a/src/libide/testing/ide-test-provider.h
+++ b/src/libide/foundry/ide-test-provider.h
@@ -20,12 +20,13 @@
 
 #pragma once
 
-#include "ide-version-macros.h"
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "ide-object.h"
+#include <libide-core.h>
 
-#include "buildsystem/ide-build-pipeline.h"
-#include "testing/ide-test.h"
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
@@ -50,14 +51,7 @@ struct _IdeTestProviderClass
   void     (*reload)     (IdeTestProvider      *self);
 
   /*< private >*/
-  gpointer _reserved1;
-  gpointer _reserved2;
-  gpointer _reserved3;
-  gpointer _reserved4;
-  gpointer _reserved5;
-  gpointer _reserved6;
-  gpointer _reserved7;
-  gpointer _reserved8;
+  gpointer _reserved[16];
 };
 
 IDE_AVAILABLE_IN_3_32
diff --git a/src/libide/testing/ide-test.c b/src/libide/foundry/ide-test.c
similarity index 98%
rename from src/libide/testing/ide-test.c
rename to src/libide/foundry/ide-test.c
index ec489c95d..f2980bbe4 100644
--- a/src/libide/testing/ide-test.c
+++ b/src/libide/foundry/ide-test.c
@@ -22,11 +22,11 @@
 
 #include "config.h"
 
-#include "ide-enums.h"
+#include "ide-foundry-enums.h"
 
-#include "testing/ide-test.h"
-#include "testing/ide-test-private.h"
-#include "testing/ide-test-provider.h"
+#include "ide-test.h"
+#include "ide-test-private.h"
+#include "ide-test-provider.h"
 
 typedef struct
 {
diff --git a/src/libide/testing/ide-test.h b/src/libide/foundry/ide-test.h
similarity index 92%
rename from src/libide/testing/ide-test.h
rename to src/libide/foundry/ide-test.h
index e20337cea..6cdffe3af 100644
--- a/src/libide/testing/ide-test.h
+++ b/src/libide/foundry/ide-test.h
@@ -20,9 +20,11 @@
 
 #pragma once
 
-#include <glib-object.h>
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "ide-version-macros.h"
+#include <libide-core.h>
 
 G_BEGIN_DECLS
 
@@ -44,7 +46,7 @@ struct _IdeTestClass
   GObjectClass parent;
 
   /*< private >*/
-  gpointer _reserved[8];
+  gpointer _reserved[16];
 };
 
 IDE_AVAILABLE_IN_3_32
diff --git a/src/libide/toolchain/ide-toolchain-manager.c b/src/libide/foundry/ide-toolchain-manager.c
similarity index 95%
rename from src/libide/toolchain/ide-toolchain-manager.c
rename to src/libide/foundry/ide-toolchain-manager.c
index a947121a1..37b66e3b1 100644
--- a/src/libide/toolchain/ide-toolchain-manager.c
+++ b/src/libide/foundry/ide-toolchain-manager.c
@@ -25,21 +25,18 @@
 #include "config.h"
 
 #include <glib/gi18n.h>
+#include <libide-threading.h>
 #include <libpeas/peas.h>
 
-#include "ide-context.h"
-#include "ide-debug.h"
-
-#include "application/ide-application.h"
-#include "buildsystem/ide-build-private.h"
-#include "config/ide-configuration.h"
-#include "devices/ide-device.h"
-#include "threading/ide-task.h"
-#include "toolchain/ide-simple-toolchain.h"
-#include "toolchain/ide-toolchain.h"
-#include "toolchain/ide-toolchain-manager.h"
-#include "toolchain/ide-toolchain-private.h"
-#include "toolchain/ide-toolchain-provider.h"
+#include "ide-build-private.h"
+#include "ide-build-pipeline.h"
+#include "ide-configuration.h"
+#include "ide-device.h"
+#include "ide-simple-toolchain.h"
+#include "ide-toolchain.h"
+#include "ide-toolchain-manager.h"
+#include "ide-toolchain-private.h"
+#include "ide-toolchain-provider.h"
 
 struct _IdeToolchainManager
 {
@@ -197,6 +194,8 @@ ide_toolchain_manager_extension_added (PeasExtensionSet *set,
 
   provider_connect (self, provider);
 
+  ide_object_append (IDE_OBJECT (self), IDE_OBJECT (provider));
+
   ide_toolchain_provider_load_async (provider,
                                      self->cancellable,
                                      ide_toolchain_manager_toolchain_load_cb,
@@ -219,6 +218,8 @@ ide_toolchain_manager_extension_removed (PeasExtensionSet *set,
   provider_disconnect (self, provider);
 
   ide_toolchain_provider_unload (provider, self);
+
+  ide_object_destroy (IDE_OBJECT (self));
 }
 
 static void
@@ -231,7 +232,6 @@ ide_toolchain_manager_init_load_cb (GObject      *object,
   g_autoptr(GError) error = NULL;
   g_autoptr(IdeTask) task = user_data;
   GPtrArray *providers;
-  IdeContext *context;
 
   IDE_ENTRY;
 
@@ -243,16 +243,12 @@ ide_toolchain_manager_init_load_cb (GObject      *object,
   self = ide_task_get_source_object (task);
   g_assert (IDE_IS_TOOLCHAIN_MANAGER (self));
 
-  context = ide_object_get_context (IDE_OBJECT (self));
-  g_assert (IDE_IS_CONTEXT (context));
-
   if (!ide_toolchain_provider_load_finish (provider, result, &error))
     {
       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
           !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
-        ide_context_warning (context,
-                             "Failed to initialize toolchain provider: %s: %s",
-                             G_OBJECT_TYPE_NAME (provider), error->message);
+        g_warning ("Failed to initialize toolchain provider: %s: %s",
+                   G_OBJECT_TYPE_NAME (provider), error->message);
     }
 
   providers = ide_task_get_task_data (task);
@@ -318,7 +314,6 @@ ide_toolchain_manager_init_async (GAsyncInitable      *initable,
 
   self->extensions = peas_extension_set_new (peas_engine_get_default (),
                                              IDE_TYPE_TOOLCHAIN_PROVIDER,
-                                             "context", context,
                                              NULL);
 
   g_signal_connect (self->extensions,
@@ -339,7 +334,9 @@ ide_toolchain_manager_init_async (GAsyncInitable      *initable,
                           g_ptr_array_ref (providers),
                           g_ptr_array_unref);
 
-  default_toolchain = ide_simple_toolchain_new (context, "default", _("Default (Host operating system)"));
+  default_toolchain = ide_simple_toolchain_new ("default", _("Default (Host operating system)"));
+  ide_object_append (IDE_OBJECT (self), IDE_OBJECT (default_toolchain));
+
   idx = self->toolchains->len;
   g_ptr_array_add (self->toolchains, g_steal_pointer (&default_toolchain));
   g_list_model_items_changed (G_LIST_MODEL (self), idx, 0, 1);
@@ -352,6 +349,8 @@ ide_toolchain_manager_init_async (GAsyncInitable      *initable,
 
       provider_connect (self, provider);
 
+      ide_object_append (IDE_OBJECT (self), IDE_OBJECT (provider));
+
       ide_toolchain_provider_load_async (provider,
                                          cancellable,
                                          ide_toolchain_manager_init_load_cb,
diff --git a/src/libide/toolchain/ide-toolchain-manager.h b/src/libide/foundry/ide-toolchain-manager.h
similarity index 87%
rename from src/libide/toolchain/ide-toolchain-manager.h
rename to src/libide/foundry/ide-toolchain-manager.h
index 59e92fb7a..ad2b1c210 100644
--- a/src/libide/toolchain/ide-toolchain-manager.h
+++ b/src/libide/foundry/ide-toolchain-manager.h
@@ -22,10 +22,13 @@
 
 #pragma once
 
-#include "ide-object.h"
-#include "ide-version-macros.h"
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "toolchain/ide-toolchain.h"
+#include <libide-core.h>
+
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/libide/toolchain/ide-toolchain-private.h b/src/libide/foundry/ide-toolchain-private.h
similarity index 94%
rename from src/libide/toolchain/ide-toolchain-private.h
rename to src/libide/foundry/ide-toolchain-private.h
index d9e52d360..be819f89e 100644
--- a/src/libide/toolchain/ide-toolchain-private.h
+++ b/src/libide/foundry/ide-toolchain-private.h
@@ -22,8 +22,7 @@
 
 #pragma once
 
-#include "buildsystem/ide-build-pipeline.h"
-#include "toolchain/ide-toolchain-manager.h"
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/libide/toolchain/ide-toolchain-provider.c b/src/libide/foundry/ide-toolchain-provider.c
similarity index 98%
rename from src/libide/toolchain/ide-toolchain-provider.c
rename to src/libide/foundry/ide-toolchain-provider.c
index 02db09c9d..b7b5d2b54 100644
--- a/src/libide/toolchain/ide-toolchain-provider.c
+++ b/src/libide/foundry/ide-toolchain-provider.c
@@ -24,10 +24,9 @@
 
 #include "config.h"
 
-#include "ide-debug.h"
-
-#include "application/ide-application.h"
-#include "toolchain/ide-toolchain-provider.h"
+#include "ide-toolchain.h"
+#include "ide-toolchain-manager.h"
+#include "ide-toolchain-provider.h"
 
 G_DEFINE_INTERFACE (IdeToolchainProvider, ide_toolchain_provider, IDE_TYPE_OBJECT)
 
diff --git a/src/libide/toolchain/ide-toolchain-provider.h b/src/libide/foundry/ide-toolchain-provider.h
similarity index 94%
rename from src/libide/toolchain/ide-toolchain-provider.h
rename to src/libide/foundry/ide-toolchain-provider.h
index 1ef73bebc..222a5e9b0 100644
--- a/src/libide/toolchain/ide-toolchain-provider.h
+++ b/src/libide/foundry/ide-toolchain-provider.h
@@ -22,10 +22,13 @@
 
 #pragma once
 
-#include "ide-object.h"
-#include "ide-version-macros.h"
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
 
-#include "toolchain/ide-toolchain-manager.h"
+#include <libide-core.h>
+
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/libide/toolchain/ide-toolchain.c b/src/libide/foundry/ide-toolchain.c
similarity index 98%
rename from src/libide/toolchain/ide-toolchain.c
rename to src/libide/foundry/ide-toolchain.c
index c2177cd01..d8d8b2f23 100644
--- a/src/libide/toolchain/ide-toolchain.c
+++ b/src/libide/foundry/ide-toolchain.c
@@ -24,12 +24,8 @@
 
 #include "config.h"
 
-#include "ide-debug.h"
-#include "ide-context.h"
-
-#include "toolchain/ide-toolchain.h"
-#include "util/ide-posix.h"
-
+#include "ide-toolchain.h"
+#include "ide-triplet.h"
 
 typedef struct
 {
diff --git a/src/libide/toolchain/ide-toolchain.h b/src/libide/foundry/ide-toolchain.h
similarity index 93%
rename from src/libide/toolchain/ide-toolchain.h
rename to src/libide/foundry/ide-toolchain.h
index 44c6866a2..2d4cca3fe 100644
--- a/src/libide/toolchain/ide-toolchain.h
+++ b/src/libide/foundry/ide-toolchain.h
@@ -22,9 +22,13 @@
 
 #pragma once
 
-#include "ide-object.h"
-#include "ide-version-macros.h"
-#include "util/ide-triplet.h"
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
+
+#include <libide-core.h>
+
+#include "ide-foundry-types.h"
 
 G_BEGIN_DECLS
 
@@ -45,7 +49,7 @@ struct _IdeToolchainClass
                                          const gchar   *tool_id);
 
   /*< private >*/
-  gpointer _reserved[12];
+  gpointer _reserved[16];
 };
 
 #define IDE_TOOLCHAIN_TOOL_CC          "cc"
diff --git a/src/libide/foundry/ide-triplet.c b/src/libide/foundry/ide-triplet.c
new file mode 100644
index 000000000..389fb001e
--- /dev/null
+++ b/src/libide/foundry/ide-triplet.c
@@ -0,0 +1,389 @@
+/* ide-triplet.c
+ *
+ * Copyright 2018 Corentin Noël <corentin noel collabora com>
+ * Copyright 2018 Collabora Ltd.
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-triplet"
+
+#include "config.h"
+
+#include "ide-triplet.h"
+
+G_DEFINE_BOXED_TYPE (IdeTriplet, ide_triplet, ide_triplet_ref, ide_triplet_unref)
+
+struct _IdeTriplet
+{
+  volatile gint ref_count;
+
+  gchar *full_name;
+  gchar *arch;
+  gchar *vendor;
+  gchar *kernel;
+  gchar *operating_system;
+};
+
+static IdeTriplet *
+_ide_triplet_construct (void)
+{
+  IdeTriplet *self;
+
+  self = g_slice_new0 (IdeTriplet);
+  self->ref_count = 1;
+  self->full_name = NULL;
+  self->arch = NULL;
+  self->vendor = NULL;
+  self->kernel = NULL;
+  self->operating_system = NULL;
+
+  return self;
+}
+
+/**
+ * ide_triplet_new:
+ * @full_name: The complete identifier of the machine
+ *
+ * Creates a new #IdeTriplet from a given identifier. This identifier
+ * can be a simple architecture name, a duet of "arch-kernel" (like "m68k-coff"), a triplet
+ * of "arch-kernel-os" (like "x86_64-linux-gnu") or a quadriplet of "arch-vendor-kernel-os"
+ * (like "i686-pc-linux-gnu")
+ *
+ * Returns: (transfer full): An #IdeTriplet.
+ *
+ * Since: 3.32
+ */
+IdeTriplet *
+ide_triplet_new (const gchar *full_name)
+{
+  IdeTriplet *self;
+  g_auto (GStrv) parts = NULL;
+  guint parts_length = 0;
+
+  g_return_val_if_fail (full_name != NULL, NULL);
+
+  self = _ide_triplet_construct ();
+  self->full_name = g_strdup (full_name);
+
+  parts = g_strsplit (full_name, "-", 4);
+  parts_length = g_strv_length (parts);
+  /* Currently they can't have more than 4 parts */
+  if (parts_length >= 4)
+    {
+      self->arch = g_strdup (parts[0]);
+      self->vendor = g_strdup (parts[1]);
+      self->kernel = g_strdup (parts[2]);
+      self->operating_system = g_strdup (parts[3]);
+    }
+  else if (parts_length == 3)
+    {
+      self->arch = g_strdup (parts[0]);
+      self->kernel = g_strdup (parts[1]);
+      self->operating_system = g_strdup (parts[2]);
+    }
+  else if (parts_length == 2)
+    {
+      self->arch = g_strdup (parts[0]);
+      self->kernel = g_strdup (parts[1]);
+    }
+  else if (parts_length == 1)
+    self->arch = g_strdup (parts[0]);
+
+  return self;
+}
+
+/**
+ * ide_triplet_new_from_system:
+ *
+ * Creates a new #IdeTriplet from a the current system information
+ *
+ * Returns: (transfer full): An #IdeTriplet.
+ *
+ * Since: 3.32
+ */
+IdeTriplet *
+ide_triplet_new_from_system (void)
+{
+  static IdeTriplet *system_triplet;
+
+  if (g_once_init_enter (&system_triplet))
+    g_once_init_leave (&system_triplet, ide_triplet_new (ide_get_system_type ()));
+
+  return ide_triplet_ref (system_triplet);
+}
+
+/**
+ * ide_triplet_new_with_triplet:
+ * @arch: The name of the architecture of the machine (like "x86_64")
+ * @kernel: (nullable): The name of the kernel of the machine (like "linux")
+ * @operating_system: (nullable): The name of the os of the machine
+ * (like "gnuabi64")
+ *
+ * Creates a new #IdeTriplet from a given triplet of "arch-kernel-os"
+ * (like "x86_64-linux-gnu")
+ *
+ * Returns: (transfer full): An #IdeTriplet.
+ *
+ * Since: 3.32
+ */
+IdeTriplet *
+ide_triplet_new_with_triplet (const gchar *arch,
+                              const gchar *kernel,
+                              const gchar *operating_system)
+{
+  IdeTriplet *self;
+  g_autofree gchar *full_name = NULL;
+
+  g_return_val_if_fail (arch != NULL, NULL);
+
+  self = _ide_triplet_construct ();
+  self->arch = g_strdup (arch);
+  self->kernel = g_strdup (kernel);
+  self->operating_system = g_strdup (operating_system);
+
+  full_name = g_strdup (arch);
+  if (kernel != NULL)
+    {
+      g_autofree gchar *start_full_name = full_name;
+      full_name = g_strdup_printf ("%s-%s", start_full_name, kernel);
+    }
+
+  if (operating_system != NULL)
+    {
+      g_autofree gchar *start_full_name = full_name;
+      full_name = g_strdup_printf ("%s-%s", start_full_name, operating_system);
+    }
+
+  self->full_name = g_steal_pointer (&full_name);
+
+  return self;
+}
+
+/**
+ * ide_triplet_new_with_quadruplet:
+ * @arch: The name of the architecture of the machine (like "x86_64")
+ * @vendor: (nullable): The name of the vendor of the machine (like "pc")
+ * @kernel: (nullable): The name of the kernel of the machine (like "linux")
+ * @operating_system: (nullable): The name of the os of the machine (like "gnuabi64")
+ *
+ * Creates a new #IdeTriplet from a given quadruplet of
+ * "arch-vendor-kernel-os" (like "i686-pc-linux-gnu")
+ *
+ * Returns: (transfer full): An #IdeTriplet.
+ *
+ * Since: 3.32
+ */
+IdeTriplet *
+ide_triplet_new_with_quadruplet (const gchar *arch,
+                                 const gchar *vendor,
+                                 const gchar *kernel,
+                                 const gchar *operating_system)
+{
+  IdeTriplet *self;
+  g_autofree gchar *full_name = NULL;
+
+  g_return_val_if_fail (arch != NULL, NULL);
+
+  if (vendor == NULL)
+    return ide_triplet_new_with_triplet (arch, kernel, operating_system);
+
+  self = _ide_triplet_construct ();
+  self->arch = g_strdup (arch);
+  self->vendor = g_strdup (vendor);
+  self->kernel = g_strdup (kernel);
+  self->operating_system = g_strdup (operating_system);
+
+  full_name = g_strdup_printf ("%s-%s", arch, vendor);
+  if (kernel != NULL)
+    {
+      g_autofree gchar *start_full_name = full_name;
+      full_name = g_strdup_printf ("%s-%s", start_full_name, kernel);
+    }
+
+  if (operating_system != NULL)
+    {
+      g_autofree gchar *start_full_name = full_name;
+      full_name = g_strdup_printf ("%s-%s", start_full_name, operating_system);
+    }
+
+  self->full_name = g_steal_pointer (&full_name);
+
+  return self;
+}
+
+static void
+ide_triplet_finalize (IdeTriplet *self)
+{
+  g_free (self->full_name);
+  g_free (self->arch);
+  g_free (self->vendor);
+  g_free (self->kernel);
+  g_free (self->operating_system);
+  g_slice_free (IdeTriplet, self);
+}
+
+/**
+ * ide_triplet_ref:
+ * @self: An #IdeTriplet
+ *
+ * Increases the reference count of @self
+ *
+ * Returns: (transfer none): An #IdeTriplet.
+ *
+ * Since: 3.32
+ */
+IdeTriplet *
+ide_triplet_ref (IdeTriplet *self)
+{
+  g_return_val_if_fail (self, NULL);
+  g_return_val_if_fail (self->ref_count > 0, NULL);
+
+  g_atomic_int_inc (&self->ref_count);
+
+  return self;
+}
+
+/**
+ * ide_triplet_unref:
+ * @self: An #IdeTriplet
+ *
+ * Decreases the reference count of @self
+ * Once the reference count reaches 0, the object is freed.
+ *
+ * Since: 3.32
+ */
+void
+ide_triplet_unref (IdeTriplet *self)
+{
+  g_return_if_fail (self);
+  g_return_if_fail (self->ref_count > 0);
+
+  if (g_atomic_int_dec_and_test (&self->ref_count))
+    ide_triplet_finalize (self);
+}
+
+/**
+ * ide_triplet_get_full_name:
+ * @self: An #IdeTriplet
+ *
+ * Gets the full name of the machine configuration name (can be an architecture name,
+ * a duet, a triplet or a quadruplet).
+ *
+ * Returns: (transfer none): The full name of the machine configuration name
+ *
+ * Since: 3.32
+ */
+const gchar *
+ide_triplet_get_full_name (IdeTriplet *self)
+{
+  g_return_val_if_fail (self, NULL);
+
+  return self->full_name;
+}
+
+/**
+ * ide_triplet_get_arch:
+ * @self: An #IdeTriplet
+ *
+ * Gets the architecture name of the machine
+ *
+ * Returns: (transfer none): The architecture name of the machine
+ *
+ * Since: 3.32
+ */
+const gchar *
+ide_triplet_get_arch (IdeTriplet *self)
+{
+  g_return_val_if_fail (self, NULL);
+
+  return self->arch;
+}
+
+/**
+ * ide_triplet_get_vendor:
+ * @self: An #IdeTriplet
+ *
+ * Gets the vendor name of the machine
+ *
+ * Returns: (transfer none) (nullable): The vendor name of the machine
+ *
+ * Since: 3.32
+ */
+const gchar *
+ide_triplet_get_vendor (IdeTriplet *self)
+{
+  g_return_val_if_fail (self, NULL);
+
+  return self->vendor;
+}
+
+/**
+ * ide_triplet_get_kernel:
+ * @self: An #IdeTriplet
+ *
+ * Gets name of the kernel of the machine
+ *
+ * Returns: (transfer none) (nullable): The name of the kernel of the machine
+ *
+ * Since: 3.32
+ */
+const gchar *
+ide_triplet_get_kernel (IdeTriplet *self)
+{
+  g_return_val_if_fail (self, NULL);
+
+  return self->kernel;
+}
+
+/**
+ * ide_triplet_get_operating_system:
+ * @self: An #IdeTriplet
+ *
+ * Gets name of the operating system of the machine
+ *
+ * Returns: (transfer none) (nullable): The name of the operating system of the machine
+ *
+ * Since: 3.32
+ */
+const gchar *
+ide_triplet_get_operating_system (IdeTriplet *self)
+{
+  g_return_val_if_fail (self, NULL);
+
+  return self->operating_system;
+}
+
+
+/**
+ * ide_triplet_is_system:
+ * @self: An #IdeTriplet
+ *
+ * Gets whether this is the same architecture as the system
+ *
+ * Returns: %TRUE if this is the same architecture as the system, %FALSE otherwise
+ *
+ * Since: 3.32
+ */
+gboolean
+ide_triplet_is_system (IdeTriplet *self)
+{
+  g_autofree gchar *system_arch = ide_get_system_arch ();
+
+  g_return_val_if_fail (self, FALSE);
+
+  return g_strcmp0 (self->arch, system_arch) == 0;
+}
diff --git a/src/libide/foundry/ide-triplet.h b/src/libide/foundry/ide-triplet.h
new file mode 100644
index 000000000..54c70fb7a
--- /dev/null
+++ b/src/libide/foundry/ide-triplet.h
@@ -0,0 +1,70 @@
+/* ide-triplet.c
+ *
+ * Copyright 2018 Corentin Noël <corentin noel collabora com>
+ * Copyright 2018 Collabora Ltd.
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
+
+#include <libide-core.h>
+
+#include "ide-foundry-types.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_TRIPLET (ide_triplet_get_type())
+
+IDE_AVAILABLE_IN_3_32
+GType         ide_triplet_get_type             (void);
+IDE_AVAILABLE_IN_3_32
+IdeTriplet   *ide_triplet_new                  (const gchar  *full_name);
+IDE_AVAILABLE_IN_3_32
+IdeTriplet   *ide_triplet_new_from_system      (void);
+IDE_AVAILABLE_IN_3_32
+IdeTriplet   *ide_triplet_new_with_triplet     (const gchar  *arch,
+                                                const gchar  *kernel,
+                                                const gchar  *operating_system);
+IDE_AVAILABLE_IN_3_32
+IdeTriplet   *ide_triplet_new_with_quadruplet  (const gchar  *arch,
+                                                const gchar  *vendor,
+                                                const gchar  *kernel,
+                                                const gchar  *operating_system);
+IDE_AVAILABLE_IN_3_32
+IdeTriplet   *ide_triplet_ref                  (IdeTriplet   *self);
+IDE_AVAILABLE_IN_3_32
+void          ide_triplet_unref                (IdeTriplet   *self);
+IDE_AVAILABLE_IN_3_32
+const gchar  *ide_triplet_get_full_name        (IdeTriplet   *self);
+IDE_AVAILABLE_IN_3_32
+const gchar  *ide_triplet_get_arch             (IdeTriplet   *self);
+IDE_AVAILABLE_IN_3_32
+const gchar  *ide_triplet_get_vendor           (IdeTriplet   *self);
+IDE_AVAILABLE_IN_3_32
+const gchar  *ide_triplet_get_kernel           (IdeTriplet   *self);
+IDE_AVAILABLE_IN_3_32
+const gchar  *ide_triplet_get_operating_system (IdeTriplet   *self);
+IDE_AVAILABLE_IN_3_32
+gboolean      ide_triplet_is_system            (IdeTriplet   *self);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (IdeTriplet, ide_triplet_unref)
+
+G_END_DECLS
diff --git a/src/libide/foundry/libide-foundry.h b/src/libide/foundry/libide-foundry.h
new file mode 100644
index 000000000..066082321
--- /dev/null
+++ b/src/libide/foundry/libide-foundry.h
@@ -0,0 +1,75 @@
+/* libide-foundry.h"
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-core.h>
+#include <libide-io.h>
+#include <libide-threading.h>
+
+G_BEGIN_DECLS
+
+#define IDE_FOUNDRY_INSIDE
+
+#include "ide-build-log.h"
+#include "ide-build-manager.h"
+#include "ide-build-pipeline-addin.h"
+#include "ide-build-pipeline.h"
+#include "ide-build-stage-launcher.h"
+#include "ide-build-stage-mkdirs.h"
+#include "ide-build-stage-transfer.h"
+#include "ide-build-stage.h"
+#include "ide-build-system-discovery.h"
+#include "ide-build-system.h"
+#include "ide-build-target-provider.h"
+#include "ide-build-target.h"
+#include "ide-configuration.h"
+#include "ide-configuration-manager.h"
+#include "ide-configuration-provider.h"
+#include "ide-compile-commands.h"
+#include "ide-dependency-updater.h"
+#include "ide-deploy-strategy.h"
+#include "ide-device-info.h"
+#include "ide-device-manager.h"
+#include "ide-device-provider.h"
+#include "ide-device.h"
+#include "ide-fallback-build-system.h"
+#include "ide-foundry-compat.h"
+#include "ide-local-device.h"
+#include "ide-run-manager.h"
+#include "ide-runner-addin.h"
+#include "ide-runner.h"
+#include "ide-runtime-manager.h"
+#include "ide-runtime-provider.h"
+#include "ide-runtime.h"
+#include "ide-simple-build-system-discovery.h"
+#include "ide-simple-build-target.h"
+#include "ide-simple-toolchain.h"
+#include "ide-test.h"
+#include "ide-test-manager.h"
+#include "ide-test-provider.h"
+#include "ide-toolchain-manager.h"
+#include "ide-toolchain-provider.h"
+#include "ide-toolchain.h"
+#include "ide-triplet.h"
+
+#undef IDE_FOUNDRY_INSIDE
+
+G_END_DECLS
diff --git a/src/libide/foundry/meson.build b/src/libide/foundry/meson.build
new file mode 100644
index 000000000..173036f03
--- /dev/null
+++ b/src/libide/foundry/meson.build
@@ -0,0 +1,192 @@
+libide_foundry_header_dir = join_paths(libide_header_dir, 'foundry')
+libide_foundry_header_subdir = join_paths(libide_header_subdir, 'foundry')
+libide_include_directories += include_directories('.')
+
+libide_foundry_sources = []
+libide_foundry_public_headers = []
+libide_foundry_generated_headers = []
+
+#
+# Public API Headers
+#
+
+libide_foundry_public_headers = [
+  'ide-build-log.h',
+  'ide-build-manager.h',
+  'ide-build-pipeline-addin.h',
+  'ide-build-pipeline.h',
+  'ide-build-stage-launcher.h',
+  'ide-build-stage-mkdirs.h',
+  'ide-build-stage-transfer.h',
+  'ide-build-stage.h',
+  'ide-build-system-discovery.h',
+  'ide-build-system.h',
+  'ide-build-target-provider.h',
+  'ide-build-target.h',
+  'ide-compile-commands.h',
+  'ide-configuration-manager.h',
+  'ide-configuration-provider.h',
+  'ide-configuration.h',
+  'ide-dependency-updater.h',
+  'ide-deploy-strategy.h',
+  'ide-device-info.h',
+  'ide-device-manager.h',
+  'ide-device-provider.h',
+  'ide-device.h',
+  'ide-fallback-build-system.h',
+  'ide-foundry-types.h',
+  'ide-local-device.h',
+  'ide-run-manager.h',
+  'ide-runner-addin.h',
+  'ide-runner.h',
+  'ide-runtime-manager.h',
+  'ide-runtime-provider.h',
+  'ide-runtime.h',
+  'ide-simple-build-system-discovery.h',
+  'ide-simple-build-target.h',
+  'ide-simple-toolchain.h',
+  'ide-toolchain-manager.h',
+  'ide-toolchain-provider.h',
+  'ide-toolchain.h',
+  'ide-triplet.h',
+  'libide-foundry.h',
+]
+
+libide_foundry_private_headers = [
+  'ide-build-log-private.h',
+  'ide-build-private.h',
+  'ide-build-stage-private.h',
+  'ide-configuration-private.h',
+  'ide-device-private.h',
+  'ide-foundry-init.h',
+  'ide-run-manager-private.h',
+  'ide-runtime-private.h',
+  'ide-toolchain-private.h',
+]
+
+libide_foundry_enum_headers = [
+  'ide-build-log.h',
+  'ide-build-pipeline.h',
+  'ide-configuration.h',
+  'ide-device.h',
+  'ide-device-info.h',
+  'ide-runtime.h',
+  'ide-test.h',
+]
+
+install_headers(libide_foundry_public_headers, subdir: libide_foundry_header_subdir)
+
+#
+# Sources
+#
+
+libide_foundry_public_sources = [
+  'ide-build-manager.c',
+  'ide-build-pipeline-addin.c',
+  'ide-build-pipeline.c',
+  'ide-build-stage-launcher.c',
+  'ide-build-stage-mkdirs.c',
+  'ide-build-stage-transfer.c',
+  'ide-build-stage.c',
+  'ide-build-system-discovery.c',
+  'ide-build-system.c',
+  'ide-build-target-provider.c',
+  'ide-build-target.c',
+  'ide-compile-commands.c',
+  'ide-configuration-manager.c',
+  'ide-configuration-provider.c',
+  'ide-configuration.c',
+  'ide-dependency-updater.c',
+  'ide-deploy-strategy.c',
+  'ide-device-info.c',
+  'ide-device-manager.c',
+  'ide-device-provider.c',
+  'ide-device.c',
+  'ide-fallback-build-system.c',
+  'ide-foundry-compat.c',
+  'ide-local-device.c',
+  'ide-run-manager.c',
+  'ide-runner-addin.c',
+  'ide-runner.c',
+  'ide-runtime-manager.c',
+  'ide-runtime-provider.c',
+  'ide-runtime.c',
+  'ide-simple-build-system-discovery.c',
+  'ide-simple-build-target.c',
+  'ide-simple-toolchain.c',
+  'ide-test.c',
+  'ide-test-manager.c',
+  'ide-test-provider.c',
+  'ide-toolchain-manager.c',
+  'ide-toolchain-provider.c',
+  'ide-toolchain.c',
+  'ide-triplet.c',
+]
+
+
+libide_foundry_private_sources = [
+  'ide-build-log.c',
+  'ide-build-utils.c',
+  'ide-foundry-init.c',
+]
+
+libide_foundry_sources += libide_foundry_public_sources
+libide_foundry_sources += libide_foundry_private_sources
+
+#
+# Enum generation
+#
+
+libide_foundry_enums = gnome.mkenums_simple('ide-foundry-enums',
+     body_prefix: '#include "config.h"',
+   header_prefix: '#include <libide-core.h>',
+       decorator: '_IDE_EXTERN',
+         sources: libide_foundry_enum_headers,
+  install_header: true,
+     install_dir: libide_foundry_header_dir,
+)
+libide_foundry_sources += [libide_foundry_enums[0]]
+libide_foundry_generated_headers += [libide_foundry_enums[1]]
+
+#
+# Dependencies
+#
+
+libide_foundry_deps = [
+  libgio_dep,
+  libgtk_dep,
+  libdazzle_dep,
+  libpeas_dep,
+  libvte_dep,
+  libjson_glib_dep,
+
+  libide_core_dep,
+  libide_io_dep,
+  libide_projects_dep,
+  libide_threading_dep,
+]
+
+#
+# Library Definitions
+#
+
+libide_foundry = static_library('ide-foundry-' + libide_api_version,
+  libide_foundry_sources, libide_foundry_generated_headers,
+   dependencies: libide_foundry_deps,
+         c_args: libide_args + release_args + ['-DIDE_FOUNDRY_COMPILATION'],
+)
+
+libide_foundry_dep = declare_dependency(
+         dependencies: libide_foundry_deps,
+           link_whole: libide_foundry,
+  include_directories: include_directories('.'),
+              sources: libide_foundry_generated_headers,
+)
+
+gnome_builder_public_sources += files(libide_foundry_public_sources)
+gnome_builder_public_headers += files(libide_foundry_public_headers)
+gnome_builder_private_sources += files(libide_foundry_private_sources)
+gnome_builder_private_headers += files(libide_foundry_private_headers)
+gnome_builder_generated_headers += libide_foundry_generated_headers
+gnome_builder_include_subdirs += libide_foundry_header_subdir
+gnome_builder_gir_extra_args += ['--c-include=libide-foundry.h', '-DIDE_FOUNDRY_COMPILATION']


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