A small Introduction to the `gtkgen' Command -==========================================- (by Elmar Ludwig , last update: 2000-12-25) As you may have noticed (or maybe not), most of the source files of the GToolKit library are automatically generated from the GTK+ include files. The program that does this is called `gtkgen' and resides in the GToolKit directory in this archive. There is also small helper script (`mkclasses') that can be used to build class table input files for gtkgen. Both scripts have been written in Perl for maximum readability... ;-) Fine. But why should you bother? Well, there are several other useful add-on libraries available for GTK+ (like gtkhtml or gtk-extra) that may contain some classes you want to use in your own Objective-C programs. Of course, you can always work with the plain C interface of these libraries (since Objective-C is an extension of ANSI-C), but there is also another approach: You can take the scripts that are used to generate the GToolKit source code and apply them to other libraries. I will try to explain here in short the basic procedure necessary. Basically, the process of creating a set of Objective-C wrapper classes for a collection of GTK+ classes (I use this term here to refer to a class written in C using the GTK/GLIB object system) is a two step process: - Build a class table file containing some vital information about the classes that should be wrapped, plus all the classes that may appear (as parameter or return types) in these classes' header files. This information will then be used by gtkgen during the second step (see below). You can prevent any class from being wrapped just be omitting it from the class table file. - Create the actual Objective-C interface (`.h') and implementation (`.m') files from the corresponding C include files of the classes you need to wrap. It is also possible to add additional methods or instance variables to the created files during this step. You can see this process in action by looking at how the GToolKit source code is generated. First, I run `make genclean' to delete all generated files in the GToolKit source directory: $ make genclean rm -f GToolKit.h `sed 's/^[^;]*;\([^;]*\);.*/\1.h/' classes.in` rm -f GToolKit.m `sed 's/^[^;]*;\([^;]*\);.*/\1.m/' classes.in` rm -f -r ../html GTKMain.h GTKMain.m classes.in Although this has nothing to do with gtkgen, I use this to make sure that all files will be rebuilt. (Note that this will also delete the generated HTML documentation files in the html directory, which you cannot recreate at the moment, because the program which will do that is not included in this archive.) $ make gen ./mkclasses --add GtkAccelGroup --add GtkMenuFactory \ --exclude GtkType --path gtk \ /usr/local/include/gtk/*.h | sort >classes.in ./gtkgen --output GToolKit.m --package GToolKit --strict \ /usr/local/include/gtk/*.h skipping gtk.h... skipping gtkarg.h... skipping gtkbindings.h... skipping gtkcompat.h... skipping gtkdebug.h... skipping gtkdnd.h... skipping gtkenums.h... skipping gtkfeatures.h... skipping gtkgc.h... skipping gtkmarshal.h... skipping gtkprivate.h... skipping gtkrc.h... skipping gtkselection.h... skipping gtksignal.h... skipping gtkthemes.h... skipping gtktypebuiltins.h... skipping gtktypeutils.h... As you can see above, I use the `mkclasses' script to extract a list of all GTK+ classes from the complete set of GTK+ include files, which is then sorted and written to the file `classes.in' (though the list does not have to be sorted any more, early versions of gtkgen required this). You can perform a (very) limited degree of fine-tuning using the `--add' and `--exclude' options of mkclasses. `--add' will include an additional class in the class table, but it will have to *guess* the proper output from the class name (which is ok here), while `--exclude' will omit the given class from the class table. The option `--path' specifies the name (or path) of the C include directory of all file arguments relative to the standard include path of the C compiler. In this case, it is `gtk'. The output of the first command (mkclasses) typically looks like this: [...] GtkBin;GTKBin;bin;gtk_bin;GtkContainer;gtk/gtkbin.h GtkBox;GTKBox;box;gtk_box;GtkContainer;gtk/gtkbox.h GtkButton;GTKButton;button;gtk_button;GtkBin;gtk/gtkbutton.h GtkButtonBox;GTKButtonBox;buttonBox;gtk_button_box;GtkBox;gtk/gtkbbox.h [...] Each output line describes a list of properties for a single class (the info fields are separated by `;'), where the individual fields have the following meaning: - the GTK+ class name - the corresponding Objective-C class name - the method name prefix of the Objective-C allocator method (prefix of the class method that will return a new autoreleased instance of this class, this is typically named after the class name) - the common C function name prefix of all GTK+ functions in this class - the GTK+ class name of the super class (leave empty if there is none) - the name of the C include file of this class After that, gtkgen is called to scan the C include files for method names and create the Objective-C include and source code files. By default, it will create two files for each class: `classname.h' and `classname.m'. Alternatively, you can set a single output file (or `-' for stdout) for all class implementations (which can considerably speed up compilation times). In this case, only one file per class (`classname.h') is created, in addition to the given output file. If you want to add custom methods to the generated files, read the comments at the beginning of the gtkgen script (you need to supply a file `classname.in' for this). Optionally (with `--package'), gtkgen can also create a package include file for a collection of Objective-C classes (one file that includes all the others, similar to Foundation/Foundation.h or GToolKit/GToolKit.h). The last option, `--strict', is used to enable stricter source formatting rules for the C include files. Currently, the only real difference is the handling of the type `char *' in a function's argument list. In strict mode, gtkgen will assume that such a function will modify its argument (because there is no `const' in front of `char *'). That's it. Finally, we should look at a small practical example: Let's assume you wish to create an Objective-C wrapper class for the GtkHTML class from the gtkhtml library (which can be found on the GNOME FTP server). In this simple example, I just need to do the following: $ cd gtkhtml-0.5/src $ ls gtk* gtkhtml-embedded.c gtkhtml-properties.h gtkhtmldebug.c gtkhtml-embedded.h gtkhtml-stream.c gtkhtmldebug.h gtkhtml-keybinding.h gtkhtml-stream.h gtkhtmlfontstyle.c gtkhtml-private.h gtkhtml.c gtkhtmlfontstyle.h gtkhtml-properties.c gtkhtml.h $ mkclasses --path gtkhtml gtkhtml.h GtkHTML;GTKHTML;html;gtk_html;GtkLayout;gtkhtml/gtkhtml.h $ cp ~/Work/gtoolkit-0.9.4/GToolKit/classes.in . $ mkclasses --path gtkhtml gtkhtml.h >>classes.in Although I am only interested in the GtkHTML class here, it is important that the class input file (`classes.in') contains a complete list of *all* the classes that may appear in the header files you want to process. As including more classes does not really hurt, I would strongly recommend to always start with the `classes.in' file provided with the GToolKit library and then add the additional classes you want to wrap. Of course, you can also write these additional class table entries by hand if the output of mkclasses is not correct (which may happen if a class does not exactly follow the usual GTK+ naming conventions). Now, I can proceed by creating the actual Objective-C source code files for the GTKHTML class by invoking the `gtkgen' command: $ gtkgen gtkhtml.h skipping gtkhtml.h... That surely doesn't look right. What went wrong here? (gtkgen will warn you if it did not create a class for an input file.) Well, I told mkclasses (in step one above) that the name of the GtkHTML include file is `gtkhtml/gtkhtml.h'. This is true, but only *after* the library has been installed (which I did not want to do for this short demonstration). So I have to either: {install the gtkhtml library} $ gtkgen /usr/local/include/gtkhtml/gtkhtml.h or use a simple trick to fool gtkgen: $ ln -s . gtkhtml $ gtkgen gtkhtml/gtkhtml.h Now I have successfully created the wrapper class: $ ls -lt | head -6 total 1486 -rw-r--r-- 1 elmar users 3408 Dec 25 20:48 GTKHTML.m -rw-r--r-- 1 elmar users 2035 Dec 25 20:48 GTKHTML.h lrwxrwxrwx 1 elmar users 1 Dec 25 20:48 gtkhtml -> . -rw-r--r-- 1 elmar users 7089 Dec 25 20:43 classes.in drwxrwxr-x 2 elmar users 1024 Jul 11 01:29 tests A final note: In order to properly support file systems that do not use case sensitive filenames (like FAT or NTFS), you cannot use the same include directory name for the C and Objective-C versions of the same class (since the names `gtkhtml/gtkhtml.h' and `gtkhtml/GTKHTML.h' would refer to the same file). Therefore, the Objective-C include directory is distinguished by adding the suffix `_objc' at the end of the directory name, as you can see in the generated file GTKHTML.m: [...] #include #include @implementation GTKHTML [...]