1 /* ide-toolchain.c
2  *
3  * Copyright 2018 Collabora Ltd.
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  * Authors: Corentin Noël <corentin.noel@collabora.com>
19  *
20  * SPDX-License-Identifier: GPL-3.0-or-later
21  */
22 
23 #define G_LOG_DOMAIN "ide-toolchain"
24 
25 #include "config.h"
26 
27 #include "ide-toolchain.h"
28 #include "ide-triplet.h"
29 
30 typedef struct
31 {
32   gchar *id;
33   gchar *display_name;
34   IdeTriplet *host_triplet;
35 } IdeToolchainPrivate;
36 
37 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (IdeToolchain, ide_toolchain, IDE_TYPE_OBJECT)
38 
39 enum {
40   PROP_0,
41   PROP_ID,
42   PROP_DISPLAY_NAME,
43   PROP_HOST_TRIPLET,
44   N_PROPS
45 };
46 
47 static GParamSpec *properties [N_PROPS];
48 
49 /**
50  * ide_toolchain_get_id:
51  * @self: an #IdeToolchain
52  *
53  * Gets the internal identifier of the toolchain
54  *
55  * Returns: (transfer none): the unique identifier.
56  *
57  * Since: 3.32
58  */
59 const gchar *
ide_toolchain_get_id(IdeToolchain * self)60 ide_toolchain_get_id (IdeToolchain  *self)
61 {
62   IdeToolchainPrivate *priv = ide_toolchain_get_instance_private (self);
63 
64   g_return_val_if_fail (IDE_IS_TOOLCHAIN (self), NULL);
65 
66   return priv->id;
67 }
68 
69 
70 /**
71  * ide_toolchain_set_id:
72  * @self: an #IdeToolchain
73  * @id: the unique identifier
74  *
75  * Sets the internal identifier of the toolchain
76  *
77  * Since: 3.32
78  */
79 void
ide_toolchain_set_id(IdeToolchain * self,const gchar * id)80 ide_toolchain_set_id (IdeToolchain  *self,
81                       const gchar   *id)
82 {
83   IdeToolchainPrivate *priv = ide_toolchain_get_instance_private (self);
84 
85   g_return_if_fail (IDE_IS_TOOLCHAIN (self));
86   g_return_if_fail (id != NULL);
87 
88   if (g_strcmp0 (id, priv->id) != 0)
89     {
90       g_clear_pointer (&priv->id, g_free);
91       priv->id = g_strdup (id);
92       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ID]);
93     }
94 }
95 
96 const gchar *
ide_toolchain_get_display_name(IdeToolchain * self)97 ide_toolchain_get_display_name (IdeToolchain  *self)
98 {
99   IdeToolchainPrivate *priv = ide_toolchain_get_instance_private (self);
100 
101   g_return_val_if_fail (IDE_IS_TOOLCHAIN (self), NULL);
102 
103   return priv->display_name;
104 }
105 
106 void
ide_toolchain_set_display_name(IdeToolchain * self,const gchar * display_name)107 ide_toolchain_set_display_name (IdeToolchain  *self,
108                                 const gchar   *display_name)
109 {
110   IdeToolchainPrivate *priv = ide_toolchain_get_instance_private (self);
111 
112   g_return_if_fail (IDE_IS_TOOLCHAIN (self));
113   g_return_if_fail (display_name != NULL);
114 
115   if (g_strcmp0 (display_name, priv->display_name) != 0)
116     {
117       g_clear_pointer (&priv->display_name, g_free);
118       priv->display_name = g_strdup (display_name);
119       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DISPLAY_NAME]);
120     }
121 }
122 
123 /**
124  * ide_toolchain_set_host_triplet:
125  * @self: an #IdeToolchain
126  * @host_triplet: an #IdeTriplet representing the host architecture of the toolchain
127  *
128  * Sets the host system of the toolchain
129  *
130  * Since: 3.32
131  */
132 void
ide_toolchain_set_host_triplet(IdeToolchain * self,IdeTriplet * host_triplet)133 ide_toolchain_set_host_triplet (IdeToolchain *self,
134                                 IdeTriplet   *host_triplet)
135 {
136   IdeToolchainPrivate *priv = ide_toolchain_get_instance_private (self);
137 
138   g_return_if_fail (IDE_IS_TOOLCHAIN (self));
139 
140   if (host_triplet != priv->host_triplet)
141     {
142       g_clear_pointer (&priv->host_triplet, ide_triplet_unref);
143       priv->host_triplet = ide_triplet_ref (host_triplet);
144       g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HOST_TRIPLET]);
145     }
146 }
147 
148 /**
149  * ide_toolchain_get_host_triplet:
150  * @self: an #IdeToolchain
151  *
152  * Gets the combination of arch-kernel-system, sometimes referred to as
153  * the "host triplet".
154  *
155  * For Linux based devices, this will generally be something like
156  * "x86_64-linux-gnu".
157  *
158  * Returns: (transfer full): The host system.type of the toolchain
159  *
160  * Since: 3.32
161  */
162 IdeTriplet *
ide_toolchain_get_host_triplet(IdeToolchain * self)163 ide_toolchain_get_host_triplet (IdeToolchain *self)
164 {
165   IdeToolchainPrivate *priv = ide_toolchain_get_instance_private (self);
166 
167   g_return_val_if_fail (IDE_IS_TOOLCHAIN (self), NULL);
168 
169   return ide_triplet_ref (priv->host_triplet);
170 }
171 
172 static const gchar *
ide_toolchain_real_get_tool_for_language(IdeToolchain * self,const gchar * language,const gchar * tool_id)173 ide_toolchain_real_get_tool_for_language (IdeToolchain  *self,
174                                           const gchar   *language,
175                                           const gchar   *tool_id)
176 {
177   g_return_val_if_fail (IDE_IS_TOOLCHAIN (self), NULL);
178 
179   g_critical ("%s has not implemented get_tool_for_language()", G_OBJECT_TYPE_NAME (self));
180 
181   return NULL;
182 }
183 
184 static GHashTable *
ide_toolchain_real_get_tools_for_id(IdeToolchain * self,const gchar * tool_id)185 ide_toolchain_real_get_tools_for_id (IdeToolchain  *self,
186                                      const gchar   *tool_id)
187 {
188   g_return_val_if_fail (IDE_IS_TOOLCHAIN (self), NULL);
189 
190   g_critical ("%s has not implemented get_tools_for_id()", G_OBJECT_TYPE_NAME (self));
191 
192   return NULL;
193 }
194 
195 /**
196  * ide_toolchain_get_tool_for_language:
197  * @self: an #IdeToolchain
198  * @language: the language of the tool like %IDE_TOOLCHAIN_LANGUAGE_C.
199  * @tool_id: the identifier of the tool like %IDE_TOOLCHAIN_TOOL_CC
200  *
201  * Gets the path of the specified tool for the requested language.
202  * If %IDE_TOOLCHAIN_LANGUAGE_ANY is used in the @language field, the first tool matching @tool_id
203  * will be returned.
204  *
205  * Returns: (transfer none): A string containing the path of the tool for the given language, or
206  * %NULL is no tool has been found.
207  *
208  * Since: 3.32
209  */
210 const gchar *
ide_toolchain_get_tool_for_language(IdeToolchain * self,const gchar * language,const gchar * tool_id)211 ide_toolchain_get_tool_for_language (IdeToolchain *self,
212                                      const gchar  *language,
213                                      const gchar  *tool_id)
214 {
215   const gchar *ret;
216 
217   IDE_ENTRY;
218 
219   g_return_val_if_fail (IDE_IS_TOOLCHAIN (self), NULL);
220 
221   ret = IDE_TOOLCHAIN_GET_CLASS (self)->get_tool_for_language (self, language, tool_id);
222 
223   IDE_RETURN (ret);
224 }
225 
226 /**
227  * ide_toolchain_get_tools_for_id:
228  * @self: an #IdeToolchain
229  * @tool_id: the identifier of the tool like %IDE_TOOLCHAIN_TOOL_CC
230  *
231  * Gets the list of all the paths to the specified tool id.
232  *
233  * Returns: (transfer full) (element-type utf8 utf8): A table of language names and paths.
234  *
235  * Since: 3.32
236  */
237 GHashTable *
ide_toolchain_get_tools_for_id(IdeToolchain * self,const gchar * tool_id)238 ide_toolchain_get_tools_for_id (IdeToolchain  *self,
239                                 const gchar   *tool_id)
240 {
241   GHashTable *ret;
242 
243   IDE_ENTRY;
244 
245   g_return_val_if_fail (IDE_IS_TOOLCHAIN (self), NULL);
246 
247   ret = IDE_TOOLCHAIN_GET_CLASS (self)->get_tools_for_id (self, tool_id);
248 
249   IDE_RETURN (ret);
250 }
251 
252 static void
ide_toolchain_finalize(GObject * object)253 ide_toolchain_finalize (GObject *object)
254 {
255   IdeToolchain *self = (IdeToolchain *)object;
256   IdeToolchainPrivate *priv = ide_toolchain_get_instance_private (self);
257 
258   g_clear_pointer (&priv->id, g_free);
259   g_clear_pointer (&priv->display_name, g_free);
260   g_clear_pointer (&priv->host_triplet, ide_triplet_unref);
261 
262   G_OBJECT_CLASS (ide_toolchain_parent_class)->finalize (object);
263 }
264 
265 static void
ide_toolchain_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)266 ide_toolchain_get_property (GObject    *object,
267                             guint       prop_id,
268                             GValue     *value,
269                             GParamSpec *pspec)
270 {
271   IdeToolchain *self = IDE_TOOLCHAIN (object);
272 
273   switch (prop_id)
274     {
275     case PROP_ID:
276       g_value_set_string (value, ide_toolchain_get_id (self));
277       break;
278     case PROP_DISPLAY_NAME:
279       g_value_set_string (value, ide_toolchain_get_display_name (self));
280       break;
281     case PROP_HOST_TRIPLET:
282       g_value_set_boxed (value, ide_toolchain_get_host_triplet (self));
283       break;
284     default:
285       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
286     }
287 }
288 
289 static void
ide_toolchain_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)290 ide_toolchain_set_property (GObject      *object,
291                             guint         prop_id,
292                             const GValue *value,
293                             GParamSpec   *pspec)
294 {
295   IdeToolchain *self = IDE_TOOLCHAIN (object);
296 
297   switch (prop_id)
298     {
299     case PROP_ID:
300       ide_toolchain_set_id (self, g_value_get_string (value));
301       break;
302     case PROP_DISPLAY_NAME:
303       ide_toolchain_set_display_name (self, g_value_get_string (value));
304       break;
305     case PROP_HOST_TRIPLET:
306       ide_toolchain_set_host_triplet (self, g_value_get_boxed (value));
307       break;
308     default:
309       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
310     }
311 }
312 
313 static void
ide_toolchain_class_init(IdeToolchainClass * klass)314 ide_toolchain_class_init (IdeToolchainClass *klass)
315 {
316   GObjectClass *object_class = G_OBJECT_CLASS (klass);
317 
318   object_class->finalize = ide_toolchain_finalize;
319   object_class->get_property = ide_toolchain_get_property;
320   object_class->set_property = ide_toolchain_set_property;
321 
322   klass->get_tool_for_language = ide_toolchain_real_get_tool_for_language;
323   klass->get_tools_for_id = ide_toolchain_real_get_tools_for_id;
324 
325   properties [PROP_ID] =
326     g_param_spec_string ("id",
327                          "Id",
328                          "The toolchain identifier",
329                          NULL,
330                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
331 
332   properties [PROP_DISPLAY_NAME] =
333     g_param_spec_string ("display-name",
334                          "Display Name",
335                          "The displayable name of the toolchain",
336                          NULL,
337                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
338 
339   properties [PROP_HOST_TRIPLET] =
340     g_param_spec_boxed ("host-triplet",
341                          "Host Triplet",
342                          "The #IdeTriplet object containing the architecture of the machine on which the compiled binary will run",
343                          IDE_TYPE_TRIPLET,
344                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
345 
346   g_object_class_install_properties (object_class, N_PROPS, properties);
347 }
348 
349 static void
ide_toolchain_init(IdeToolchain * self)350 ide_toolchain_init (IdeToolchain *self)
351 {
352   IdeToolchainPrivate *priv = ide_toolchain_get_instance_private (self);
353   priv->host_triplet = ide_triplet_new_from_system ();
354 }
355