Importing Island Libraries

Note: until library import for Island (ands Cocoa) is integrated in FXGen within Fire and Water, you can use HeaderImporter manually from the command line to import libraries.

HeaderImporter, or HI for short, is a command line tool we use to import C header files and generate .fx files the Elements compiler understands. It is used for both the Cocoa and Island platforms.

This tutorial will show you how to import a new set of .h header files, based on the example of GTK and its related dependencies (the generated .fx files for GTK actually ship included with Island, at least for the Linux sub-platform).

The first step is to collect the headers and libraries for GTK. To keep things simple I installed the develop libraries on Ubuntu:

apt-get install libgtk-3-dev

This pulls in development packages for everything needed to import this and creates include files in /usr/include/1 and libraries in /usr/lib.

The next step is to find out which includes we actually need and where they are located. Fortunately GTK comes with a PKG-config configuration we can use to find out where the files are:

pkg-config gtk+-3.0 --cflags
pkg-config gtk+-3.0 --libs

The first command spells out the include file directories which we'll need later when importing, the second command the libraries required. HeaderImporter uses the library files to find out which symbol is located in which .so file. This way, when compiling, it emits info for the linker and allows you to build the executable locally without having all of GTK present (for example on Windows or Mac).

For our purposes this gives:

user@ubuntu:~$ pkg-config gtk+-3.0 --cflags
-pthread -I/usr/include/gtk-3.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/usr/include/gtk-3.0 -I/usr/include/gio-unix-2.0/ -I/usr/include/mirclient -I/usr/include/mircommon -I/usr/include/mircookie -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/pango-1.0 -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libpng12 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include

user@ubuntu:~$ pkg-config gtk+-3.0 --libs
-lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0

Importing can be done on Linux, or by copying the headers/libraries to a system that has Elements installed. In this tutorial we presume the files were copied, but the same thing works when running it locally. The libraries mentioned above (-l) are generally symbolic links to the real files. These need to be copied:

libatk-1.0.so.0.21809.1
libcairo-gobject.so.2.11400.6
libcairo.so.2.11400.6
libgdk-3.so.0.1800.9
libgdk_pixbuf-2.0.so.0.3200.2
libgio-2.0.so.0.4800.1
libglib-2.0.so.0
libgobject-2.0.so.0.4800.1
libgtk-3.so.0.1800.9
libpango-1.0.so.0.3800.1
libpangocairo-1.0.so.0.3800.1

Now we can start writing the import information file. This file is a simple Json file that tells HI which files to import into what .fx files.

{
  "TargetString": "x86_64-linux-gnu", 
  "Version": "3.18",
  "SDKVersionString": "3.18.9-1ubuntu3.1",
  "Imports": [
    {
      "Name": "gtk",
      "Files": ["gtk/gtk.h"],
      "IndirectFiles": ["gtk/*.h"]
    }
  ],
  "Platform": "Linux"
}

The TargetString is the triple that identifies the platform. For our Linux this has to match x86_64-linux-gnu. Elements currently knows the following three triples for Island:

  • x86_64-linux-gnu – Linux, 64-bit
  • x86_64-pc-windows-msvc – Windows, 64-bit
  • i686-pc-windows-msvc – Windows, 32-bit

The Version and SDKVersionString are used only for displaying purposes. Platform has to match Linux in this case (or Windows when importing for the Windows sub-platform). Finally, the Imports tag holds a collection of import information:

  • Name: Name of the generated .fx file (in this case, "gtk").
  • Files: Entry point(s) for the parser to start parsing. For GTK+ the only thing usually needed is #include "gtk/gtk.h" so that's all we need here. This isn't a Json array.
  • IndirectFiles: Files that should also be imported: The parser will read everything (and fail on missing files) but it will only place types and functions declared in Files or IndirectFiles into the .fx. This is a Json array.

The relative directory a file is in (in relation to the root) affects the namespace for the types, in this case gtk/ places the types in the gtk namespace. If the include files weren't in a special directory, the Prefix flag could be used to add a namespace, instead.

Now we can run HeaderImporter. Since we copied the include files and libraries locally we pass the local include paths:

HeaderImporter.exe import 
  --json=ubuntu-gtk-x86_64.json 
  --libpath=c:\projects\hi\libs 
  -x "C:\Program Files (x86)\RemObjects Software\Elements\Island\Reference Libraries\Linux\x86_64" 
  -i C:\projects\hi\Linux\inc\pango-1.0 
  -i C:\projects\hi\Linux\inc\glib-2.0 
  -i C:\projects\hi\Linux\inc\atk-1.0 
  -i C:\projects\hi\Linux\inc\cairo 
  -i C:\projects\hi\Linux\inc\gtk-3.0 
  -i C:\projects\hi\Linux\inc\gdk-pixbuf-2.0 
  -o "C:\projects\hi\gtk"

Here, --json provides the path to the the json file we just created, --libpath the path to the .so files, -x the path to where the core Elements .fx files (such as rtl.fx) are located, and -i the include paths.

This example above would only generates a gtk.fx, which isn't exactly what we want in the case of GTK; we also need glib, atk, cairo, gdk and pango (GTK's dependencies), so we add those too. The final Json import file looks like:

{
  "TargetString": "x86_64-linux-gnu",
  "Version": "3.18",
  "SDKVersionString": "3.18.9-1ubuntu3.1",
  "Imports": [
    {
      "Name": "atk",
      "Files": ["atk/atk.h"],
      "IndirectFiles": ["atk/*.h"]
    },
    {
      "Name": "cairo",
      "Files": ["cairo.h"],
      "IndirectFiles": ["cairo-*.h"]
    },
    {
      "Name": "gdk",
      "Files": ["gdk/gdk.h","gdk-pixbuf/gdk-pixbuf.h"],
      "IndirectFiles": ["gdk/*.h","gdk-pixbuf/*.h"]
    },
    {
      "Name": "glib",
      "Files": ["gio/gio.h", "glib.h"],
      "IndirectFiles": ["gio/*.h", "gobject/*.h", "glib/*.h", "glibconfig.h"]
    },
    {
      "Name": "pango",
      "Files": ["pango/pango.h", "pango/pangocairo.h"],
      "IndirectFiles": ["pango/*.h"]
    },
    {
      "Name": "gtk",
      "Files": ["gtk/gtk.h"],
      "IndirectFiles": ["gtk/*.h"]
    }
  ],
  "Platform": "Linux"
}

While technically everything could be imported into a single .fx, it's useful to keep them split up so they can be used independently from each other. Rerunning HeaderImporter with this new Json generates 6 .fx files that are all that's needed to use GTK (on Linux).

The same concept can be used to import GTK for Windows (should you want to use it for creating cross-platform GUI), or to import any other library, for any supported Island sub-platform, that you have .h files for.