Problèmes dans l'API C
Vous allez vraisemblablement rencontrer des problèmes dans la bibliothèque en cours d'habillage, en particulier s'il s'agit d'un nouveau projet. Voici quelques problèmes courants et leurs solutions.
- G.VI.I. Impossibilité de pré-déclarer des structures
- G.VI.II. Perte de propriétés
G.VI.I. Impossibilité de pré-déclarer des structures
Par convention, les structures sont déclarées comme suit dans les en-têtes de style glib/GTK+ :
typedef struct _ExampleWidget ExampleWidget; struct _ExampleWidget { ... };
Le typedef préliminaire permet l'utilisation de cette structure dans un en-tête sans inclure sa définition complète, simplement en la pré-déclarant, par répétition de la définition de type. Cela signifie que vous n'avez pas à inclure les en-têtes de la bibliothèque C dans la bibliothèque C++ ; vous la gardez ainsi hors de votre API publique. gmmproc suppose qu'on utilise cette technique ; vous verrez donc des messages d'erreurs si ce n'est pas le cas.
L'erreur de compilation ressemble à quelque chose comme :
example-widget.h:56: error: using typedef-name 'ExampleWidget' after 'struct' ../../libexample/libexamplemm/example-widget.h:34: error: 'ExampleWidget' has a previous declaration here make[4]: *** [example-widget.lo] Error 1
example-widget.h:60: error: '_ExampleWidget ExampleWidget' redeclared as different kind of symbol ../../libexample/libexamplemm/example-widget.h:34: error: previous declaration of 'typedef struct _ExampleWidget ExampleWidget'
C'est facile à corriger dans la bibliothèque C ; n'envoyez pas de correctif au mainteneur concerné.
G.VI.II. Perte de propriétés
Par convention, les objets de style glib/GTK+ possèdent des fonctions *_new(), comme par exemple example_widget_new(), qui ne font rien de plus qu'appeler g_object_new() et renvoyer le résultat. Les paramètres en entrée sont fournis à la fonction g_object_new() en même temps que les noms des propriétés dont elles sont les valeurs. Par exemple,
GtkWidget* example_widget_new(int something, const char* thing) { return g_object_new (EXAMPLE_TYPE_WIDGET, "something", something, "thing", thing, NULL); }
Cette façon de procéder permet des liaisons de langage pour implémenter leurs propres équivalents (comme les constructeurs C++) sans utiliser les fonctions *_new(). Ceci est souvent nécessaire ; elles peuvent donc instancier en réalité un GType dérivé pour ajouter leurs propres accroches pour les gestionnaires de signal et les fonctions virtuelles.
Pour le moins, la fonction _new() ne doit pas utiliser une quelconque API privée (fonctions uniquement dans un fichier .c). Même s'il n'y a pas de fonctions, nous pouvons ré-implémenter 2 ou 3 lignes de code dans une fonction _new() pour autant que ces lignes de code utilisent une API disponible pour nous.
Une autre manière de contourner ce problème consiste à ajouter une fonction *_construct() que le constructeur C++ peut appeler après avoir instancié son propre type. Par exemple,
GtkWidget* example_widget_new(int something, const char* thing) { ExampleWidget* widget; widget = g_object_new (EXAMPLE_TYPE_WIDGET, NULL); example_widget_construct(widget, "something", something, "thing", thing); } void example_widget_construct(ExampleWidget* widget, int something, const char* thing) { //faire quelque chose qui utilise l'API privée: widget->priv->thing = thing; do_something(something); }
Ajouter des propriétés en s'assurant qu'elles interagissent proprement entre elles est relativement difficile à corriger dans une bibliothèque C, mais c'est possible ; faites remonter un rapport d'anomalie avec si possible un correctif au mainteneur concerné.