1 /* ide-runtime.c
2 *
3 * Copyright 2016-2019 Christian Hergert <chergert@redhat.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: GPL-3.0-or-later
19 */
20
21 #define G_LOG_DOMAIN "ide-runtime"
22
23 #include "config.h"
24
25 #include <dazzle.h>
26 #include <glib/gi18n.h>
27 #include <libide-threading.h>
28 #include <string.h>
29
30 #include "ide-build-target.h"
31 #include "ide-config.h"
32 #include "ide-config-manager.h"
33 #include "ide-runtime.h"
34 #include "ide-runner.h"
35 #include "ide-toolchain.h"
36 #include "ide-triplet.h"
37
38 typedef struct
39 {
40 gchar *id;
41 gchar *short_id;
42 gchar *category;
43 gchar *name;
44 gchar *display_name;
45 } IdeRuntimePrivate;
46
47 G_DEFINE_TYPE_WITH_PRIVATE (IdeRuntime, ide_runtime, IDE_TYPE_OBJECT)
48
49 enum {
50 PROP_0,
51 PROP_ID,
52 PROP_SHORT_ID,
53 PROP_CATEGORY,
54 PROP_DISPLAY_NAME,
55 PROP_NAME,
56 N_PROPS
57 };
58
59 static GParamSpec *properties [N_PROPS];
60
61 static IdeSubprocessLauncher *
ide_runtime_real_create_launcher(IdeRuntime * self,GError ** error)62 ide_runtime_real_create_launcher (IdeRuntime *self,
63 GError **error)
64 {
65 IdeSubprocessLauncher *ret;
66
67 IDE_ENTRY;
68
69 g_assert (IDE_IS_RUNTIME (self));
70
71 ret = ide_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE);
72
73 if (ret != NULL)
74 {
75 ide_subprocess_launcher_set_run_on_host (ret, TRUE);
76 ide_subprocess_launcher_set_clear_env (ret, FALSE);
77 }
78 else
79 {
80 g_set_error (error,
81 G_IO_ERROR,
82 G_IO_ERROR_FAILED,
83 "An unknown error ocurred");
84 }
85
86 IDE_RETURN (ret);
87 }
88
89 static gboolean
ide_runtime_real_contains_program_in_path(IdeRuntime * self,const gchar * program,GCancellable * cancellable)90 ide_runtime_real_contains_program_in_path (IdeRuntime *self,
91 const gchar *program,
92 GCancellable *cancellable)
93 {
94 g_assert (IDE_IS_RUNTIME (self));
95 g_assert (program != NULL);
96 g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
97
98 if (!ide_is_flatpak ())
99 {
100 g_autofree gchar *path = NULL;
101 path = g_find_program_in_path (program);
102 return path != NULL;
103 }
104 else
105 {
106 g_autoptr(IdeSubprocessLauncher) launcher = NULL;
107
108 /*
109 * If we are in flatpak, we have to execute a program on the host to
110 * determine if there is a program available, as we cannot resolve
111 * file paths from inside the mount namespace.
112 */
113
114 if (NULL != (launcher = ide_runtime_create_launcher (self, NULL)))
115 {
116 g_autoptr(IdeSubprocess) subprocess = NULL;
117
118 ide_subprocess_launcher_set_run_on_host (launcher, TRUE);
119 ide_subprocess_launcher_push_argv (launcher, "which");
120 ide_subprocess_launcher_push_argv (launcher, program);
121
122 if (NULL != (subprocess = ide_subprocess_launcher_spawn (launcher, cancellable, NULL)))
123 return ide_subprocess_wait_check (subprocess, NULL, NULL);
124 }
125
126 return FALSE;
127 }
128
129 g_assert_not_reached ();
130 }
131
132 gboolean
ide_runtime_contains_program_in_path(IdeRuntime * self,const gchar * program,GCancellable * cancellable)133 ide_runtime_contains_program_in_path (IdeRuntime *self,
134 const gchar *program,
135 GCancellable *cancellable)
136 {
137 g_return_val_if_fail (IDE_IS_RUNTIME (self), FALSE);
138 g_return_val_if_fail (program != NULL, FALSE);
139 g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
140
141 return IDE_RUNTIME_GET_CLASS (self)->contains_program_in_path (self, program, cancellable);
142 }
143
144 static void
ide_runtime_real_prepare_configuration(IdeRuntime * self,IdeConfig * config)145 ide_runtime_real_prepare_configuration (IdeRuntime *self,
146 IdeConfig *config)
147 {
148 IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
149
150 g_assert (IDE_IS_RUNTIME (self));
151 g_assert (IDE_IS_CONFIG (config));
152
153 if (!ide_config_get_prefix_set (config))
154 {
155 g_autofree gchar *install_path = NULL;
156 g_autofree gchar *project_id = NULL;
157 IdeContext *context;
158
159 context = ide_object_get_context (IDE_OBJECT (self));
160 project_id = ide_context_dup_project_id (context);
161
162 install_path = g_build_filename (g_get_user_cache_dir (),
163 "gnome-builder",
164 "install",
165 project_id,
166 priv->id,
167 NULL);
168
169 ide_config_set_prefix (config, install_path);
170 ide_config_set_prefix_set (config, FALSE);
171 }
172 }
173
174 static IdeRunner *
ide_runtime_real_create_runner(IdeRuntime * self,IdeBuildTarget * build_target)175 ide_runtime_real_create_runner (IdeRuntime *self,
176 IdeBuildTarget *build_target)
177 {
178 IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
179 IdeEnvironment *env;
180 g_autoptr(GFile) installdir = NULL;
181 g_auto(GStrv) argv = NULL;
182 g_autofree gchar *cwd = NULL;
183 IdeConfigManager *config_manager;
184 const gchar *prefix;
185 IdeContext *context;
186 IdeRunner *runner;
187 IdeConfig *config;
188
189 g_assert (IDE_IS_RUNTIME (self));
190 g_assert (!build_target || IDE_IS_BUILD_TARGET (build_target));
191
192 context = ide_object_get_context (IDE_OBJECT (self));
193 g_assert (IDE_IS_CONTEXT (context));
194
195 config_manager = ide_config_manager_from_context (context);
196 config = ide_config_manager_get_current (config_manager);
197 prefix = ide_config_get_prefix (config);
198
199 runner = ide_runner_new (context);
200 g_assert (IDE_IS_RUNNER (runner));
201
202 ide_object_append (IDE_OBJECT (self), IDE_OBJECT (runner));
203
204 env = ide_runner_get_environment (runner);
205
206 if (ide_str_equal0 (priv->id, "host"))
207 ide_runner_set_run_on_host (runner, TRUE);
208
209 if (build_target != NULL)
210 {
211 ide_runner_set_build_target (runner, build_target);
212
213 installdir = ide_build_target_get_install_directory (build_target);
214 argv = ide_build_target_get_argv (build_target);
215 cwd = ide_build_target_get_cwd (build_target);
216 }
217
218 /* Possibly translate relative paths for the binary */
219 if (argv && argv[0] && !g_path_is_absolute (argv[0]))
220 {
221 const gchar *slash = strchr (argv[0], '/');
222 g_autofree gchar *copy = g_strdup (slash ? (slash + 1) : argv[0]);
223
224 g_free (argv[0]);
225
226 if (installdir != NULL)
227 {
228 g_autoptr(GFile) dest = g_file_get_child (installdir, copy);
229 argv[0] = g_file_get_path (dest);
230 }
231 else
232 argv[0] = g_steal_pointer (©);
233 }
234
235 if (installdir != NULL)
236 {
237 g_autoptr(GFile) parentdir = NULL;
238 g_autofree gchar *schemadir = NULL;
239 g_autofree gchar *parentpath = NULL;
240
241 /* GSettings requires an env var for non-standard dirs */
242 if ((parentdir = g_file_get_parent (installdir)))
243 {
244 parentpath = g_file_get_path (parentdir);
245 schemadir = g_build_filename (parentpath, "share", "glib-2.0", "schemas", NULL);
246 ide_environment_setenv (env, "GSETTINGS_SCHEMA_DIR", schemadir);
247 }
248 }
249
250 if (prefix != NULL)
251 {
252 static const gchar *tries[] = { "lib64", "lib", "lib32", };
253 const gchar *old_path = ide_environment_getenv (env, "LD_LIBRARY_PATH");
254
255 for (guint i = 0; i < G_N_ELEMENTS (tries); i++)
256 {
257 g_autofree gchar *ld_library_path = g_build_filename (prefix, tries[i], NULL);
258
259 if (g_file_test (ld_library_path, G_FILE_TEST_IS_DIR))
260 {
261 if (old_path != NULL)
262 {
263 g_autofree gchar *freeme = g_steal_pointer (&ld_library_path);
264 ld_library_path = g_strdup_printf ("%s:%s", freeme, old_path);
265 }
266
267 ide_environment_setenv (env, "LD_LIBRARY_PATH", ld_library_path);
268 break;
269 }
270 }
271 }
272
273 if (argv != NULL)
274 ide_runner_push_args (runner, (const gchar * const *)argv);
275
276 if (cwd != NULL)
277 ide_runner_set_cwd (runner, cwd);
278
279 return runner;
280 }
281
282 static GFile *
ide_runtime_real_translate_file(IdeRuntime * self,GFile * file)283 ide_runtime_real_translate_file (IdeRuntime *self,
284 GFile *file)
285 {
286 g_autofree gchar *path = NULL;
287
288 g_assert (IDE_IS_RUNTIME (self));
289 g_assert (G_IS_FILE (file));
290
291 /* We only need to translate when running as flatpak */
292 if (!ide_is_flatpak ())
293 return NULL;
294
295 /* Only deal with native files */
296 if (!g_file_is_native (file) || NULL == (path = g_file_get_path (file)))
297 return NULL;
298
299 /* If this is /usr or /etc, then translate to /run/host/$dir,
300 * as that is where flatpak 0.10.1 and greater will mount them
301 * when --filesystem=host.
302 */
303 if (g_str_has_prefix (path, "/usr/") || g_str_has_prefix (path, "/etc/"))
304 return g_file_new_build_filename ("/run/host/", path, NULL);
305
306 return NULL;
307 }
308
309 static gchar *
ide_runtime_repr(IdeObject * object)310 ide_runtime_repr (IdeObject *object)
311 {
312 IdeRuntime *self = (IdeRuntime *)object;
313 IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
314
315 g_assert (IDE_IS_MAIN_THREAD ());
316 g_assert (IDE_IS_RUNTIME (self));
317
318 return g_strdup_printf ("%s id=\"%s\" display-name=\"%s\"",
319 G_OBJECT_TYPE_NAME (self),
320 priv->id ?: "",
321 priv->display_name ?: "");
322 }
323
324 static void
ide_runtime_finalize(GObject * object)325 ide_runtime_finalize (GObject *object)
326 {
327 IdeRuntime *self = (IdeRuntime *)object;
328 IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
329
330 g_clear_pointer (&priv->id, g_free);
331 g_clear_pointer (&priv->short_id, g_free);
332 g_clear_pointer (&priv->display_name, g_free);
333 g_clear_pointer (&priv->name, g_free);
334
335 G_OBJECT_CLASS (ide_runtime_parent_class)->finalize (object);
336 }
337
338 static void
ide_runtime_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)339 ide_runtime_get_property (GObject *object,
340 guint prop_id,
341 GValue *value,
342 GParamSpec *pspec)
343 {
344 IdeRuntime *self = IDE_RUNTIME (object);
345
346 switch (prop_id)
347 {
348 case PROP_ID:
349 g_value_set_string (value, ide_runtime_get_id (self));
350 break;
351
352 case PROP_SHORT_ID:
353 g_value_set_string (value, ide_runtime_get_short_id (self));
354 break;
355
356 case PROP_CATEGORY:
357 g_value_set_string (value, ide_runtime_get_category (self));
358 break;
359
360 case PROP_DISPLAY_NAME:
361 g_value_set_string (value, ide_runtime_get_display_name (self));
362 break;
363
364 case PROP_NAME:
365 g_value_set_string (value, ide_runtime_get_name (self));
366 break;
367
368 default:
369 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
370 }
371 }
372
373 static void
ide_runtime_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)374 ide_runtime_set_property (GObject *object,
375 guint prop_id,
376 const GValue *value,
377 GParamSpec *pspec)
378 {
379 IdeRuntime *self = IDE_RUNTIME (object);
380
381 switch (prop_id)
382 {
383 case PROP_ID:
384 ide_runtime_set_id (self, g_value_get_string (value));
385 break;
386
387 case PROP_SHORT_ID:
388 ide_runtime_set_short_id (self, g_value_get_string (value));
389 break;
390
391 case PROP_CATEGORY:
392 ide_runtime_set_category (self, g_value_get_string (value));
393 break;
394
395 case PROP_DISPLAY_NAME:
396 ide_runtime_set_display_name (self, g_value_get_string (value));
397 break;
398
399 case PROP_NAME:
400 ide_runtime_set_name (self, g_value_get_string (value));
401 break;
402
403 default:
404 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
405 }
406 }
407
408 static void
ide_runtime_class_init(IdeRuntimeClass * klass)409 ide_runtime_class_init (IdeRuntimeClass *klass)
410 {
411 GObjectClass *object_class = G_OBJECT_CLASS (klass);
412 IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
413
414 object_class->finalize = ide_runtime_finalize;
415 object_class->get_property = ide_runtime_get_property;
416 object_class->set_property = ide_runtime_set_property;
417
418 i_object_class->repr = ide_runtime_repr;
419
420 klass->create_launcher = ide_runtime_real_create_launcher;
421 klass->create_runner = ide_runtime_real_create_runner;
422 klass->contains_program_in_path = ide_runtime_real_contains_program_in_path;
423 klass->prepare_configuration = ide_runtime_real_prepare_configuration;
424 klass->translate_file = ide_runtime_real_translate_file;
425
426 properties [PROP_ID] =
427 g_param_spec_string ("id",
428 "Id",
429 "The runtime identifier",
430 NULL,
431 (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
432
433 properties [PROP_SHORT_ID] =
434 g_param_spec_string ("short-id",
435 "Short Id",
436 "The short runtime identifier",
437 NULL,
438 (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
439
440 properties [PROP_CATEGORY] =
441 g_param_spec_string ("category",
442 "Category",
443 "The runtime's category",
444 NULL,
445 (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
446
447 properties [PROP_DISPLAY_NAME] =
448 g_param_spec_string ("display-name",
449 "Display Name",
450 "Display Name",
451 NULL,
452 (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
453
454 properties [PROP_NAME] =
455 g_param_spec_string ("name",
456 "Name",
457 "Name",
458 NULL,
459 (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
460
461 g_object_class_install_properties (object_class, N_PROPS, properties);
462 }
463
464 static void
ide_runtime_init(IdeRuntime * self)465 ide_runtime_init (IdeRuntime *self)
466 {
467 }
468
469 const gchar *
ide_runtime_get_id(IdeRuntime * self)470 ide_runtime_get_id (IdeRuntime *self)
471 {
472 IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
473
474 g_return_val_if_fail (IDE_IS_RUNTIME (self), NULL);
475
476 return priv->id;
477 }
478
479 void
ide_runtime_set_id(IdeRuntime * self,const gchar * id)480 ide_runtime_set_id (IdeRuntime *self,
481 const gchar *id)
482 {
483 IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
484
485 g_return_if_fail (IDE_IS_RUNTIME (self));
486 g_return_if_fail (id != NULL);
487
488 if (!ide_str_equal0 (id, priv->id))
489 {
490 g_free (priv->id);
491 priv->id = g_strdup (id);
492 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ID]);
493 }
494 }
495
496 const gchar *
ide_runtime_get_short_id(IdeRuntime * self)497 ide_runtime_get_short_id (IdeRuntime *self)
498 {
499 IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
500
501 g_return_val_if_fail (IDE_IS_RUNTIME (self), NULL);
502
503 return priv->short_id ? priv->short_id : priv->id;
504 }
505
506 void
ide_runtime_set_short_id(IdeRuntime * self,const gchar * short_id)507 ide_runtime_set_short_id (IdeRuntime *self,
508 const gchar *short_id)
509 {
510 IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
511
512 g_return_if_fail (IDE_IS_RUNTIME (self));
513 g_return_if_fail (short_id != NULL);
514
515 if (!ide_str_equal0 (short_id, priv->short_id))
516 {
517 g_free (priv->short_id);
518 priv->short_id = g_strdup (short_id);
519 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SHORT_ID]);
520 }
521 }
522
523 const gchar *
ide_runtime_get_category(IdeRuntime * self)524 ide_runtime_get_category (IdeRuntime *self)
525 {
526 IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
527
528 g_return_val_if_fail (IDE_IS_RUNTIME (self), NULL);
529 g_return_val_if_fail (priv->category != NULL, "Host System");
530
531 return priv->category;
532 }
533
534 void
ide_runtime_set_category(IdeRuntime * self,const gchar * category)535 ide_runtime_set_category (IdeRuntime *self,
536 const gchar *category)
537 {
538 IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
539
540 g_return_if_fail (IDE_IS_RUNTIME (self));
541
542 if (category == NULL)
543 category = _("Host System");
544
545 if (!ide_str_equal0 (category, priv->category))
546 {
547 g_free (priv->category);
548 priv->category = g_strdup (category);
549 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CATEGORY]);
550 }
551 }
552
553 const gchar *
ide_runtime_get_name(IdeRuntime * self)554 ide_runtime_get_name (IdeRuntime *self)
555 {
556 IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
557
558 g_return_val_if_fail (IDE_IS_RUNTIME (self), NULL);
559
560 return priv->name ? priv->name : priv->display_name;
561 }
562
563 void
ide_runtime_set_name(IdeRuntime * self,const gchar * name)564 ide_runtime_set_name (IdeRuntime *self,
565 const gchar *name)
566 {
567 IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
568
569 g_return_if_fail (IDE_IS_RUNTIME (self));
570
571 if (g_strcmp0 (name, priv->name) != 0)
572 {
573 g_free (priv->name);
574 priv->name = g_strdup (name);
575 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_NAME]);
576 }
577 }
578
579 const gchar *
ide_runtime_get_display_name(IdeRuntime * self)580 ide_runtime_get_display_name (IdeRuntime *self)
581 {
582 IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
583 gchar *ret;
584
585 g_return_val_if_fail (IDE_IS_RUNTIME (self), NULL);
586
587 if (!(ret = priv->display_name))
588 {
589 if (!(ret = priv->name))
590 ret = priv->id;
591 }
592
593 return ret;
594 }
595
596 void
ide_runtime_set_display_name(IdeRuntime * self,const gchar * display_name)597 ide_runtime_set_display_name (IdeRuntime *self,
598 const gchar *display_name)
599 {
600 IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
601
602 g_return_if_fail (IDE_IS_RUNTIME (self));
603
604 if (g_strcmp0 (display_name, priv->display_name) != 0)
605 {
606 g_free (priv->display_name);
607 priv->display_name = g_strdup (display_name);
608 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DISPLAY_NAME]);
609 }
610 }
611
612 IdeRuntime *
ide_runtime_new(const gchar * id,const gchar * display_name)613 ide_runtime_new (const gchar *id,
614 const gchar *display_name)
615 {
616 g_return_val_if_fail (id != NULL, NULL);
617 g_return_val_if_fail (display_name != NULL, NULL);
618
619 return g_object_new (IDE_TYPE_RUNTIME,
620 "id", id,
621 "display-name", display_name,
622 NULL);
623 }
624
625 /**
626 * ide_runtime_create_launcher:
627 *
628 * Creates a launcher for the runtime.
629 *
630 * This can be used to execute a command within a runtime.
631 *
632 * It is important that this function can be run from a thread without
633 * side effects.
634 *
635 * Returns: (transfer full): An #IdeSubprocessLauncher or %NULL upon failure.
636 *
637 * Since: 3.32
638 */
639 IdeSubprocessLauncher *
ide_runtime_create_launcher(IdeRuntime * self,GError ** error)640 ide_runtime_create_launcher (IdeRuntime *self,
641 GError **error)
642 {
643 g_return_val_if_fail (IDE_IS_RUNTIME (self), NULL);
644
645 return IDE_RUNTIME_GET_CLASS (self)->create_launcher (self, error);
646 }
647
648 void
ide_runtime_prepare_configuration(IdeRuntime * self,IdeConfig * configuration)649 ide_runtime_prepare_configuration (IdeRuntime *self,
650 IdeConfig *configuration)
651 {
652 g_return_if_fail (IDE_IS_RUNTIME (self));
653 g_return_if_fail (IDE_IS_CONFIG (configuration));
654
655 IDE_RUNTIME_GET_CLASS (self)->prepare_configuration (self, configuration);
656 }
657
658 /**
659 * ide_runtime_create_runner:
660 * @self: An #IdeRuntime
661 * @build_target: (nullable): An #IdeBuildTarget or %NULL
662 *
663 * Creates a new runner that can be used to execute the build target within
664 * the runtime. This should be used to implement such features as "run target"
665 * or "run unit test" inside the target runtime.
666 *
667 * If @build_target is %NULL, the runtime should create a runner that allows
668 * the caller to specify the binary using the #IdeRunner API.
669 *
670 * Returns: (transfer full) (nullable): An #IdeRunner if successful, otherwise
671 * %NULL and @error is set.
672 *
673 * Since: 3.32
674 */
675 IdeRunner *
ide_runtime_create_runner(IdeRuntime * self,IdeBuildTarget * build_target)676 ide_runtime_create_runner (IdeRuntime *self,
677 IdeBuildTarget *build_target)
678 {
679 g_return_val_if_fail (IDE_IS_RUNTIME (self), NULL);
680 g_return_val_if_fail (!build_target || IDE_IS_BUILD_TARGET (build_target), NULL);
681
682 return IDE_RUNTIME_GET_CLASS (self)->create_runner (self, build_target);
683 }
684
685 GQuark
ide_runtime_error_quark(void)686 ide_runtime_error_quark (void)
687 {
688 static GQuark quark = 0;
689
690 if G_UNLIKELY (quark == 0)
691 quark = g_quark_from_static_string ("ide_runtime_error_quark");
692
693 return quark;
694 }
695
696 /**
697 * ide_runtime_translate_file:
698 * @self: An #IdeRuntime
699 * @file: a #GFile
700 *
701 * Translates the file from a path within the runtime to a path that can
702 * be accessed from the host system.
703 *
704 * Returns: (transfer full) (not nullable): a #GFile.
705 *
706 * Since: 3.32
707 */
708 GFile *
ide_runtime_translate_file(IdeRuntime * self,GFile * file)709 ide_runtime_translate_file (IdeRuntime *self,
710 GFile *file)
711 {
712 GFile *ret = NULL;
713
714 g_return_val_if_fail (IDE_IS_RUNTIME (self), NULL);
715 g_return_val_if_fail (G_IS_FILE (file), NULL);
716
717 if (IDE_RUNTIME_GET_CLASS (self)->translate_file)
718 ret = IDE_RUNTIME_GET_CLASS (self)->translate_file (self, file);
719
720 if (ret == NULL)
721 ret = g_object_ref (file);
722
723 return ret;
724 }
725
726 /**
727 * ide_runtime_get_system_include_dirs:
728 * @self: a #IdeRuntime
729 *
730 * Gets the system include dirs for the runtime. Usually, this is just
731 * "/usr/include", but more complex runtimes may include additional.
732 *
733 * Returns: (transfer full) (array zero-terminated=1): A newly allocated
734 * string containing the include dirs.
735 *
736 * Since: 3.32
737 */
738 gchar **
ide_runtime_get_system_include_dirs(IdeRuntime * self)739 ide_runtime_get_system_include_dirs (IdeRuntime *self)
740 {
741 static const gchar *basic[] = { "/usr/include", NULL };
742
743 g_return_val_if_fail (IDE_IS_RUNTIME (self), NULL);
744
745 if (IDE_RUNTIME_GET_CLASS (self)->get_system_include_dirs)
746 return IDE_RUNTIME_GET_CLASS (self)->get_system_include_dirs (self);
747
748 return g_strdupv ((gchar **)basic);
749 }
750
751 /**
752 * ide_runtime_get_triplet:
753 * @self: a #IdeRuntime
754 *
755 * Gets the architecture triplet of the runtime.
756 *
757 * This can be used to ensure we're compiling for the right architecture
758 * given the current device.
759 *
760 * Returns: (transfer full) (not nullable): the architecture triplet the runtime
761 * will build for.
762 *
763 * Since: 3.32
764 */
765 IdeTriplet *
ide_runtime_get_triplet(IdeRuntime * self)766 ide_runtime_get_triplet (IdeRuntime *self)
767 {
768 IdeTriplet *ret = NULL;
769
770 g_return_val_if_fail (IDE_IS_RUNTIME (self), NULL);
771
772 if (IDE_RUNTIME_GET_CLASS (self)->get_triplet)
773 ret = IDE_RUNTIME_GET_CLASS (self)->get_triplet (self);
774
775 if (ret == NULL)
776 ret = ide_triplet_new_from_system ();
777
778 return ret;
779 }
780
781 /**
782 * ide_runtime_get_arch:
783 * @self: a #IdeRuntime
784 *
785 * Gets the architecture of the runtime.
786 *
787 * This can be used to ensure we're compiling for the right architecture
788 * given the current device.
789 *
790 * This is strictly equivalent to calling #ide_triplet_get_arch on the result
791 * of #ide_runtime_get_triplet.
792 *
793 * Returns: (transfer full) (not nullable): the name of the architecture
794 * the runtime will build for.
795 *
796 * Since: 3.32
797 */
798 gchar *
ide_runtime_get_arch(IdeRuntime * self)799 ide_runtime_get_arch (IdeRuntime *self)
800 {
801 gchar *ret = NULL;
802 g_autoptr(IdeTriplet) triplet = NULL;
803
804 g_return_val_if_fail (IDE_IS_RUNTIME (self), NULL);
805
806 triplet = ide_runtime_get_triplet (self);
807 ret = g_strdup (ide_triplet_get_arch (triplet));
808
809 return ret;
810 }
811
812 /**
813 * ide_runtime_supports_toolchain:
814 * @self: a #IdeRuntime
815 * @toolchain: the #IdeToolchain to check
816 *
817 * Informs wether a toolchain is supported by this.
818 *
819 * Returns: %TRUE if the toolchain is supported
820 *
821 * Since: 3.32
822 */
823 gboolean
ide_runtime_supports_toolchain(IdeRuntime * self,IdeToolchain * toolchain)824 ide_runtime_supports_toolchain (IdeRuntime *self,
825 IdeToolchain *toolchain)
826 {
827 const gchar *toolchain_id;
828
829 g_return_val_if_fail (IDE_IS_RUNTIME (self), FALSE);
830 g_return_val_if_fail (IDE_IS_TOOLCHAIN (toolchain), FALSE);
831
832 toolchain_id = ide_toolchain_get_id (toolchain);
833 if (g_strcmp0 (toolchain_id, "default") == 0)
834 return TRUE;
835
836 if (IDE_RUNTIME_GET_CLASS (self)->supports_toolchain)
837 return IDE_RUNTIME_GET_CLASS (self)->supports_toolchain (self, toolchain);
838
839 return TRUE;
840 }
841