Monday, May 12, 2008

Mono Bindings in 5 minutes

Last month at FISL 9 I met again with my good friend Henri Bergius, and he told me about Midgard news and showed me some changes on version 2 of Midgard Core. Midgard Core is a glib based library that could be used to persist glib objects on databases. Since it uses the GLib object model it is very easy to create binding for Mono, and that's what we did it at FISL days.

That was not the first time that I created Mono bindings for GLib libraries, I had done it before for Maemo libraries, and this weekend again for WebKit, but at this time I decide to create a project skeleton so everybody that is interested in creating Mono binding for Glib based libraries could use this skeleton for easy bindings creation.

The steps below describe how I easily created WebKit bindings without typing any lines of C# code.

First, download the skeleton file, unpack it and rename it to "webkit-sharp":


# wget http://anonsvn.mono-project.com/viewcvs/trunk/monoskel-gapi.tar.gz
# tar -xzf monoskel-gapi.tar.gz
# mv monoskel-gapi webkit-sharp

Now, go into this new directory and run the script that will perform the magic:

# cd webkit-sharp
# chmod +x autogen.sh skel-create.sh
# ./skel-create.sh webkit-sharp
# ./autogen.sh

We now have our source tree ready with autotools and makefiles. In the next step we must tell gapi where the C header files of the library that we want to make bindings for are. Open sources/webkit-sharp-sources.xml with your preferred text editor and type the following content:

<?xml version="1.0"?>
<gapi-parser-input>
<api filename="webkit-sharp-api.raw">
<library name="webkit-1.0">
<namespace name="WebKit">
<dir>/usr/include/webkit-1.0/webkit</dir>
</namespace>
</library>
</api>
</gapi-parser-input>

Here, the important information is "WebKit" that will be used as our namespace and "dir" that indicates the directory where our header (.h) files are.

And that is all, no changes needed anymore, you just need to run "make api" on the sources directory every time you change "webkit-sharp-sources.xml".

# cd sources
# make api

You can now follow the normal procedure to compile and install the linux package. On the package root directory, just type:

# ./configure
# make
# make install

If you are a developer, it should be easy to understand and create more samples in "samples" dir. There are also some "Package settings" that can be changed on top of "configure.in".

I did some other changes in my webkit-sharp like creation of webbrowser sample and checking for installed WebKit in configure.in. On my next post I will show webkit-sharp in action.

More information about GAPI could be found here.

8 comments:

Tehk said...

Great guide but i have a few questions. I am trying to generate some bindings but it seems to be taxing my system a bit.

For a decent size GTK C application how long would it take to make the API?

I ask this because my second core has been at 100% for about an hour now. Since it doesnt seem to output anything other then the initial "dir /path/to/included/libx" I am not sure if its some how stuck in some infinite loop, or frozen.


Does 'make api'

everaldo said...

Humm, normally it take only few seconds to finish, probably something in your C headers is not right handled by GAPI.

Could you give me your C header (.h)?

(everaldo.canuto@gmail.com)

Thanks

Tehk said...

Thanks for the time perspective. I solved that issue by removing headers one by one to find the offending one. Then I ran each sub component of gapi on the files and I found the offending code.

The only issue I have now is multiple 'cname doesn't follow the NamespaceType capitalization style:' outputs when generating the code, but I think I know what is going on there. I am going to dive into the api.raw xml tonight and solve that.

Other then that I really wish the code generation tool was a little more verbose(line numbers etc) so I could see where the offending code was.

everaldo said...

Dont forget to read the Customizations chapter in GAPI documentation, it will help to fix things without change generated xml:

http://www.mono-project.com/GAPI#Fixing_API_issues_and_Adding_Customizations

Maik said...

Hello Everaldo,

nice work, really. I've got the same problematic than Tehk described above using the webkit headers:


#define WEBKIT_MAJOR_VERSION (1)
#define WEBKIT_MINOR_VERSION (3)
#define WEBKIT_MICRO_VERSION (13)
#define WEBKIT_USER_AGENT_MAJOR_VERSION (534)
#define WEBKIT_USER_AGENT_MINOR_VERSION (26)
#define WEBKITGTK_API_VERSION (1.0)


The gapi_pp.pl runs now sine about 20 minutes:

20 0 6816 1844 1420 R 99.7 0.1 12:59.17 gapi_pp.pl

I just want to add DOM access to webkit-sharp. Is there any reason why it does not end using the 1.3.13 version which you already know about?

Sorry for opening that topic 3 years later, but I like that code generation solution very sexy.

Regards
Maik

Maik said...

