Die Programmiersprache Ruby

Blog| Forum| Wiki  

Eine C-Extension ist eine Ruby-Erweiterung, die in C geschrieben ist. Meist handelt es sich dabei um ein Gem, aber da dies nicht zwangsläufig erforderlich ist, hält Ruby den Ordner site_ruby bereit, in welchem nicht-Gem-gebundene C-Extensions verstaut werden.

Inhaltsverzeichnis

Einbinden

Das Einbinden einer C-Extension funktioniert genauso wie das Einbinden einer Ruby-Datei, per require. Jede C-Extension besitzt mindestens eine Datei mit der system-nativen Endung für Linkdateien, z.B. .o, .so, .dll oder .bundle. Diese Datei ist die eigentliche C-Extension. Wird sie eingebunden (und hat sie keine anderen Abhängigkeiten), kann mit der C-Extension genauso verfahren werden wie mit einer normalen Ruby-Erweiterung.

1
2
3
require "win32/api" #Dateiendung kann wie immer weggelassen werden

msgbox = Win32::API.new("MessageBox", 'LPPI', 'I', "user32")

Nicht Gem-gebundene C-Extensions können genauso eingebunden werden, da sich das Verzeichnis site_ruby bereits im Suchpfad $: befindet.

Erstellen einer C-Extension

Dies ist eine kleine Zusammenfassung, welche Schritte minimal nötig sind, um eine C-Extension für verschiedene Ruby-Versionen zu erstellen.

Vorbereitung

Dass zum Erstellen zumindest minimale C-Kenntnisse erforderlich sind, braucht wohl nicht weiter erwähnt zu werden. Die Ruby-Community verweist in diesem Punkt immer gern auf das Buch The C Programming Lanugage. Außerdem sollte man sich in Rubys C-API einarbeiten. Eine größtenteils ausreichende Einführung bietet die Datei README.ext aus dem Ruby-Sources-Archiv jeder Ruby-Version (downloadbar von ftp://ftp.ruby-lang.org/pub/ruby/ ); etwas ausführlicher ist die API-Dokumentation auf ruby-lang.org, die dem aktuellen Stand mit der Version 1.8.4 aber leider deutlich hinterher hinkt. Um den Prozess des Erstellens abzukürzen, werde ich die folgende C-Extension mit dem Namen »example.c« verwenden:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "ruby.h"

static VALUE Example;

//Methoden, die verwendet werden
VALUE method_hello_world(VALUE self);

//Ruby-Einstiegsmethode. Sie muss immer mit Init_ beginnen und auf den Namen der Extension enden. 
void Init_example(void)
{
  //Erstelle die Klasse Example als Subklasse von Object
  Example = rb_define_class("Example", rb_cObject);
  
  //F��ge Example die Instanzmethode hello_world hinzu
  rb_define_method(Example, "hello_world", method_hello_world, 0);
}

//Dokumentation der Klassen

/*
*Document-class: Example
*
*Diese Klasse ist eine Beispielklasse. 
*/

//Definition der Methoden

/*
*call-seq: 
*  hello_world ==> "Hello world!"
*
*Diese Methode gibt den String <tt>"Hello world!"</tt> 
*zur��ck. 
*/
VALUE method_hello_world(VALUE self) //self sollte explizit angegeben werden, auch wenn es nicht benutzt wird
{
  return rb_str_new2("Hello World!");
}

Außerdem muss für jede C-Extension eine Datei namens extconf.rb erstellt werden. Deren minimaler Inhalt sieht so aus:

1
2
3
4
5
require "mkmf"

extension_name = "example"
dir_config(extension_name)
create_makefile(extension_name)

In der extconf.rb lassen sich aber auch noch viel mehr Dinge festlegen; zum Beispiel könnte man überprüfen, ob das kompilierende System bestimmte Programmbibliotheken besitzt.

Linux

  1. $ ruby extconf.rb ==> Makefile
  2. $ make ==> example.o, example.so
  3. # make install ==> Dieser wird die Extension in das Verzeichnis site_ruby schreiben. Für Gems auslassen.

MinGW

Eingaben im MSYS-Prompt.

  1. ruby extconf.rb ==> Makefile
  2. make ==> example.o, example.so
  3. make install ==> Dieser wird die Extension in das Verzeichnis site_ruby schreiben. Für Gems auslassen.

Windows

Das ist etwas komplizierter. Zunächst muss das »Microsoft Windows Software Development Kid« installiert werden (kurz Windows SDK, kostenlos): http://www.microsoft.com/downloads/details.aspx?FamilyID=c17ba869-9671-4330-a63e-1fd44e0e2505&displaylang=en (Obwohl da Windows 7 draufsteht, sollte es auch für Vista und XP laufen). Vollständig wären das über 5GB, aber die Dokumentation kann man weglassen, wenn der Installer danach fragt (die gibt's auch online bei MSDN).
Das ist aber noch nicht alles. Weil die mswin32-Version von Ruby mithilfe einer MSVC-Version von anno dazumal kompiliert wird, hat der Windows-Maintainer in die Datei config.h von Ruby an den Anfang geschrieben:

1
2
3
 #if _MSC_VER != 1200
 #error MSC version unmatch
 #endif

Das verhindert natürlich jegliches Erstellen von C-Extensions mit modernen Compilern. Kommentiere dies einfach aus.
Die folgenden Eingaben erfolgen in der SDK-Konsole.

  1. ruby extconf.rb ==> Makefile
  2. nmake ==> example.so (Wer auch immer .so geschrieben hat, gemeint ist .dll...)
  3. mt.exe -manifest example.so.manifest -outputresource:example.so;2
  4. nmake install ==> Dieser wird die Extension in das Verzeichnis site_ruby schreiben. Für Gems auslassen.

Mac OS X

  1. $ ruby extconf.rb ==> Makefile
  2. $ make ==> example.o, example.bundle
  3. # make install ==> Dieser wird die Extension in das Verzeichnis site_ruby schreiben. Für Gems auslassen.

Ergebnis betrachten

1
2
3
4
5
6
7
8
9
10
ruby 1.9.1p243 (2009-07-16 revision 24175) [i686-linux]
Working directory: /home/marvin
irb(main):001:0> cd "Desktop/test"
=> "/home/marvin/Desktop/test"
irb(main):002:0> require "example"
=> true
irb(main):003:0> puts Example.new.hello_world
Hello World!
=> nil
irb(main):004:0>

Siehe auch