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

By convention, structs are declared in glib/GTK-style headers like so:

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.

This compiler error might look like this:

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
or this:
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

By convention, glib/GTK-style objects have *_new() functions, such as example_widget_new() that do nothing more than call g_object_new() and return the result. The input parameters are supplied to g_object_new() along with the names of the properties for which they are values. For instance,

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.

Another workaround is to add a *_construct() function that the C++ constructor can call after instantiating its own type. For instance,

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é.