820 lines
26 KiB
C
820 lines
26 KiB
C
/* ide-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 "ide-build-system"
|
|
|
|
#include "config.h"
|
|
|
|
#include <libide-code.h>
|
|
#include <libide-io.h>
|
|
#include <libide-projects.h>
|
|
#include <libide-threading.h>
|
|
#include <libide-vcs.h>
|
|
#include <string.h>
|
|
|
|
#include "ide-gfile-private.h"
|
|
|
|
#include "ide-build-manager.h"
|
|
#include "ide-pipeline.h"
|
|
#include "ide-build-system.h"
|
|
#include "ide-config.h"
|
|
#include "ide-device.h"
|
|
#include "ide-foundry-compat.h"
|
|
#include "ide-toolchain.h"
|
|
|
|
G_DEFINE_INTERFACE (IdeBuildSystem, ide_build_system, IDE_TYPE_OBJECT)
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_PROJECT_FILE,
|
|
N_PROPS
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
GPtrArray *files;
|
|
GHashTable *flags;
|
|
guint index;
|
|
} GetBuildFlagsData;
|
|
|
|
static GParamSpec *properties [N_PROPS];
|
|
|
|
static void
|
|
get_build_flags_data_free (GetBuildFlagsData *data)
|
|
{
|
|
g_clear_pointer (&data->files, g_ptr_array_unref);
|
|
g_clear_pointer (&data->flags, g_hash_table_unref);
|
|
g_slice_free (GetBuildFlagsData, data);
|
|
}
|
|
|
|
gint
|
|
ide_build_system_get_priority (IdeBuildSystem *self)
|
|
{
|
|
IdeBuildSystemInterface *iface;
|
|
|
|
g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (self), 0);
|
|
|
|
iface = IDE_BUILD_SYSTEM_GET_IFACE (self);
|
|
|
|
if (iface->get_priority != NULL)
|
|
return iface->get_priority (self);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
ide_build_system_real_get_build_flags_async (IdeBuildSystem *self,
|
|
GFile *file,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
g_autoptr(IdeContext) context = NULL;
|
|
g_autoptr(IdeTask) task = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
g_auto(GStrv) parsed_flags = NULL;
|
|
IdeBuildManager *build_manager;
|
|
IdeEnvironment *env;
|
|
const gchar *flags = NULL;
|
|
const gchar *path;
|
|
IdePipeline *pipeline;
|
|
IdeConfig *config;
|
|
|
|
g_assert (IDE_IS_MAIN_THREAD ());
|
|
g_assert (IDE_IS_BUILD_SYSTEM (self));
|
|
g_assert (G_IS_FILE (file));
|
|
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
|
|
|
task = ide_task_new (self, cancellable, callback, user_data);
|
|
ide_task_set_source_tag (task, ide_build_system_real_get_build_flags_async);
|
|
|
|
/* Avoid work immediately if we can */
|
|
if (ide_task_return_error_if_cancelled (task))
|
|
return;
|
|
|
|
if (!g_file_is_native (file) || !(path = g_file_peek_path (file)))
|
|
{
|
|
ide_task_return_new_error (task,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_NOT_SUPPORTED,
|
|
"Cannot get build flags for non-native file");
|
|
return;
|
|
}
|
|
|
|
if (!(context = ide_object_ref_context (IDE_OBJECT (self))) ||
|
|
!ide_context_has_project (context) ||
|
|
!(build_manager = ide_build_manager_from_context (context)) ||
|
|
!(pipeline = ide_build_manager_get_pipeline (build_manager)) ||
|
|
!(config = ide_pipeline_get_config (pipeline)) ||
|
|
!(env = ide_config_get_environment (config)))
|
|
{
|
|
ide_task_return_new_error (task,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_NOT_INITIALIZED,
|
|
"Cannot access build flags without build config");
|
|
return;
|
|
}
|
|
|
|
if (ide_path_is_cpp_like (path))
|
|
{
|
|
flags = ide_environment_getenv (env, "CXXFLAGS");
|
|
}
|
|
else if (ide_path_is_c_like (path))
|
|
{
|
|
if (!(flags = ide_environment_getenv (env, "CFLAGS")))
|
|
flags = ide_environment_getenv (env, "CXXFLAGS");
|
|
}
|
|
else
|
|
{
|
|
ide_task_return_new_error (task,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_NOT_SUPPORTED,
|
|
"Cannot extract build flags for unknown file type: \"%s\"",
|
|
path);
|
|
return;
|
|
}
|
|
|
|
if (flags == NULL)
|
|
{
|
|
ide_task_return_new_error (task,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_NOT_SUPPORTED,
|
|
"No CFLAGS or CXXFLAGS environment variables were specified");
|
|
return;
|
|
}
|
|
|
|
if (!g_shell_parse_argv (flags, NULL, &parsed_flags, &error))
|
|
ide_task_return_error (task, g_steal_pointer (&error));
|
|
else
|
|
ide_task_return_pointer (task, g_steal_pointer (&parsed_flags), g_strfreev);
|
|
}
|
|
|
|
static gchar **
|
|
ide_build_system_real_get_build_flags_finish (IdeBuildSystem *self,
|
|
GAsyncResult *result,
|
|
GError **error)
|
|
{
|
|
return ide_task_propagate_pointer (IDE_TASK (result), error);
|
|
}
|
|
|
|
static void
|
|
ide_build_system_get_build_flags_cb (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
IdeBuildSystem *self = (IdeBuildSystem *)object;
|
|
g_autoptr(IdeTask) task = user_data;
|
|
g_autoptr(GError) error = NULL;
|
|
g_auto(GStrv) flags = NULL;
|
|
GetBuildFlagsData *data;
|
|
GFile *file;
|
|
|
|
g_assert (IDE_IS_BUILD_SYSTEM (self));
|
|
g_assert (G_IS_ASYNC_RESULT (result));
|
|
g_assert (IDE_IS_TASK (task));
|
|
|
|
data = ide_task_get_task_data (task);
|
|
g_assert (data != NULL);
|
|
g_assert (data->files != NULL);
|
|
g_assert (data->files->len > 0);
|
|
g_assert (data->index < data->files->len);
|
|
g_assert (data->flags != NULL);
|
|
|
|
file = g_ptr_array_index (data->files, data->index);
|
|
g_assert (G_IS_FILE (file));
|
|
|
|
data->index++;
|
|
|
|
flags = ide_build_system_get_build_flags_finish (self, result, &error);
|
|
|
|
if (error != NULL)
|
|
g_debug ("Failed to load build flags for \"%s\": %s",
|
|
g_file_peek_path (file),
|
|
error->message);
|
|
else
|
|
g_hash_table_insert (data->flags, g_object_ref (file), g_steal_pointer (&flags));
|
|
|
|
if (ide_task_return_error_if_cancelled (task))
|
|
return;
|
|
|
|
if (data->index < data->files->len)
|
|
{
|
|
GCancellable *cancellable = ide_task_get_cancellable (task);
|
|
|
|
file = g_ptr_array_index (data->files, data->index);
|
|
g_assert (G_IS_FILE (file));
|
|
|
|
ide_build_system_get_build_flags_async (self,
|
|
file,
|
|
cancellable,
|
|
ide_build_system_get_build_flags_cb,
|
|
g_steal_pointer (&task));
|
|
return;
|
|
}
|
|
|
|
ide_task_return_pointer (task,
|
|
g_steal_pointer (&data->flags),
|
|
g_hash_table_unref);
|
|
}
|
|
|
|
static GPtrArray *
|
|
copy_files (GPtrArray *in)
|
|
{
|
|
GPtrArray *out = g_ptr_array_new_full (in->len, g_object_unref);
|
|
for (guint i = 0; i < in->len; i++)
|
|
g_ptr_array_add (out, g_file_dup (g_ptr_array_index (in, i)));
|
|
return g_steal_pointer (&out);
|
|
}
|
|
|
|
static void
|
|
ide_build_system_real_get_build_flags_for_files_async (IdeBuildSystem *self,
|
|
GPtrArray *files,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
g_autoptr(IdeTask) task = NULL;
|
|
GetBuildFlagsData *data;
|
|
|
|
g_return_if_fail (IDE_IS_BUILD_SYSTEM (self));
|
|
g_return_if_fail (files != NULL);
|
|
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_build_system_real_get_build_flags_for_files_async);
|
|
ide_task_set_priority (task, G_PRIORITY_LOW);
|
|
|
|
if (files->len == 0)
|
|
{
|
|
ide_task_return_new_error (task,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_INVAL,
|
|
"No files were provided");
|
|
return;
|
|
}
|
|
|
|
g_assert (files->len > 0);
|
|
g_assert (G_IS_FILE (g_ptr_array_index (files, 0)));
|
|
|
|
if (ide_task_return_error_if_cancelled (task))
|
|
return;
|
|
|
|
data = g_slice_new0 (GetBuildFlagsData);
|
|
data->files = copy_files (files);
|
|
data->flags = g_hash_table_new_full ((GHashFunc)g_file_hash,
|
|
(GEqualFunc)g_file_equal,
|
|
g_object_unref,
|
|
(GDestroyNotify)g_strfreev);
|
|
ide_task_set_task_data (task, data, get_build_flags_data_free);
|
|
|
|
ide_build_system_get_build_flags_async (self,
|
|
g_ptr_array_index (files, 0),
|
|
cancellable,
|
|
ide_build_system_get_build_flags_cb,
|
|
g_steal_pointer (&task));
|
|
}
|
|
|
|
static GHashTable *
|
|
ide_build_system_real_get_build_flags_for_files_finish (IdeBuildSystem *self,
|
|
GAsyncResult *result,
|
|
GError **error)
|
|
{
|
|
return ide_task_propagate_pointer (IDE_TASK (result), error);
|
|
}
|
|
|
|
static void
|
|
ide_build_system_default_init (IdeBuildSystemInterface *iface)
|
|
{
|
|
iface->get_build_flags_async = ide_build_system_real_get_build_flags_async;
|
|
iface->get_build_flags_finish = ide_build_system_real_get_build_flags_finish;
|
|
iface->get_build_flags_for_files_async = ide_build_system_real_get_build_flags_for_files_async;
|
|
iface->get_build_flags_for_files_finish = ide_build_system_real_get_build_flags_for_files_finish;
|
|
|
|
properties [PROP_PROJECT_FILE] =
|
|
g_param_spec_object ("project-file",
|
|
"Project File",
|
|
"The project file.",
|
|
G_TYPE_FILE,
|
|
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_interface_install_property (iface, properties [PROP_PROJECT_FILE]);
|
|
}
|
|
|
|
static gchar *
|
|
ide_build_system_translate (IdeBuildSystem *self,
|
|
IdePipeline *pipeline,
|
|
const gchar *prefix,
|
|
const gchar *path)
|
|
{
|
|
g_autofree gchar *freeme = NULL;
|
|
g_autofree gchar *translated_path = NULL;
|
|
g_autoptr(GFile) file = NULL;
|
|
g_autoptr(GFile) translated = NULL;
|
|
IdeRuntime *runtime;
|
|
|
|
g_assert (IDE_IS_BUILD_SYSTEM (self));
|
|
g_assert (!pipeline || IDE_IS_PIPELINE (pipeline));
|
|
g_assert (prefix != NULL);
|
|
g_assert (path != NULL);
|
|
|
|
if (NULL == pipeline ||
|
|
NULL == (runtime = ide_pipeline_get_runtime (pipeline)))
|
|
return g_strdup_printf ("%s%s", prefix, path);
|
|
|
|
if (!g_path_is_absolute (path))
|
|
path = freeme = ide_pipeline_build_builddir_path (pipeline, path, NULL);
|
|
|
|
file = g_file_new_for_path (path);
|
|
translated = ide_runtime_translate_file (runtime, file);
|
|
translated_path = g_file_get_path (translated);
|
|
|
|
return g_strdup_printf ("%s%s", prefix, translated_path);
|
|
}
|
|
|
|
static void
|
|
ide_build_system_post_process_build_flags (IdeBuildSystem *self,
|
|
gchar **flags)
|
|
{
|
|
IdePipeline *pipeline;
|
|
IdeBuildManager *build_manager;
|
|
IdeContext *context;
|
|
|
|
g_assert (IDE_IS_BUILD_SYSTEM (self));
|
|
|
|
if (flags == NULL || flags[0] == NULL)
|
|
return;
|
|
|
|
context = ide_object_get_context (IDE_OBJECT (self));
|
|
build_manager = ide_build_manager_from_context (context);
|
|
pipeline = ide_build_manager_get_pipeline (build_manager);
|
|
|
|
for (guint i = 0; flags[i] != NULL; i++)
|
|
{
|
|
gchar *flag = flags[i];
|
|
gchar *translated;
|
|
|
|
if (flag[0] != '-')
|
|
continue;
|
|
|
|
switch (flag[1])
|
|
{
|
|
case 'I':
|
|
if (flag[2] == '\0')
|
|
{
|
|
if (flags[i+1] != NULL)
|
|
{
|
|
translated = ide_build_system_translate (self, pipeline, "", flags[++i]);
|
|
flags[i] = translated;
|
|
g_free (flag);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
translated = ide_build_system_translate (self, pipeline, "-I", &flag[2]);
|
|
flags[i] = translated;
|
|
g_free (flag);
|
|
}
|
|
break;
|
|
|
|
case 'D':
|
|
case 'x':
|
|
if (strlen (flag) == 2)
|
|
i++;
|
|
break;
|
|
|
|
case 'f': /* -fPIC */
|
|
case 'W': /* -Werror... */
|
|
case 'm': /* -m64 -mtune=native */
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ide_build_system_get_build_flags_async (IdeBuildSystem *self,
|
|
GFile *file,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
IDE_ENTRY;
|
|
|
|
g_return_if_fail (IDE_IS_BUILD_SYSTEM (self));
|
|
g_return_if_fail (G_IS_FILE (file));
|
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
|
|
|
IDE_BUILD_SYSTEM_GET_IFACE (self)->get_build_flags_async (self, file, cancellable, callback, user_data);
|
|
|
|
IDE_EXIT;
|
|
}
|
|
|
|
/**
|
|
* ide_build_system_get_build_flags_finish:
|
|
*
|
|
* Returns: (transfer full):
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
gchar **
|
|
ide_build_system_get_build_flags_finish (IdeBuildSystem *self,
|
|
GAsyncResult *result,
|
|
GError **error)
|
|
{
|
|
gchar **ret;
|
|
|
|
IDE_ENTRY;
|
|
|
|
g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (self), NULL);
|
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
|
|
|
|
ret = IDE_BUILD_SYSTEM_GET_IFACE (self)->get_build_flags_finish (self, result, error);
|
|
if (ret != NULL)
|
|
ide_build_system_post_process_build_flags (self, ret);
|
|
|
|
#ifdef IDE_ENABLE_TRACE
|
|
if (ret != NULL)
|
|
{
|
|
g_autoptr(GString) str = g_string_new (NULL);
|
|
for (guint i = 0; ret[i]; i++)
|
|
{
|
|
g_autofree char *escaped = g_shell_quote (ret[i]);
|
|
g_string_append (str, escaped);
|
|
g_string_append_c (str, ' ');
|
|
}
|
|
IDE_TRACE_MSG ("build_flags = %s", str->str);
|
|
}
|
|
#endif
|
|
|
|
IDE_RETURN (ret);
|
|
}
|
|
|
|
/**
|
|
* ide_build_system_get_build_flags_for_files_async:
|
|
* @self: An #IdeBuildSystem instance.
|
|
* @files: (element-type GFile) (transfer none): array of files whose build flags has to be retrieved.
|
|
* @cancellable: (allow-none): a #GCancellable to cancel getting build flags.
|
|
* @callback: function to be called after getting build flags.
|
|
* @user_data: data to pass to @callback.
|
|
*
|
|
* This function will get build flags for all files and returns
|
|
* map of file and its build flags as #GHashTable.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
void
|
|
ide_build_system_get_build_flags_for_files_async (IdeBuildSystem *self,
|
|
GPtrArray *files,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
IDE_ENTRY;
|
|
|
|
g_return_if_fail (IDE_IS_BUILD_SYSTEM (self));
|
|
g_return_if_fail ( files != NULL);
|
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
|
|
|
IDE_BUILD_SYSTEM_GET_IFACE (self)->get_build_flags_for_files_async (self, files, cancellable, callback, user_data);
|
|
|
|
IDE_EXIT;
|
|
}
|
|
|
|
/**
|
|
* ide_build_system_get_build_flags_for_files_finish:
|
|
* @self: an #IdeBuildSystem
|
|
* @result: a #GAsyncResult
|
|
* @error: a location for a #GError or %NULL
|
|
*
|
|
* Returns: (element-type Ide.File GStrv) (transfer full): a #GHashTable or #GFile to #GStrv
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
GHashTable *
|
|
ide_build_system_get_build_flags_for_files_finish (IdeBuildSystem *self,
|
|
GAsyncResult *result,
|
|
GError **error)
|
|
{
|
|
GHashTable *ret;
|
|
|
|
IDE_ENTRY;
|
|
|
|
g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (self), NULL);
|
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
|
|
|
|
ret = IDE_BUILD_SYSTEM_GET_IFACE (self)->get_build_flags_for_files_finish (self, result, error);
|
|
|
|
if (ret != NULL)
|
|
{
|
|
GHashTableIter iter;
|
|
gchar **flags;
|
|
|
|
g_hash_table_iter_init (&iter, ret);
|
|
|
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&flags))
|
|
ide_build_system_post_process_build_flags (self, flags);
|
|
}
|
|
|
|
IDE_RETURN (ret);
|
|
}
|
|
|
|
gchar *
|
|
ide_build_system_get_builddir (IdeBuildSystem *self,
|
|
IdePipeline *pipeline)
|
|
{
|
|
gchar *ret = NULL;
|
|
|
|
IDE_ENTRY;
|
|
|
|
g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (self), NULL);
|
|
g_return_val_if_fail (IDE_IS_PIPELINE (pipeline), NULL);
|
|
|
|
if (IDE_BUILD_SYSTEM_GET_IFACE (self)->get_builddir)
|
|
ret = IDE_BUILD_SYSTEM_GET_IFACE (self)->get_builddir (self, pipeline);
|
|
|
|
if (ret == NULL)
|
|
{
|
|
g_autofree gchar *name = NULL;
|
|
g_autofree gchar *branch = NULL;
|
|
g_autoptr(GFile) base = NULL;
|
|
g_autoptr(GFile) nosymlink = NULL;
|
|
IdeConfig *config;
|
|
const gchar *config_id;
|
|
const gchar *runtime_id;
|
|
const gchar *arch;
|
|
IdeRuntime *runtime;
|
|
IdeContext *context;
|
|
IdeVcs *vcs;
|
|
|
|
context = ide_object_get_context (IDE_OBJECT (self));
|
|
vcs = ide_vcs_from_context (context);
|
|
config = ide_pipeline_get_config (pipeline);
|
|
config_id = ide_config_get_id (config);
|
|
runtime = ide_pipeline_get_runtime (pipeline);
|
|
runtime_id = ide_runtime_get_short_id (runtime);
|
|
branch = ide_vcs_get_branch_name (vcs);
|
|
arch = ide_pipeline_get_arch (pipeline);
|
|
|
|
if (branch != NULL)
|
|
name = g_strdup_printf ("%s-%s-%s-%s", config_id, runtime_id, arch, branch);
|
|
else
|
|
name = g_strdup_printf ("%s-%s-%s", config_id, runtime_id, arch);
|
|
|
|
g_strdelimit (name, "@:/ ", '-');
|
|
|
|
/* Avoid symlink's when we can, so that paths with symlinks have at least
|
|
* a chance of working.
|
|
*/
|
|
base = ide_context_cache_file (context, "builds", name, NULL);
|
|
nosymlink = _ide_g_file_readlink (base);
|
|
|
|
ret = g_file_get_path (nosymlink);
|
|
}
|
|
|
|
IDE_RETURN (ret);
|
|
}
|
|
|
|
gchar *
|
|
ide_build_system_get_id (IdeBuildSystem *self)
|
|
{
|
|
g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (self), NULL);
|
|
|
|
if (IDE_BUILD_SYSTEM_GET_IFACE (self)->get_id)
|
|
return IDE_BUILD_SYSTEM_GET_IFACE (self)->get_id (self);
|
|
|
|
return g_strdup (G_OBJECT_TYPE_NAME (self));
|
|
}
|
|
|
|
gchar *
|
|
ide_build_system_get_display_name (IdeBuildSystem *self)
|
|
{
|
|
g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (self), NULL);
|
|
|
|
if (IDE_BUILD_SYSTEM_GET_IFACE (self)->get_display_name)
|
|
return IDE_BUILD_SYSTEM_GET_IFACE (self)->get_display_name (self);
|
|
|
|
return ide_build_system_get_id (self);
|
|
}
|
|
|
|
static void
|
|
ide_build_system_get_build_flags_for_dir_cb2 (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
IdeBuildSystem *build_system = (IdeBuildSystem *)object;
|
|
g_autoptr(IdeTask) task = user_data;
|
|
g_autoptr(GError) error = NULL;
|
|
g_autoptr(GHashTable) ret = NULL;
|
|
|
|
g_assert (IDE_IS_BUILD_SYSTEM (build_system));
|
|
g_assert (G_IS_ASYNC_RESULT (result));
|
|
g_assert (IDE_IS_TASK (task));
|
|
|
|
ret = ide_build_system_get_build_flags_for_files_finish (build_system, result, &error);
|
|
|
|
if (ret == NULL)
|
|
ide_task_return_error (task, g_steal_pointer (&error));
|
|
else
|
|
ide_task_return_pointer (task,
|
|
g_steal_pointer (&ret),
|
|
g_hash_table_unref);
|
|
}
|
|
|
|
static void
|
|
ide_build_system_get_build_flags_for_dir_cb (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
GFile *dir = (GFile *)object;
|
|
g_autoptr(IdeTask) task = user_data;
|
|
g_autoptr(GError) error = NULL;
|
|
g_autoptr(GPtrArray) infos = NULL;
|
|
g_autoptr(GPtrArray) files = NULL;
|
|
IdeBuildSystem *self;
|
|
GCancellable *cancellable;
|
|
IdeContext *context;
|
|
IdeVcs *vcs;
|
|
|
|
g_assert (G_IS_FILE (dir));
|
|
g_assert (G_IS_ASYNC_RESULT (result));
|
|
g_assert (IDE_IS_TASK (task));
|
|
|
|
infos = ide_g_file_get_children_finish (dir, result, &error);
|
|
IDE_PTR_ARRAY_SET_FREE_FUNC (infos, g_object_unref);
|
|
|
|
if (infos == NULL)
|
|
{
|
|
ide_task_return_error (task, g_steal_pointer (&error));
|
|
return;
|
|
}
|
|
|
|
self = ide_task_get_source_object (task);
|
|
context = ide_object_get_context (IDE_OBJECT (self));
|
|
vcs = ide_vcs_from_context (context);
|
|
cancellable = ide_task_get_cancellable (task);
|
|
files = g_ptr_array_new_with_free_func (g_object_unref);
|
|
|
|
for (guint i = 0; i < infos->len; i++)
|
|
{
|
|
GFileInfo *file_info = g_ptr_array_index (infos, i);
|
|
GFileType file_type = g_file_info_get_file_type (file_info);
|
|
|
|
if (file_type == G_FILE_TYPE_REGULAR)
|
|
{
|
|
const gchar *name = g_file_info_get_name (file_info);
|
|
g_autoptr(GFile) child = g_file_get_child (dir, name);
|
|
|
|
if (!ide_vcs_is_ignored (vcs, child, NULL))
|
|
g_ptr_array_add (files, g_steal_pointer (&child));
|
|
}
|
|
}
|
|
|
|
ide_build_system_get_build_flags_for_files_async (self,
|
|
files,
|
|
cancellable,
|
|
ide_build_system_get_build_flags_for_dir_cb2,
|
|
g_steal_pointer (&task));
|
|
}
|
|
|
|
void
|
|
ide_build_system_get_build_flags_for_dir_async (IdeBuildSystem *self,
|
|
GFile *directory,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
g_autoptr(IdeTask) task = NULL;
|
|
|
|
g_return_if_fail (IDE_IS_BUILD_SYSTEM (self));
|
|
g_return_if_fail (G_IS_FILE (directory));
|
|
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_build_system_get_build_flags_for_dir_async);
|
|
ide_task_set_priority (task, G_PRIORITY_LOW);
|
|
|
|
ide_g_file_get_children_async (directory,
|
|
G_FILE_ATTRIBUTE_STANDARD_NAME","
|
|
G_FILE_ATTRIBUTE_STANDARD_TYPE,
|
|
G_FILE_QUERY_INFO_NONE,
|
|
G_PRIORITY_LOW,
|
|
cancellable,
|
|
ide_build_system_get_build_flags_for_dir_cb,
|
|
g_steal_pointer (&task));
|
|
}
|
|
|
|
/**
|
|
* ide_build_system_get_build_flags_for_dir_finish:
|
|
* @self: an #IdeBuildSystem
|
|
* @result: a #GAsyncResult
|
|
* @error: a location for a #GError or %NULL
|
|
*
|
|
* Returns: (element-type Ide.File GStrv) (transfer full): a #GHashTable of #GFile to #GStrv
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
GHashTable *
|
|
ide_build_system_get_build_flags_for_dir_finish (IdeBuildSystem *self,
|
|
GAsyncResult *result,
|
|
GError **error)
|
|
{
|
|
g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (self), NULL);
|
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
|
|
|
|
return ide_task_propagate_pointer (IDE_TASK (result), error);
|
|
}
|
|
|
|
/**
|
|
* ide_build_system_supports_toolchain:
|
|
* @self: an #IdeBuildSystem
|
|
* @toolchain: a #IdeToolchain
|
|
*
|
|
* Checks whether the build system supports the given toolchain.
|
|
*
|
|
* Returns: %TRUE if the toolchain is supported by the build system, %FALSE otherwise
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
gboolean
|
|
ide_build_system_supports_toolchain (IdeBuildSystem *self,
|
|
IdeToolchain *toolchain)
|
|
{
|
|
const gchar *toolchain_id;
|
|
|
|
g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (self), FALSE);
|
|
g_return_val_if_fail (IDE_IS_TOOLCHAIN (toolchain), FALSE);
|
|
|
|
toolchain_id = ide_toolchain_get_id (toolchain);
|
|
if (g_strcmp0 (toolchain_id, "default") == 0)
|
|
return TRUE;
|
|
|
|
if (IDE_BUILD_SYSTEM_GET_IFACE (self)->supports_toolchain)
|
|
return IDE_BUILD_SYSTEM_GET_IFACE (self)->supports_toolchain (self, toolchain);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* ide_build_system_get_project_version:
|
|
* @self: a #IdeBuildSystem
|
|
*
|
|
* If the build system supports it, gets the project version as configured
|
|
* in the build system's configuration files.
|
|
*
|
|
* Returns: (transfer full) (nullable): a string containing the project version
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
gchar *
|
|
ide_build_system_get_project_version (IdeBuildSystem *self)
|
|
{
|
|
g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
|
|
g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (self), NULL);
|
|
|
|
if (IDE_BUILD_SYSTEM_GET_IFACE (self)->get_project_version)
|
|
return IDE_BUILD_SYSTEM_GET_IFACE (self)->get_project_version (self);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* ide_build_system_supports_language:
|
|
* @self: a #IdeBuildSystem
|
|
* @language: the language identifier
|
|
*
|
|
* Returns %TRUE if @self in it's current configuration is known to support @language.
|
|
*
|
|
* Returns: %TRUE if @language is supported, otherwise %FALSE.
|
|
*
|
|
* Since: 41.0
|
|
*/
|
|
gboolean
|
|
ide_build_system_supports_language (IdeBuildSystem *self,
|
|
const char *language)
|
|
{
|
|
g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (self), FALSE);
|
|
g_return_val_if_fail (language != NULL, FALSE);
|
|
|
|
if (IDE_BUILD_SYSTEM_GET_IFACE (self)->supports_language)
|
|
return IDE_BUILD_SYSTEM_GET_IFACE (self)->supports_language (self, language);
|
|
|
|
return FALSE;
|
|
}
|