[gnome-builder/wip/tintou/sysroot-toolchain] sysroot: Provide the toolchain for OpenEmbedded targets



commit afb78b801d3e2555671f844cee1aca02f85ad959
Author: Corentin Noël <corentin noel collabora co uk>
Date:   Thu Apr 19 16:11:07 2018 +0100

    sysroot: Provide the toolchain for OpenEmbedded targets

 .../meson/gbp-meson-build-stage-cross-file.c       | 230 +++++++++++++++
 .../meson/gbp-meson-build-stage-cross-file.h       |  35 +++
 src/plugins/meson/gbp-meson-pipeline-addin.c       |  77 +----
 src/plugins/meson/meson.build                      |   2 +
 src/plugins/sysroot/gbp-sysroot-runtime.c          |  17 +-
 .../sysroot/gbp-sysroot-toolchain-provider.c       | 313 +++++++++++++++++++++
 .../sysroot/gbp-sysroot-toolchain-provider.h       |  30 ++
 src/plugins/sysroot/meson.build                    |   4 +-
 src/plugins/sysroot/sysroot-plugin.c               |   2 +
 9 files changed, 635 insertions(+), 75 deletions(-)
---
diff --git a/src/plugins/meson/gbp-meson-build-stage-cross-file.c 
b/src/plugins/meson/gbp-meson-build-stage-cross-file.c
new file mode 100644
index 000000000..8d23c73b7
--- /dev/null
+++ b/src/plugins/meson/gbp-meson-build-stage-cross-file.c
@@ -0,0 +1,230 @@
+/* gbp-meson-build-stage-cross-file.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/>.
+ */
+
+#define G_LOG_DOMAIN "gbp-meson-build-stage-cross-file"
+
+#include "config.h"
+
+#include "gbp-meson-build-stage-cross-file.h"
+
+struct _GbpMesonBuildStageCrossFile
+{
+  IdeBuildStage parent_instance;
+  IdeToolchain *toolchain;
+};
+
+G_DEFINE_TYPE (GbpMesonBuildStageCrossFile, gbp_meson_build_stage_cross_file, IDE_TYPE_BUILD_STAGE)
+
+static void
+_g_key_file_set_string_quoted (GKeyFile *keyfile,
+                               const gchar *group,
+                               const gchar *key,
+                               const gchar *unquoted_value)
+{
+  g_autofree gchar *quoted_value = NULL;
+
+  g_return_if_fail (keyfile != NULL);
+  g_return_if_fail (group != NULL);
+  g_return_if_fail (key != NULL);
+  g_return_if_fail (unquoted_value != NULL);
+
+  quoted_value = g_strdup_printf ("'%s'", unquoted_value);
+  g_key_file_set_string (keyfile, group, key, quoted_value);
+}
+
+static void
+_g_key_file_set_string_array_quoted (GKeyFile *keyfile,
+                                     const gchar *group,
+                                     const gchar *key,
+                                     const gchar *unquoted_value)
+{
+  g_autofree gchar *quoted_value = NULL;
+
+  g_return_if_fail (keyfile != NULL);
+  g_return_if_fail (group != NULL);
+  g_return_if_fail (key != NULL);
+  g_return_if_fail (unquoted_value != NULL);
+
+  quoted_value = g_strdup_printf ("['%s']", unquoted_value);
+  g_key_file_set_string (keyfile, group, key, quoted_value);
+}
+
+static void
+add_lang_executable (const gchar *lang,
+                     const gchar *path,
+                     GKeyFile *keyfile)
+{
+  if (g_strcmp0 (lang, IDE_TOOLCHAIN_TOOL_CPP) == 0)
+    lang = "cpp";
+
+  _g_key_file_set_string_quoted (keyfile, "binaries", lang, path);
+}
+
+static void
+gbp_meson_build_stage_cross_file_query (IdeBuildStage    *stage,
+                                        IdeBuildPipeline *pipeline,
+                                        GCancellable     *cancellable)
+{
+  GbpMesonBuildStageCrossFile *self = (GbpMesonBuildStageCrossFile *)stage;
+  g_autofree gchar *crossbuild_file = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_MESON_BUILD_STAGE_CROSS_FILE (self));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  crossbuild_file = gbp_meson_build_stage_cross_file_get_path (self, pipeline);
+  if (!g_file_test (crossbuild_file, G_FILE_TEST_EXISTS))
+    {
+      ide_build_stage_set_completed (stage, FALSE);
+      IDE_EXIT;
+    }
+
+  ide_build_stage_set_completed (stage, TRUE);
+
+  IDE_EXIT;
+}
+
+static gboolean
+gbp_meson_build_stage_cross_file_execute (IdeBuildStage     *stage,
+                                          IdeBuildPipeline  *pipeline,
+                                          GCancellable      *cancellable,
+                                          GError           **error)
+{
+  GbpMesonBuildStageCrossFile *self = (GbpMesonBuildStageCrossFile *)stage;
+  g_autoptr(GKeyFile) crossbuild_keyfile = NULL;
+  g_autoptr(IdeTriplet) triplet = NULL;
+  g_autoptr(IdeSubprocessLauncher) env_launcher = NULL;
+  g_autofree gchar *crossbuild_file = NULL;
+  const gchar *binary_path;
+  const gchar *flags;
+  GHashTable *compilers;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_MESON_BUILD_STAGE_CROSS_FILE (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+  g_assert (IDE_IS_TOOLCHAIN (self->toolchain));
+
+  ide_build_stage_set_active (stage, TRUE);
+
+  crossbuild_keyfile = g_key_file_new ();
+  triplet = ide_toolchain_get_host_triplet (self->toolchain);
+
+  compilers  = ide_toolchain_get_tools_for_id (self->toolchain,
+                                               IDE_TOOLCHAIN_TOOL_CC);
+  g_hash_table_foreach (compilers, (GHFunc)add_lang_executable, crossbuild_keyfile);
+
+  binary_path = ide_toolchain_get_tool_for_language (self->toolchain,
+                                                     IDE_TOOLCHAIN_LANGUAGE_ANY,
+                                                     IDE_TOOLCHAIN_TOOL_AR);
+  if (binary_path != NULL)
+    _g_key_file_set_string_quoted (crossbuild_keyfile, "binaries", "ar", binary_path);
+
+  binary_path = ide_toolchain_get_tool_for_language (self->toolchain,
+                                                     IDE_TOOLCHAIN_LANGUAGE_ANY,
+                                                     IDE_TOOLCHAIN_TOOL_STRIP);
+  if (binary_path != NULL)
+    _g_key_file_set_string_quoted (crossbuild_keyfile, "binaries", "strip", binary_path);
+
+  binary_path = ide_toolchain_get_tool_for_language (self->toolchain,
+                                                     IDE_TOOLCHAIN_LANGUAGE_ANY,
+                                                     IDE_TOOLCHAIN_TOOL_PKG_CONFIG);
+  if (binary_path != NULL)
+    _g_key_file_set_string_quoted (crossbuild_keyfile, "binaries", "pkgconfig", binary_path);
+
+  binary_path = ide_toolchain_get_tool_for_language (self->toolchain,
+                                                     IDE_TOOLCHAIN_LANGUAGE_ANY,
+                                                     IDE_TOOLCHAIN_TOOL_EXEC);
+  if (binary_path != NULL)
+    _g_key_file_set_string_quoted (crossbuild_keyfile, "binaries", "exe_wrapper", binary_path);
+
+  binary_path = ide_triplet_get_kernel (triplet);
+  _g_key_file_set_string_quoted (crossbuild_keyfile, "host_machine", "system", binary_path);
+
+  binary_path = ide_triplet_get_arch (triplet);
+  _g_key_file_set_string_quoted (crossbuild_keyfile, "host_machine", "cpu_family", binary_path);
+
+  _g_key_file_set_string_quoted (crossbuild_keyfile, "host_machine", "cpu", binary_path);
+  _g_key_file_set_string_quoted (crossbuild_keyfile, "host_machine", "endian", "little");
+
+  env_launcher = ide_build_pipeline_create_launcher (pipeline, error);
+  flags = ide_subprocess_launcher_getenv (env_launcher, "CFLAGS");
+  _g_key_file_set_string_array_quoted (crossbuild_keyfile, "properties", "c_args", flags);
+  flags = ide_subprocess_launcher_getenv (env_launcher, "LDFLAGS");
+  _g_key_file_set_string_array_quoted (crossbuild_keyfile, "properties", "c_link_args", flags);
+
+  crossbuild_file = gbp_meson_build_stage_cross_file_get_path (self, pipeline);
+  if (!g_key_file_save_to_file (crossbuild_keyfile, crossbuild_file, error))
+    IDE_RETURN (FALSE);
+
+  ide_build_stage_set_active (stage, FALSE);
+
+  IDE_RETURN (TRUE);
+}
+
+static void
+ide_build_stage_mkdirs_finalize (GObject *object)
+{
+  GbpMesonBuildStageCrossFile *self = (GbpMesonBuildStageCrossFile *)object;
+
+  g_clear_object (&self->toolchain);
+
+  G_OBJECT_CLASS (gbp_meson_build_stage_cross_file_parent_class)->finalize (object);
+}
+
+static void
+gbp_meson_build_stage_cross_file_class_init (GbpMesonBuildStageCrossFileClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  IdeBuildStageClass *stage_class = IDE_BUILD_STAGE_CLASS (klass);
+
+  object_class->finalize = ide_build_stage_mkdirs_finalize;
+
+  stage_class->execute = gbp_meson_build_stage_cross_file_execute;
+  stage_class->query = gbp_meson_build_stage_cross_file_query;
+}
+
+static void
+gbp_meson_build_stage_cross_file_init (GbpMesonBuildStageCrossFile *self)
+{
+  
+}
+
+GbpMesonBuildStageCrossFile *
+gbp_meson_build_stage_cross_file_new (IdeContext    *context,
+                                      IdeToolchain  *toolchain)
+{
+  GbpMesonBuildStageCrossFile *build_stage = g_object_new (GBP_TYPE_MESON_BUILD_STAGE_CROSS_FILE,
+                                                           "context", context,
+                                                           NULL);
+  build_stage->toolchain = g_object_ref (toolchain);
+  return build_stage;
+}
+
+gchar *
+gbp_meson_build_stage_cross_file_get_path (GbpMesonBuildStageCrossFile *stage,
+                                           IdeBuildPipeline            *pipeline)
+{
+  g_return_val_if_fail (GBP_IS_MESON_BUILD_STAGE_CROSS_FILE (stage), NULL);
+  g_return_val_if_fail (IDE_IS_BUILD_PIPELINE (pipeline), NULL);
+
+  return ide_build_pipeline_build_builddir_path (pipeline, "gnome-builder-meson.crossfile", NULL);
+}
diff --git a/src/plugins/meson/gbp-meson-build-stage-cross-file.h 
b/src/plugins/meson/gbp-meson-build-stage-cross-file.h
new file mode 100644
index 000000000..4f06968eb
--- /dev/null
+++ b/src/plugins/meson/gbp-meson-build-stage-cross-file.h
@@ -0,0 +1,35 @@
+/* gbp-meson-build-stage-cross-file.h
+ *
+ * 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/>.
+ */
+
+#pragma once
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_MESON_BUILD_STAGE_CROSS_FILE (gbp_meson_build_stage_cross_file_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpMesonBuildStageCrossFile, gbp_meson_build_stage_cross_file, GBP, 
MESON_BUILD_STAGE_CROSS_FILE, IdeBuildStage)
+
+GbpMesonBuildStageCrossFile *gbp_meson_build_stage_cross_file_new      (IdeContext                  *context,
+                                                                        IdeToolchain                
*toolchain);
+gchar                       *gbp_meson_build_stage_cross_file_get_path (GbpMesonBuildStageCrossFile *stage,
+                                                                        IdeBuildPipeline            
*pipeline);
+
+G_END_DECLS
diff --git a/src/plugins/meson/gbp-meson-pipeline-addin.c b/src/plugins/meson/gbp-meson-pipeline-addin.c
index afd37dabb..bc389eea2 100644
--- a/src/plugins/meson/gbp-meson-pipeline-addin.c
+++ b/src/plugins/meson/gbp-meson-pipeline-addin.c
@@ -21,6 +21,7 @@
 #include <glib/gi18n.h>
 
 #include "gbp-meson-toolchain.h"
+#include "gbp-meson-build-stage-cross-file.h"
 #include "gbp-meson-build-system.h"
 #include "gbp-meson-pipeline-addin.h"
 
@@ -44,31 +45,6 @@ on_stage_query (IdeBuildStage    *stage,
   ide_build_stage_set_completed (stage, FALSE);
 }
 
-static void
-_g_key_file_set_string_quoted (GKeyFile *keyfile,
-                               const gchar *group,
-                               const gchar *key,
-                               const gchar *unquoted_value)
-{
-  g_autofree gchar *quoted_value = NULL;
-
-  g_return_if_fail (keyfile != NULL);
-  g_return_if_fail (group != NULL);
-  g_return_if_fail (key != NULL);
-  g_return_if_fail (unquoted_value != NULL);
-
-  quoted_value = g_strdup_printf ("'%s'", unquoted_value);
-  g_key_file_set_string (keyfile, group, key, quoted_value);
-}
-
-static void
-add_lang_executable (gchar *lang,
-                     gchar *path,
-                     GKeyFile *keyfile)
-{
-    _g_key_file_set_string_quoted (keyfile, "binaries", lang, path);
-}
-
 static void
 gbp_meson_pipeline_addin_load (IdeBuildPipelineAddin *addin,
                                IdeBuildPipeline      *pipeline)
@@ -146,55 +122,18 @@ gbp_meson_pipeline_addin_load (IdeBuildPipelineAddin *addin,
   if (NULL == (meson = ide_configuration_getenv (config, "MESON")))
     meson = "meson";
 
-  /* Create the toolchain file is required */
+  /* Create the toolchain file if required */
+
   if (GBP_IS_MESON_TOOLCHAIN (toolchain))
     crossbuild_file = g_strdup (gbp_meson_toolchain_get_file_path (GBP_MESON_TOOLCHAIN (toolchain)));
   else if (g_strcmp0 (ide_toolchain_get_id (toolchain), "default") != 0)
     {
-      g_autoptr(GKeyFile) crossbuild_keyfile = NULL;
-      g_autoptr(IdeTriplet) triplet = NULL;
-      g_autofree gchar *crossfile_name = NULL;
-      const gchar *binary_path;
-      GHashTable *compilers;
+      GbpMesonBuildStageCrossFile *cross_file_stage;
+      cross_file_stage = gbp_meson_build_stage_cross_file_new (context, toolchain);
+      crossbuild_file = gbp_meson_build_stage_cross_file_get_path (cross_file_stage, pipeline);
 
-      crossfile_name = g_strdup_printf ("gnome-builder-%s.crossfile", ide_toolchain_get_id (toolchain));
-      crossbuild_file = ide_build_pipeline_build_builddir_path (pipeline, crossfile_name, NULL);
-
-      crossbuild_keyfile = g_key_file_new ();
-      triplet = ide_toolchain_get_host_triplet (toolchain);
-
-      compilers  = ide_toolchain_get_tools_for_id (toolchain,
-                                                   IDE_TOOLCHAIN_TOOL_CC);
-      g_hash_table_foreach (compilers, (GHFunc)add_lang_executable, crossbuild_keyfile);
-
-      binary_path = ide_toolchain_get_tool_for_language (toolchain,
-                                                         IDE_TOOLCHAIN_LANGUAGE_ANY,
-                                                         IDE_TOOLCHAIN_TOOL_AR);
-      _g_key_file_set_string_quoted (crossbuild_keyfile, "binaries", "ar", binary_path);
-
-      binary_path = ide_toolchain_get_tool_for_language (toolchain,
-                                                         IDE_TOOLCHAIN_LANGUAGE_ANY,
-                                                         IDE_TOOLCHAIN_TOOL_STRIP);
-      _g_key_file_set_string_quoted (crossbuild_keyfile, "binaries", "strip", binary_path);
-
-      binary_path = ide_toolchain_get_tool_for_language (toolchain,
-                                                         IDE_TOOLCHAIN_LANGUAGE_ANY,
-                                                         IDE_TOOLCHAIN_TOOL_PKG_CONFIG);
-      _g_key_file_set_string_quoted (crossbuild_keyfile, "binaries", "pkgconfig", binary_path);
-
-      binary_path = ide_toolchain_get_tool_for_language (toolchain,
-                                                         IDE_TOOLCHAIN_LANGUAGE_ANY,
-                                                         IDE_TOOLCHAIN_TOOL_EXEC);
-      _g_key_file_set_string_quoted (crossbuild_keyfile, "binaries", "exe_wrapper", binary_path);
-
-      binary_path = ide_triplet_get_kernel (triplet);
-      _g_key_file_set_string_quoted (crossbuild_keyfile, "host_machine", "system", binary_path);
-
-      binary_path = ide_triplet_get_arch (triplet);
-      _g_key_file_set_string_quoted (crossbuild_keyfile, "host_machine", "cpu_family", binary_path);
-
-      if (!g_key_file_save_to_file (crossbuild_keyfile, crossbuild_file, &error))
-        IDE_GOTO (failure);
+      id = ide_build_pipeline_connect (pipeline, IDE_BUILD_PHASE_PREPARE, 0, IDE_BUILD_STAGE 
(cross_file_stage));
+      ide_build_pipeline_addin_track (addin, id);
     }
 
   /* Setup our meson configure stage. */
diff --git a/src/plugins/meson/meson.build b/src/plugins/meson/meson.build
index 53ca7cd71..8337b0b67 100644
--- a/src/plugins/meson/meson.build
+++ b/src/plugins/meson/meson.build
@@ -8,6 +8,8 @@ meson_resources = gnome.compile_resources(
 
 meson_sources = [
   'meson-plugin.c',
+  'gbp-meson-build-stage-cross-file.c',
+  'gbp-meson-build-stage-cross-file.h',
   'gbp-meson-build-system.c',
   'gbp-meson-build-system.h',
   'gbp-meson-build-target.c',
diff --git a/src/plugins/sysroot/gbp-sysroot-runtime.c b/src/plugins/sysroot/gbp-sysroot-runtime.c
index ec13aedfc..faa2e3388 100644
--- a/src/plugins/sysroot/gbp-sysroot-runtime.c
+++ b/src/plugins/sysroot/gbp-sysroot-runtime.c
@@ -90,21 +90,27 @@ gbp_sysroot_runtime_create_launcher (IdeRuntime  *runtime,
   if (ret != NULL)
     {
       GbpSysrootManager *sysroot_manager = NULL;
-      g_autofree gchar *sysroot_cflags = NULL;
+      g_autofree gchar *sysroot_flag = NULL;
       g_autofree gchar *sysroot_libdirs = NULL;
       g_autofree gchar *sysroot_path = NULL;
       g_autofree gchar *pkgconfig_dirs = NULL;
       g_autofree gchar *cflags = NULL;
+      g_autofree gchar *ldflags = NULL;
       g_auto(GStrv) path_parts = NULL;
-      const gchar *env_var = NULL;
+      const gchar *previous_env = NULL;
       const gchar *sysroot_id = NULL;
 
       sysroot_id = gbp_sysroot_runtime_get_sysroot_id (self);
       sysroot_manager = gbp_sysroot_manager_get_default ();
       sysroot_path = gbp_sysroot_manager_get_target_path (sysroot_manager, sysroot_id);
-      env_var = ide_subprocess_launcher_getenv (ret, "CFLAGS");
-      sysroot_cflags = g_strconcat ("--sysroot=", sysroot_path, NULL);
-      cflags = g_strjoin (" ", sysroot_cflags, env_var, NULL);
+      sysroot_flag = g_strconcat ("--sysroot=", sysroot_path, NULL);
+
+      previous_env = ide_subprocess_launcher_getenv (ret, "CFLAGS");
+      cflags = g_strjoin (" ", sysroot_flag, previous_env, NULL);
+
+      previous_env = ide_subprocess_launcher_getenv (ret, "LDFLAGS");
+      ldflags = g_strjoin (" ", sysroot_flag, previous_env, NULL);
+
       pkgconfig_dirs = gbp_sysroot_manager_get_target_pkg_config_path (sysroot_manager, sysroot_id);
 
       if (!dzl_str_empty0 (pkgconfig_dirs))
@@ -119,6 +125,7 @@ gbp_sysroot_runtime_create_launcher (IdeRuntime  *runtime,
       ide_subprocess_launcher_set_clear_env (ret, FALSE);
 
       ide_subprocess_launcher_setenv (ret, "CFLAGS", cflags, TRUE);
+      ide_subprocess_launcher_setenv (ret, "LDFLAGS", ldflags, TRUE);
       ide_subprocess_launcher_setenv (ret, "PKG_CONFIG_DIR", "", TRUE);
       ide_subprocess_launcher_setenv (ret, "PKG_CONFIG_SYSROOT_DIR", g_strdup (sysroot_path), TRUE);
       ide_subprocess_launcher_setenv (ret, "PKG_CONFIG_LIBDIR", sysroot_libdirs, TRUE);
diff --git a/src/plugins/sysroot/gbp-sysroot-toolchain-provider.c 
b/src/plugins/sysroot/gbp-sysroot-toolchain-provider.c
new file mode 100644
index 000000000..015a8df69
--- /dev/null
+++ b/src/plugins/sysroot/gbp-sysroot-toolchain-provider.c
@@ -0,0 +1,313 @@
+/* gbp-sysroot-toolchain-provider.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/>.
+ */
+
+#define G_LOG_DOMAIN "gbp-sysroot-toolchain-provider"
+
+#include "gbp-sysroot-toolchain-provider.h"
+#include "gbp-sysroot-manager.h"
+
+struct _GbpSysrootToolchainProvider
+{
+  IdeObject            parent_instance;
+  GPtrArray           *toolchains;
+};
+
+static gchar *
+_create_tool_path (const gchar *base_path,
+                   const gchar *original_basename,
+                   const gchar *suffix)
+{
+  g_autofree gchar *tool_name = g_strdup_printf ("%s%s", original_basename, suffix);
+  g_autofree gchar *tool_path = g_build_filename (base_path, tool_name, NULL);
+  if (!g_file_test (tool_path, G_FILE_TEST_EXISTS))
+    return NULL;
+
+  return g_steal_pointer (&tool_path);
+}
+
+gchar *
+_test_sdk_dirs (const gchar *basepath,
+                const gchar *dir)
+{
+  g_auto(GStrv) parts = NULL;
+  guint parts_length;
+
+  g_return_val_if_fail (basepath != NULL, NULL);
+  g_return_val_if_fail (dir != NULL, NULL);
+
+  parts = g_strsplit (dir, "-", -1);
+  parts_length = g_strv_length (parts);
+
+  if (parts_length <= 1)
+    return NULL;
+
+  for (guint i = 1; i < parts_length - 1; i++)
+    {
+      g_autofree gchar *head = NULL;
+      g_autofree gchar *tail = NULL;
+      g_autofree gchar *total = NULL;
+      g_autofree gchar *total_path = NULL;
+      gchar *part = parts[i];
+
+      parts[i] = NULL;
+      head = g_strjoinv ("-", parts);
+      tail = g_strjoinv ("-", parts + i + 1);
+      total = g_strdup_printf ("%s-%ssdk-%s", head, part, tail);
+      total_path = g_build_filename (basepath, "..", total, NULL);
+      parts[i] = part;
+
+      if (g_file_test (total_path, G_FILE_TEST_EXISTS))
+        return g_steal_pointer (&total_path);
+    }
+
+  return NULL;
+}
+
+/* Yocto systems are the most used ones, but the native toolchain is in a different folder */
+IdeToolchain *
+gbp_sysroot_toolchain_provider_try_poky (GbpSysrootToolchainProvider *self,
+                                         const gchar                 *sysroot_id)
+{
+  g_autoptr(IdeTriplet) system_triplet = NULL;
+  g_autoptr(IdeTriplet) sysroot_triplet = NULL;
+  g_autoptr(GRegex) arch_regex = NULL;
+  g_autoptr(GError) regex_error = NULL;
+  g_autofree gchar *sysroot_path = NULL;
+  g_autofree gchar *sysroot_basename = NULL;
+  g_autofree gchar *arch_escaped = NULL;
+  g_autofree gchar *sdk_dir = NULL;
+  g_autofree gchar *sysroot_arch = NULL;
+  g_autofree gchar *sdk_path = NULL;
+  GbpSysrootManager *sysroot_manager;
+
+  g_assert (GBP_IS_SYSROOT_TOOLCHAIN_PROVIDER (self));
+  g_assert (sysroot_id != NULL);
+
+  sysroot_manager = gbp_sysroot_manager_get_default ();
+  sysroot_path = gbp_sysroot_manager_get_target_path (sysroot_manager, sysroot_id);
+  sysroot_basename = g_path_get_basename (sysroot_path);
+
+  /* we need to change something like aarch64-poky-linux to x86_64-pokysdk-linux */
+  sysroot_arch = gbp_sysroot_manager_get_target_arch (sysroot_manager, sysroot_id);
+  system_triplet = ide_triplet_new_from_system ();
+  sysroot_triplet = ide_triplet_new (sysroot_arch);
+
+  arch_escaped = g_regex_escape_string (ide_triplet_get_arch (sysroot_triplet), -1);
+  arch_regex = g_regex_new (arch_escaped, 0, 0, &regex_error);
+  if (regex_error != NULL)
+    return NULL;
+
+  sdk_dir = g_regex_replace_literal (arch_regex, sysroot_basename, -1, 0, ide_triplet_get_arch 
(system_triplet), 0, &regex_error);
+  if (regex_error != NULL)
+    return NULL;
+
+  sdk_path = _test_sdk_dirs (sysroot_path, sdk_dir);
+
+  if (sdk_path != NULL)
+    {
+      g_autoptr(IdeSimpleToolchain) toolchain = NULL;
+      g_autoptr(GFile) sdk_file = NULL;
+      g_autofree gchar *toolchain_id = NULL;
+      g_autofree gchar *sdk_canonical_path = NULL;
+      g_autofree gchar *sdk_tools_path = NULL;
+      g_autofree gchar *sdk_cc_path = NULL;
+      g_autofree gchar *sdk_cpp_path = NULL;
+      g_autofree gchar *sdk_cplusplus_path = NULL;
+      g_autofree gchar *sdk_ar_path = NULL;
+      g_autofree gchar *sdk_ld_path = NULL;
+      g_autofree gchar *sdk_strip_path = NULL;
+      g_autofree gchar *sdk_pkg_config_path = NULL;
+      g_autofree gchar *qemu_static_name = NULL;
+      g_autofree gchar *qemu_static_path = NULL;
+      IdeContext *context;
+
+      sdk_file = g_file_new_for_path (sdk_path);
+      sdk_canonical_path = g_file_get_path (sdk_file);
+      toolchain_id = g_strdup_printf ("sysroot:%s", sdk_canonical_path);
+      context = ide_object_get_context (IDE_OBJECT (self));
+      toolchain = ide_simple_toolchain_new (context, toolchain_id);
+      ide_toolchain_set_host_triplet (IDE_TOOLCHAIN (toolchain), sysroot_triplet);
+
+      sdk_tools_path = g_build_filename (sdk_canonical_path, "usr", "bin", sysroot_basename, NULL);
+      sdk_cc_path = _create_tool_path (sdk_tools_path, sysroot_basename, "-gcc");
+      sdk_cplusplus_path = _create_tool_path (sdk_tools_path, sysroot_basename, "-g++");
+      sdk_cpp_path = _create_tool_path (sdk_tools_path, sysroot_basename, "-cpp");
+      sdk_ar_path = _create_tool_path (sdk_tools_path, sysroot_basename, "-ar");
+      sdk_ld_path = _create_tool_path (sdk_tools_path, sysroot_basename, "-ld");
+      sdk_strip_path = _create_tool_path (sdk_tools_path, sysroot_basename, "-strip");
+      sdk_pkg_config_path = g_build_filename (sdk_canonical_path, "usr", "bin", "pkg-config", NULL);
+
+      if (sdk_cc_path != NULL)
+        ide_simple_toolchain_set_tool_for_language (toolchain, IDE_TOOLCHAIN_LANGUAGE_C, 
IDE_TOOLCHAIN_TOOL_CC, sdk_cc_path);
+
+      if (sdk_cplusplus_path != NULL)
+        ide_simple_toolchain_set_tool_for_language (toolchain, IDE_TOOLCHAIN_LANGUAGE_CPLUSPLUS, 
IDE_TOOLCHAIN_TOOL_CC, sdk_cplusplus_path);
+
+      if (sdk_ar_path != NULL)
+        ide_simple_toolchain_set_tool_for_language (toolchain, IDE_TOOLCHAIN_LANGUAGE_ANY, 
IDE_TOOLCHAIN_TOOL_AR, sdk_ar_path);
+
+      if (sdk_ld_path != NULL)
+        ide_simple_toolchain_set_tool_for_language (toolchain, IDE_TOOLCHAIN_LANGUAGE_ANY, 
IDE_TOOLCHAIN_TOOL_LD, sdk_ld_path);
+
+      if (sdk_strip_path != NULL)
+        ide_simple_toolchain_set_tool_for_language (toolchain, IDE_TOOLCHAIN_LANGUAGE_ANY, 
IDE_TOOLCHAIN_TOOL_STRIP, sdk_strip_path);
+
+      if (g_file_test (sdk_pkg_config_path, G_FILE_TEST_EXISTS))
+        ide_simple_toolchain_set_tool_for_language (toolchain, IDE_TOOLCHAIN_LANGUAGE_ANY, 
IDE_TOOLCHAIN_TOOL_PKG_CONFIG, sdk_pkg_config_path);
+
+      qemu_static_name = g_strdup_printf ("qemu-%s-static", ide_triplet_get_arch (sysroot_triplet));
+      qemu_static_path = g_find_program_in_path (qemu_static_name);
+      if (qemu_static_path != NULL)
+        ide_simple_toolchain_set_tool_for_language (toolchain, IDE_TOOLCHAIN_LANGUAGE_ANY, 
IDE_TOOLCHAIN_TOOL_EXEC, qemu_static_path);
+
+      return g_steal_pointer (&toolchain);
+    }
+
+  return NULL;
+}
+
+static void
+gbp_sysroot_toolchain_provider_load_worker (IdeTask      *task,
+                                            gpointer      source_object,
+                                            gpointer      task_data,
+                                            GCancellable *cancellable)
+{
+  GbpSysrootToolchainProvider *self = source_object;
+  g_autoptr(GPtrArray) toolchains = NULL;
+  g_auto(GStrv) sysroot_list = NULL;
+  GbpSysrootManager *sysroot_manager;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_TASK (task));
+  g_assert (GBP_IS_SYSROOT_TOOLCHAIN_PROVIDER (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  toolchains = g_ptr_array_new_with_free_func (g_object_unref);
+  sysroot_manager = gbp_sysroot_manager_get_default ();
+  sysroot_list = gbp_sysroot_manager_list (sysroot_manager);
+
+  for (guint i = 0; sysroot_list[i] != NULL; i++)
+    {
+      g_autoptr(IdeToolchain) toolchain = NULL;
+
+      toolchain = gbp_sysroot_toolchain_provider_try_poky (self, sysroot_list[i]);
+      if (toolchain != NULL)
+        g_ptr_array_add (toolchains, g_steal_pointer (&toolchain));
+    }
+
+  ide_task_return_pointer (task,
+                           g_steal_pointer (&toolchains),
+                           (GDestroyNotify)g_ptr_array_unref);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_sysroot_toolchain_provider_load_async (IdeToolchainProvider     *provider,
+                                           GCancellable             *cancellable,
+                                           GAsyncReadyCallback       callback,
+                                           gpointer                  user_data)
+{
+  GbpSysrootToolchainProvider *self = (GbpSysrootToolchainProvider *)provider;
+  g_autoptr(IdeTask) task = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_SYSROOT_TOOLCHAIN_PROVIDER (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = ide_task_new (self, cancellable, callback, user_data);
+  ide_task_set_priority (task, G_PRIORITY_LOW);
+  ide_task_set_source_tag (task, gbp_sysroot_toolchain_provider_load_async);
+  ide_task_run_in_thread (task, gbp_sysroot_toolchain_provider_load_worker);
+
+  IDE_EXIT;
+}
+
+static gboolean
+gbp_sysroot_toolchain_provider_load_finish (IdeToolchainProvider  *provider,
+                                            GAsyncResult          *result,
+                                            GError               **error)
+{
+  GbpSysrootToolchainProvider *self = (GbpSysrootToolchainProvider *)provider;
+  g_autoptr(GPtrArray) toolchains = NULL;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_SYSROOT_TOOLCHAIN_PROVIDER (self));
+  g_assert (IDE_IS_TASK (result));
+  g_assert (ide_task_is_valid (IDE_TASK (result), provider));
+
+  toolchains = ide_task_propagate_pointer (IDE_TASK (result), error);
+
+  if (toolchains == NULL)
+    return FALSE;
+
+  g_clear_pointer (&self->toolchains, g_ptr_array_unref);
+  self->toolchains = g_ptr_array_ref (toolchains);
+
+  for (guint i = 0; i < toolchains->len; i++)
+    {
+      IdeToolchain *toolchain = g_ptr_array_index (toolchains, i);
+
+      g_assert (IDE_IS_TOOLCHAIN (toolchain));
+
+      ide_toolchain_provider_emit_added (provider, toolchain);
+    }
+
+  return TRUE;
+}
+
+void
+gbp_sysroot_toolchain_provider_unload (IdeToolchainProvider  *provider,
+                                       IdeToolchainManager   *manager)
+{
+  GbpSysrootToolchainProvider *self = (GbpSysrootToolchainProvider *) provider;
+
+  g_assert (GBP_IS_SYSROOT_TOOLCHAIN_PROVIDER (self));
+  g_assert (IDE_IS_TOOLCHAIN_MANAGER (manager));
+
+  g_clear_pointer (&self->toolchains, g_ptr_array_unref);
+}
+
+static void
+toolchain_provider_iface_init (IdeToolchainProviderInterface *iface)
+{
+  iface->load_async = gbp_sysroot_toolchain_provider_load_async;
+  iface->load_finish = gbp_sysroot_toolchain_provider_load_finish;
+  iface->unload = gbp_sysroot_toolchain_provider_unload;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpSysrootToolchainProvider,
+                         gbp_sysroot_toolchain_provider,
+                         IDE_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_TOOLCHAIN_PROVIDER,
+                                                toolchain_provider_iface_init))
+
+static void
+gbp_sysroot_toolchain_provider_class_init (GbpSysrootToolchainProviderClass *klass)
+{
+}
+
+static void
+gbp_sysroot_toolchain_provider_init (GbpSysrootToolchainProvider *self)
+{
+  
+}
diff --git a/src/plugins/sysroot/gbp-sysroot-toolchain-provider.h 
b/src/plugins/sysroot/gbp-sysroot-toolchain-provider.h
new file mode 100644
index 000000000..72899c9ac
--- /dev/null
+++ b/src/plugins/sysroot/gbp-sysroot-toolchain-provider.h
@@ -0,0 +1,30 @@
+/* gbp-sysroot-toolchain-provider.h
+ *
+ * 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/>.
+ */
+
+#pragma once
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_SYSROOT_TOOLCHAIN_PROVIDER (gbp_sysroot_toolchain_provider_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpSysrootToolchainProvider, gbp_sysroot_toolchain_provider, GBP, 
SYSROOT_TOOLCHAIN_PROVIDER, IdeObject)
+
+G_END_DECLS
diff --git a/src/plugins/sysroot/meson.build b/src/plugins/sysroot/meson.build
index ffdea996f..01c2b4d72 100644
--- a/src/plugins/sysroot/meson.build
+++ b/src/plugins/sysroot/meson.build
@@ -19,7 +19,9 @@ sysroot_sources = [
   'gbp-sysroot-runtime-provider.c',
   'gbp-sysroot-runtime-provider.h',
   'gbp-sysroot-subprocess-launcher.c',
-  'gbp-sysroot-subprocess-launcher.h'
+  'gbp-sysroot-subprocess-launcher.h',
+  'gbp-sysroot-toolchain-provider.c',
+  'gbp-sysroot-toolchain-provider.h'
 ]
 
 gnome_builder_plugins_sources += files(sysroot_sources)
diff --git a/src/plugins/sysroot/sysroot-plugin.c b/src/plugins/sysroot/sysroot-plugin.c
index 404c6a451..b84f91669 100644
--- a/src/plugins/sysroot/sysroot-plugin.c
+++ b/src/plugins/sysroot/sysroot-plugin.c
@@ -21,10 +21,12 @@
 
 #include "gbp-sysroot-runtime-provider.h"
 #include "gbp-sysroot-preferences-addin.h"
+#include "gbp-sysroot-toolchain-provider.h"
 
 void
 gbp_sysroot_register_types (PeasObjectModule *module)
 {
   peas_object_module_register_extension_type (module, IDE_TYPE_RUNTIME_PROVIDER, 
GBP_TYPE_SYSROOT_RUNTIME_PROVIDER);
   peas_object_module_register_extension_type (module, IDE_TYPE_PREFERENCES_ADDIN, 
GBP_TYPE_SYSROOT_PREFERENCES_ADDIN);
+  peas_object_module_register_extension_type (module, IDE_TYPE_TOOLCHAIN_PROVIDER, 
GBP_TYPE_SYSROOT_TOOLCHAIN_PROVIDER);
 }


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