CCheaders

Introduction

The CCheaders is a small perl-skript that transforms header-files that look like those from the GTK+ system. These are object-oriented declarations written in plain C. For any C header source the output of CCheaders works just like the original because the CCheaders will only add a few lines inside #ifdef __cplusplus. The additions are just some C++ inline-methods inside the structure declarations, and the use of the C++ inclusion/inheritance syntax for the base type of each of the structures (again #ifdef __cplusplus).

As a result, the enhenced (GTK+) headers are much more easier to use from C++. For the one thing, a C++ compiler does know now about the inheritance relations for the structures, so you can leave off the ubiquitous big-caps cast-macros - instead you will benefit from compile-time type-checking as is builtin each C++ compiler.

For the other thing, you can use the (GTK+) procedures as inlined methods along the defined objects. Your code will become much shorter - and in consequence more readable and maintainable. And you don't have to think about which base-type had been introducing the set_border_width method - you can just call the method of that object instance (or their class-scope static-declared counterpart that is also generated).

Unlike real C++ wrappers, like GTK--,, the object size will not increase by a single byte. No additional library needs to be linked in, so even the runtime footprint is the same. And if you don't have a C++ compiler at hand (huh?), you can start rewriting the C++ code in an incremental way because the methods are directly derived from their underlying C-language procedure names. Since the very same headers can be used with a C compiler you will end up at just changing the file extension and it will compile cleanly.

If you want to add another function you can always switch back to C++ mode, make a RAD implementation, and if you're done you can rewrite it back into plain C. Nothing could be easier. It does help me a lot in my GTK developments - and I don't need a real wrapper bloatware (for C++/GTK or even Perl/GTK).

Invokation

The CCheaders is nothing more than a simple perl skript that should (currently) be run in the directory of the GTK+ headers. It will then create a directory named ../gtk+ and put all the transformed headers in there. It will even change the inclusions from <gtk/*.h> to <gtk+/*.h>.

So what you want to do is

gtk-c-to-cc.pl -q *.h
where the "-q" options means quiet. There are some other (not yet documented) options, just look into the source and try for yourself. This is currently nothing more than a quick hack which serves me well in my GTK developments.

The script can probably be adapted to other C-language object-oriented library systems - apart from two points the script does not make any other assumption on the headers, well other than the naming scheme should be similar to that as used by GTK.

For now, it may give you a /usr/include/gtk+ sister directory for your /usr/include/gtk directory if being run inside of the latter.

Download

You can get the latest perl script from here, it is called pub/cc-headers-000417.tar.bz2 or pub/cc-headers-000417.tar.gz and you may find updates in the local pub directory.

Example

From GTK+ Tutorial Example 3 (shortened, no comments here)
int main(int argc, char *argv[] )
{
  GtkWidget *window;
  GtkWidget *button;
  GtkWidget *box1;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
  gtk_signal_connect (GTK_OBJECT (window), "delete_event",
                      GTK_SIGNAL_FUNC (delete_event), NULL);
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);

  box1 = gtk_hbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (window), box1);

  button = gtk_button_new_with_label ("Button 1");
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
                      GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
  gtk_box_pack_start (GTK_BOX(box1), button, TRUE, TRUE, 0);
  gtk_widget_show (button);

  button = gtk_button_new_with_label ("Button 2");
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
                      GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
  gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
  gtk_widget_show (button);

  gtk_widget_show (box1);
  gtk_widget_show (window);

  gtk_main ();
}

And the same section in C++ mode (using <gtk+/gtk.h>)
int main( int  argc,  char *argv[] )
{
  GtkWindow *window;
  GtkButton *button;
  GtkBox *box1;

  gtk_init (&argc, &argv);
  window = GtkWindow::_new (GTK_WINDOW_TOPLEVEL);
  window->set_title_ ("Hello Buttons!");
  window->connect_ ("delete_event", GTK_SIG delete_event, NULL);
  window->set_border_width_ (10);

  box1 = GtkHBox::_new (FALSE, 0);
  window->add_ (box1);

  button = GtkButton::_new_with_label ("Button 1");
  button->connect_ ("clicked", GTK_SIG callback, "button 1");
  box1->pack_start_ (button, TRUE, TRUE, 0)->show_ ();

  button = GtkButton::_new_with_label ("Button 2");
  button->connect_("clicked", GTK_SIG callback, "button 2");
  box1->pack_start_ (button, TRUE, TRUE, 0)->show_ ()

  box1->show_();
  window->show_();
  gtk_main ();

}

Discussion

Comments


(C) Mar'00-Apr'00 Guido Draheim CCheaders e-mail:guidod@gmx.de