Me again. I just want to paste the output which has been done:


$ make api
cp -rf /usr/include/webkit-1.0 .
PERLLIB=/share/perl5 \
PATH=/bin:$PATH \
/usr/bin/gapi2-parser webkit-sharp-sources.xml
<dir webkit-1.0/webkit>
unsigned long long webkit_application_cache_get_maximum_size();
G_CONST_RETURN gchar* webkit_application_cache_get_database_directory_path (void);
const gchar* webkit_download_get_uri (WebKitDownload *download);
const gchar* webkit_download_get_suggested_filename (WebKitDownload *download);
const gchar* webkit_download_get_destination_uri (WebKitDownload *download);
G_CONST_RETURN gchar* webkit_icon_database_get_path (WebKitIconDatabase* database);
G_CONST_RETURN gchar * webkit_network_request_get_uri (WebKitNetworkRequest *request);
G_CONST_RETURN gchar * webkit_network_response_get_uri (WebKitNetworkResponse *response);
G_CONST_RETURN gchar* webkit_security_origin_get_protocol (WebKitSecurityOrigin* securityOrigin);
G_CONST_RETURN gchar* webkit_security_origin_get_host (WebKitSecurityOrigin* securityOrigin);
GType
G_CONST_RETURN gchar* webkit_web_database_get_name (WebKitWebDatabase* webDatabase);
G_CONST_RETURN gchar* webkit_web_database_get_display_name (WebKitWebDatabase* webDatabase);
G_CONST_RETURN gchar* webkit_web_database_get_filename (WebKitWebDatabase* webDatabase);
G_CONST_RETURN gchar* webkit_get_web_database_directory_path (void);
G_CONST_RETURN gchar * webkit_web_data_source_get_encoding (WebKitWebDataSource *data_source);
G_CONST_RETURN gchar * webkit_web_data_source_get_unreachable_uri (WebKitWebDataSource *data_source);
G_CONST_RETURN gchar * webkit_web_frame_get_name (WebKitWebFrame *frame);
G_CONST_RETURN gchar * webkit_web_frame_get_title (WebKitWebFrame *frame);
G_CONST_RETURN gchar * webkit_web_frame_get_uri (WebKitWebFrame *frame);
G_CONST_RETURN gchar * webkit_web_history_item_get_title (WebKitWebHistoryItem *web_history_item);
G_CONST_RETURN gchar * webkit_web_history_item_get_alternate_title (WebKitWebHistoryItem *web_history_item);
G_CONST_RETURN gchar * webkit_web_history_item_get_uri (WebKitWebHistoryItem *web_history_item);
G_CONST_RETURN gchar * webkit_web_history_item_get_original_uri (WebKitWebHistoryItem *web_history_item);
const gchar* webkit_web_inspector_get_inspected_uri(WebKitWebInspector* web_inspector);
const gchar* webkit_web_navigation_action_get_original_uri(WebKitWebNavigationAction* navigationAction);
G_CONST_RETURN gchar * webkit_web_navigation_action_get_target_frame(WebKitWebNavigationAction* navigationAction);
const char* webkit_web_plugin_get_name (WebKitWebPlugin*);
const char* webkit_web_plugin_get_description (WebKitWebPlugin*);
G_CONST_RETURN gchar * webkit_web_resource_get_uri (WebKitWebResource *web_resource);
G_CONST_RETURN gchar * webkit_web_resource_get_mime_type (WebKitWebResource *web_resource);
G_CONST_RETURN gchar * webkit_web_resource_get_encoding (WebKitWebResource *web_resource);
G_CONST_RETURN gchar * webkit_web_resource_get_frame_name (WebKitWebResource *web_resource);
G_CONST_RETURN gchar * webkit_web_settings_get_user_agent (WebKitWebSettings *web_settings);
G_CONST_RETURN gchar * webkit_web_view_get_title (WebKitWebView *webView);
G_CONST_RETURN gchar * webkit_web_view_get_uri (WebKitWebView *webView);



There is something I don't understand: Why is the perlib directory pointing to /share instead of /usr/share? Is this only a false-positive?

Maik said...

Solved it by myself: The problem is the GC of Mono. If MONO_ENV_OPTIONS="--gc=sgen" is set code generation runs very fast. BTW there is a forked version of webkit-sharp by gburt which adds some new events and a forked version by myself which solves two compilation problems on newer mono version (2.10.1) and x86_64 arch.

Thanks anyways.

Maik

Asava Samuel said...

Maik

Here is another database that is compatible with Mono:
http://www.kellermansoftware.com/p-43-ninja-net-database-pro.aspx