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

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
{
  ...
};

The extra typedef allows the struct to be used in a header without including its full definition, simply by predeclaring it, by repeating that typedef. This means that you don't have to include the C library's header in your C++ header, thus keeping it out of your public API. gmmproc assumes that this technique was used, so you will see compiler errors if that is not the case.

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
ou bien encore :
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é.