NAME

swipl - pwig wrapper generator for SWI-Prolog


SYNOPSIS

  $ pwig -swipl -c++ foo.i
  $ g++ -c foo_wrap.cxx
  $ g++ foo_wrap.o foo.o -o foo.so
  $ pl -g '[config, foo], foo_bar(hello(world))'


ABSTRACT

The swipl module generates SWI-Prolog wrappers for C/C++ code. C structs and C++ classes can be wrapped as Logtalk objects.


PRELIMINARIES

Running pwig + swipl

The pwig swipl module is invoked as:

  $ pwig -swipl foo.i

for C++ code the c++ option has to be used:

  $ pwig -swipl -c++ foo.i

and to activate Logtalk proxy generation use the -proxy option:

  $ pwig -swipl -c++ -proxy foo.i

What gets generated?

config_sample.pl
A prolog file defining search paths for the swipl runtime components installed under the pwig library tree.

Usually you copy this file as config.pl and edit it to suite your installation. Particularly, you have to change the Logtalk path to point to the place where you have unpacked it.

If you want to distribute the generated prolog module as an stand alone one (without pwig dependencies) you have to copy the runtime files from the pwig library and change the config.pl file accordingly.

Prolog file
A prolog file named as the module (from the %module pwig directive) is created. It is used to bootstrap the C/C++ module and load all the runtime components (also Logtalk when needed).

Logtalk classes
When in Logtalk mode, the .lgt files are generated under a directory with the module name (the one used on the %module pwig directive).

For every C++ class, two Logtalk classes are generated, a class object proxying the normal method calls and a metaclass one for the constructors and the C++ static methods.

C/C++ wrappers
A .c or .cxx file with the wrapper code is generated, you have to compile this file and link it with the rest of your object files to contruct the loadable .so module (or whatever dynamic modules are called on your system).

Look at the foo example Makefile to see some working rules for module building.

Compiling

Compile the generated .c or .cxx file as any other C/C++ file, i.e:

  $ g++ -c foo_wrap.cxx

Linking

You will have to use the linker adequate for the language used to write the extension, C or C++. If you use the C linker for a C++ written extension, C++ support libraries will not be included and later the prolog proccess will refuse to load the module with ``undefined symbol'' errors.

Remember also to add the linker objects for your own code and any required library. If you forget some library, the linker will succeed anyway but later the module will not load on the prolog proccess.

A sample linking session:

  $ g++ -Xlinker -shared foo.o foo_wrap.o -lbar -o foo.so

Importing the module from prolog

First, load the configuration file:

  [config].

then load the prolog module:

  [foo].

or in one step:

  [config, foo].

When using Logtalk, a lot of information about modules being compiled is generated. This output will get (optionally) suppresed on a future release when swipl becomes more stable!


BASIC C/C++ WRAPPING

Constants

constant support is still unimplemented

Functions

C/C++ wrapped functions appear on prolog as predicates with the same name.

Predicates wrapping a function with a non void type (returning a value) get an additional argument appended for the result:

C function...

  int strlen(char *str)

is wrapped as prolog predicate...

  strlen(Str, Result)

but...

  void foo(char *bar)

becomes...

  foo(Bar)

Result values are not assigned but unified, so the previously defined strlen predicate can be called as...

   strlen(hello, 5).

and will succeed (for most strlen implementations!)

Overloaded C++ functions as wrapped on prolog as a common predicate and the adequate C++ function will be called... most of the time!

SWI-Prolog doesn't provide any support for foreign objects so they have to be encoded as atoms, but them there is not infallible way to know if an atom is really an object reference or a normal atom.

A simple heuristic is used to differentiate:

  if it looks like a pwig object reference
       it is a pwig object reference!

or if you prefer it expressed this way...

  is_object_reference(Atom) :-
     looks_like_object_reference(Atom).

What this means is that unless you start using atoms like _p_foo_73879_ on your apps, function overloading it's going to work as expected.

Anyway, you can use the %rename directive to stop the overloading dispatching from happening at all (consult the SWIG documentation about overloading).

Structs and classes

Structs and classes are represented in prolog as atoms with the type and the pointer value encoded on it (read the SWIG documentation for the details).

C++ class methods are wrapped as prolog predicates with the class name as prefix and a first argument containing the object reference:

C method...

  int foo::hello(int a)

is wrapped as...

  foo_hello(Foo, A, Result)

Static class methods are wrapped as normal functions but with the class name prepended:

C method...

  static void foo::bye(int b)

is wrapped as...

  foo_bye(B)

Constructor and destructors are made available on prolog:

for...

  struct foo {
    int slot;
  };

on prolog...

  foo_new(Foo).

is used to allocate a new struct foo, and Foo will contain an encoded reference to it.

  foo_delete(Foo).

is used to destroy and deallocate the object.

For C++ classes, constructors are made available if they are public and the class is not abstract. Constructors accepting arguments return the created object as its *LAST* argument:

for...

  class bar {
  public:
    bar(int a, int b=5);
    char *data;
  };

predicates...

  bar_new(A, Bar)
  bar_new(A, B, Bar)
  bar_delete(Bar)

are created.

Accessor predicates are created for public data members, i.e:

  foo_slot_set(new_slot_value)
  foo_slot_get(Slot_value)
  bar_data_set(v)
  bar_data_get(V)


LOGTALK

Logtalk is used as an additional layer to wrap C++ classes (and C structs) as objects in prolog.

Creating objects

The new class method predicate is used to create new objects:

for C++ class...

  class foo {
  public:
    foo(int arg1=4);
    foo(char *hello);
    void say(char *str);
    int croak(char *str);
    static int get_number();
  };

objects are created on prolog as

  foo::new(Foo).
  foo::new(Foo, 4).
  foo::new(Foo, hello_me).

notice, that with Logtalk, the object reference is passed as the *FIRST* argument on the constructors.

A nonvar term can also be used as the first argument, then the object gets binded to this term:

  foo::new(my_foo),
  my_foo::say(bye).

Deleting objects

Objects are deleted with the delete predicate:

  my_foo::delete.

Invoking object methods

Methods are invoked as normal Logtalk methods. If the C++ method has a return value, an additional last predicate argument is used to return it:

  my_foo::say(hello).
  my_foo::croak('I am a frog!', Out).

Invoking static class methods

static class methods are exported to prolog as methods of the class object:

  foo::get_number(Result).

Notes

Objects have to be explicitely deallocated as in C++, there is not garbage collection for Logtalk objects.

Object creation and destruction on Logtalk is extremely inefficient. Trace from prolog the creation of a C++ wrapped object like...

  :- trace.
  [trace] :- foo::new(Foo).

... and see what I'm talking about!!!

The problem is that Logtalk is not optimized to work with dynamic objects but static ones.

I think that the solution is to replace Logtalk with another lighter OO layer... like plo ;-)

ideas and contributions are welcome!


EXCEPTIONS

Exception handling is still unimplemented.

Actually, when a predicate is called with the wrong types it just fails.


TIPS

To be written


SEE ALSO

pwig project home at http://pwig.sourceforge.net.

SWIG home at http://www.swig.org.

SWI-Prolog home at http://www.swi-prolog.org.

Logtalk home at http://www.logtalk.org.


AUTHOR

Salvador Fandiņo <sfandino@yahoo.com>


COPYRIGHT AND LICENSE

Copyright 2003, 2004 by Salvador Fandiņo

This module is free software; you can redistribute it and/or modify it under the same terms as pwig itself.