girtobac  0.4
Create FB Headers from GObject Introspection *.gir files
 All Classes Files Functions Variables Enumerations Enumerator Macros Pages
Tutorial

Classic vs. girtobac headers

There're small differences between the headers generated by girtobac and to the headers shipped with FreeBasic (effective up to version fbc-0.90). GI (in its *.gir files) only supports constant macros (a string or numerical constant behind the #define keyword). But the files don't contain any code-generating macros nor inline functions.

So the girtobac generated FB headers just contain macros for constants. In addition, some standard macros for the GObject-classes (for C-styled headers) are generated by girtobac.

The lack of code creating macros seems to be no big deal, since the GI-libraries are used without these macros in the above mentioned high-level programming languages for years. (In the translation process the missing macros are an advantage, since un-needed macros and pre-processors need no manual removing.) But sometimes it may be better to have some further macro support. In this cases it's possible to extend the girtobac header with a manual translated header-subset containing the missing macros.

girtobac currently generates headers in a classic (C-like) style. Additionally it's prepared to generate OOP wrappers for GI libraries as well. Most of the high-level languages are OOP languages and GI is used for translating the GObject C code into real classes. The *.gir files contain all informations to wrap a C library in real FB objects with CONSTRUCTORs , SUBs, FUNCTIONs, PROPERTYs, ... This can help to make FB code more readable and to better support memory management.

Unfortunatelly the inheritance support in FB is currently (fbc-0.90.1) limited (ie. FB cannot extend a type by several interfaces). And some other features are not well prepared for that style of library bindings (ie. EXPLICIT statement in ENUM blocks). So the development of the OOP features in girtobac is stopped ATM and we have to wait for advanced features in the FB compiler.

How to get started?

As an example the file example/GLib-2.0.gir is shipped with this package. You can make your first translation using this file and compare the output against the file Gir/GLib-2.0.bi.org to check the girtobac executable and get familar with how to call girtobac.

Follow these steps:

  1. Jump to folder Gir and call girtobac (prepending the path if necessary) to create a new header from the example file
    cd Gir
    girtobac ../example/GLib-2.0
    and you'll see output like
    loading ../example/GLib-2.0.gir
    loading GLib-2.0.GirToBac
    Translating ...
  2. Compare the newly created file Gio-2.0.bi against the original shipped in the archive by executing
    diff GLib-2.0.bi GLib-2.0.bi.org
    This should output only minor differences in the files header, like
    4c4
    < ' Auto-translated from file ../example/GLib-2.0.gir
    ---
    > ' Auto-translated from file /usr/share/gir-1.0/GLib-2.0.gir
    4999,5000d4998
    < DECLARE SUB g_resources_register(BYVAL AS GResource PTR)
    < DECLARE SUB g_resources_unregister(BYVAL AS GResource PTR)
    The first difference is a comment in the top region of the file, it has no effect. The second difference are two DECLARE lines in the left hand file, which are not present in the original file. Those functions are declared in the *.gir file twice, ie. the first one is declared as a method in the record GResource at line 57228 and also as a function at line 82917. By design, girtobac does neither find nor solve such conflicts. It's up to the user to validate the output by compiling with the FreeBASIC compiler and fix the error messages.
  3. Now the new header should be ready to use. Test this by creating a new file called test.bas and compile this file by executing
    echo '#INCLUDE ONCE "GLib-2.0.bi"' > test.bas
    fbc -e -w all test.bas
    Note
    The shipped configuration file GLib-2.0.GirToBac was used in the translation process. That's why just a small amount of manual action is necessary. When you start from scratch, you'll see much more error messages from the compiler and you've to create and fill the configuration file line by line to fix it.
  4. In order to use the girtobac created header[s] in your FB source, copy (or move) the folder Gir and its files in to your freebasic/include path. Then use
    #INCLUDE ONCE "Gir/GLib-2.0.bi"
    in your code.

How to get and translate *.gir files?

A set of GLib headers was created during the development of girtobac for testing purposes. First check if set contains your header. You can download at http://www.freebasic-portal.de/downloads/bibliotheken/gtk-3-header-dateien-fuer-freebasic-191.html. If your library isn't included or isn't up-to-date, you need do make your customized translation.

*.gir files get generated when a GI-library gets compiled. So you can either get them by downloading the source package of a library and compile it (and all its dependencies, using option –enable-introspection=yes). Thats's the laborious way to go on non-LINUX systems.

On LINUX systems the *.gir files are provided in the package management system. They're included in the *-dev packages (hopefully this will change in near future). Ie. Gtk-3.0.gir is in package libgtk-3-dev on Debian based systems. So you'll get the *.gir files by default, since you have to install this package in order to compile your source.

Create your header by following these steps:

  • Preparation
    1. Create your output folder (usually .../freebasic/include/Gir)
    2. Copy basis header Gir/_GirToBac-0.0.bi in your output folder (or install the header set mentioned above).
    3. Download and extract the *.gir file (ie. /usr/lib/girepository-1.0/Xyz-1.0.gir).
  • Translation
    1. Jump to your output folder and call girtobac for translation
      /PATH/TO/girtobac /usr/lib/girepository-1.0/Xyz-1.0
    2. Create a test file (ie. test.bas in any folder) containing the line
      #INCLUDE ONCE "Gir/Xyz-1.0.bi"
      and compile it
      fbc -wall test.bas
    3. In case of no compiler errors you're done (the linker may report that -lXyz-1.0 is missing because you didn't install the binaries yet).
    4. Otherwise see section How to fix Problems?. Create a control file (ie. Xyz-1.0.GirToBac) in the output folder and add entries. Recompile the test.bas code until fbc doesn't complain any error.

