ruby-mine

exploring the mine

Ruby 1.9.1 C-Extensions für MinGW

von quintus am 26.05.2009 (15 Uhr)

Mit der neuen (gut, inzwischen nicht mehr komplett neuen) Ruby-Version 1.9.1 hat sich bekanntlich einiges geändert. Die vielleicht größte Veränderung ist, dass der Ruby-Mainstream nun von der mittels des Microsoft Visual C++-Compilers erstellten mswin32-Version auf die MinGW/MSYS-Schiene wechselt. Mit diesem Wechsel gehen einige Veränderungen einher, insbesondere was die Erweiterung von Ruby mitteils C betrifft. Ich habe mich in den letzten Wochen etwas damit herumgeschlagen und hoffe, dass das jemandem hilft. ;-)

Zuerst ein wenig Vorgeschichte. Ich habe vor ein paar Monaten eine Library geschrieben, die sich um das mehr oder minder bekannte Windows-Automationstool AutoIt, oder besser, um die DLL-Schnittstelle AutoItX3 wrapt. Diese Library ließ sich wunderbar für die mswin32-Version (genau genommen die vom One-Click-Installer) von Ruby 1.8.6 kompilieren, aber als Ruby 1.9.1 erschienen war, wollte ich es natürlich weiterverwenden. Der Code der C-Extension war (und ist) dabei durchaus Ruby 1.9.1-kompatibel. Die für mich wichtigen Dateien waren dabei: au3.c (Meine C-Extension), AutoItX3.dll, AutoIt3.h (kein "X") und AutoItX3.lib.
Leider gestaltete sich das etwas schwieriger als gedacht. Nach einigen Versuchen stellte sich heraus: Der GCC, den MinGW als C-Compiler benutzt, kann keine .lib-Dateien verarbeiten. Das Resultat waren massenweise Fehlermeldungen der Art "undefined reference to AU3_error", "undefined reference to AU3_AutoItSetOption@8"... Ich suchte (neudeutsch: googelte), ob bereits jemand ein ähnliches Problem hatte, aber die Ergebnisse waren erstaunlich düfrtig. Eins enthielt jedenfalls einen Link zu einem Tool namens reimp.exe, dass .lib-Dateien in das für den GCC verständliche .a-Format umwandeln könne. Selbstverständlich existierte die Seite hinter dem Link nicht mehr. Also bemühte ich erneut die Suche und stieß auf das von MinGW veröffentlichte Paket mingw-utils. Dieses enthielt dann auch das Tool. Wunderbar, dachte ich, ändere einfach deine Zeile

#pragma comment(lib, "AutoItX3.lib")
in
#pragma comment(lib, "libAutoItX3.a")
. Von wegen. Der GCC ignorierte die #pragma-Zeile erfolgreich und ich bekam wieder die ganze Reihe an "undefined reference"s. Wie sollte ich denn sonst die Datei einbinden? Ich sah mir die von Ruby generierte Makefile an und stieß in Zeile 105 auf einen Eintrag:
LOCAL_LIBS = 
. Dort ergänzte ich meine .a-Datei und entfernte die #pragma-Zeile aus meiner C-Extension. Nein, immer noch nicht. Was nun? Nach diversen Suchen im Internet, die mich nicht einen Deut weiterbrachten, startete ich mein Vorhaben noch einmal komplett neu. Der Ordentlichkeit halber löschte ich dabei die Datei AutoItX3.lib aus meinem Verzeichnis. Und siehe da: Plötzlich kompilierte der GCC ohne jegliches Maulen meine C-Extension.

In Kürze zusammengefasst, um noch eine Odysee dieser Art zu vermeiden, heißt das (Eingaben im MSYS-Prompt):
1. .lib-Dateien mit
reimp -c meine_lib.lib
in .a-Dateien umwandeln
2. Die .lib-Dateien entfernen
3. In die extconf.rb die Zeile
$LOCAL_LIBS += " meine_lib1.a meine_lib2.a..." 
hinzufügen (Dank an Cremno für den Hinweis, der das manuelle Editieren der Makefile erspart)
4.
ruby extconf.rb

5.
make

6.
make install

Fertig.


Kommentar schreiben

Name (notwendig)

Mail (wird nicht veröffentlicht)

Webseite


Kommentare

  1. WoNáDo schrieb am 26.05.2009 (18 Uhr)

    Klasse, dass Du das hier geschrieben hast. Pack mal auch einen Link ins Ruby-Wiki, weil dieses Problem bestimmt wieder einmal bei jemandem auftaucht - eventuell erst in Monaten.

  2. Quintus schrieb am 26.05.2009 (20 Uhr)

    "Pack mal auch einen Link ins Ruby-Wiki, weil dieses Problem bestimmt wieder einmal bei jemandem auftaucht - eventuell erst in Monaten." Mach ich. "Klasse, dass Du das hier geschrieben hast. " Ich hab mir gedacht, hier geht das nicht so schnell unter wie im Forum. ;-) Vale, Quintus