How to fix Problems?

Here's a brief summary of the most common problems when compiling the test code (test.bas) and how to fix them. A control file in your output folder (.../freebasic/include/Gir) is used to add some translation rules. It's named after the inputs base name with suffix GirToBac (ie. Xyz-1.0.GirToBac for a Xyz-1.0.gir file). The rules are specified in XML syntax (see section The control file (*.GirToBac)). Depending on the error messages thrown by the fbc when compiling the test file, different entries should be done:

  • Duplicated definition ... There's a naming conflict. This usually happens because C syntax is case-sensitve and FBs isn't. Or it happens when an FB keyword is used as a symbol name in C code. Here you should change the FB name to make it unique (usually by adding an underscore character, but also consider to use an ALIAS statement). Example:
    <name search='window' add='_' />
  • Expected identifier ... There's a conflict between the C type name and an FB keyword. Or a C type is used that wasn't priviously specified. Rename the type to make it unique or known. Example:
    <type search='int' replace='gint' />
  • Illegal specification ... The symbol named in the error message isn't specified before this position (code line). Its declaration needs to get move forward. Example:
    <first search='synbol_name' />
  • File not found, "Xyz-0.0.bi" The library depends on an other library which isn't translated jet. Download the Xyz-0.0.gir file and translate it first. Then continue with the original translation.

You may face further problems or error messages when compiling the test file. Sorry, it's not possible to cover all of them here. If you cannot handle an issue don't hasitate to ask for help at http://www.freebasic.net/forum in the Libraries subforum.

The control file (*.GirToBac)

Similar to the *.gir files a control file is XML formated and is named by the same base-name with suffix *.GirToBac. Each control file contains adaption rules for one *.gir file, so each *.gir file may have one *.GirToBac file (located in the output folder). Ie. when the girtobac tool gets called by

../src/girtobac ../example/Gio-2.0

it loads the file Gio-2.0.gir form directory ../example and file Gio-2.0.GirToBac (if present in the current folder). If the later isn't present, translation gets done without any rules. The generated output gets written to the file Gio-2.0.bi in the current folder (where girtobac is called from).

Adaption rules may get specified for

  • a mismatch between the library name and its internal namespace
  • naming conflicts in variable names (because C naming is case-sensitive and FB's isn't)
  • typing conflicts in type names (GI is work in process, some C types are untranslated in the *.gir files, currently)
  • reordering of declarations (the *.gir files contain the symbol declarations in alphabetical order. Since fbc is a single pass compiler it needs to re-order some of them in logical order.)
  • a symbol check to switch off a dummy header when the complete header is in use.
  • a missmatch between the library name and the name declared in the *.gir file.

Therefor the parser for the configuration file understands six XML-tags and – depending on the tag type – the attributes name, add and replace:

  • binary to override the name of the binary. This is useful if the .gir file doesn't contain the right library name. Example (cairo):
    <binary name='cairo' />
  • check to enclose the complete header source by
    #IFNDEF symbol
    ...
    #ENDIF
    This is useful for a dummy binding that contains just a few type declarations. To avoid interferences with the complete binding, the dummy source can get switched of. Example (cairo):
    <check name='CAIRO_H' />
  • pack to adapt the library namespace (attribute name contains the new name in camel case letters). Example (GLib):
    <pack name='G' />
    or (GooCanvas):
    <pack name='Goo' />
  • name to adapt a symbol name (search contains a single word, further attributes add or replace). Example:
    <name search='gtk_stock_add' add='_ ALIAS "gtk_stock_add"' />
    or
    <name search='GTK_RC_STYLE' replace='_GTK_RC_STYLE' />
  • type to adapt types (search contains any text, further attributes add or replace). Example:
    <type search='GIconv' add=' PTR' />
    or
    <type search='void' replace='ANY' />
    <type search='const char* const' replace='CONST gchar PTR CONST' />
  • first to prepend the symbol (search contains a single word, no attribute) declaration before the rest. Example:
    <first search='GtkWidget' />
    <first search='GtkWidgetClass' />

The text in the attribute search needs to be specified case-sensitive. It may contain more then one word in case of a type rule, but just one word for name and first rules. replace and add attributes are used as-is in the output. See *.GirToBac files in folder Gir for further examples.

girtobac reports duplicated tags while reading the control file. The first tag gets used in that case and all further get skipped. After translating the *.gir file, girtobac reports about nonexistent symbols (defined in a search attribute but not existing in the *.gir file). Removing the corresponding tags from the control file speads up the translation process.

The control files should be shipped together with the translated header files. On one hand side this helps the users to learn about the differences between C and FB source. On the other hand side the control file helps anyone who want to generate an up-date for the header, further on.

Have fun, share your results.