Murphy hat Euch in den letzten Wochen einen tiefen Einblick in die syntaktischen Finessen von Ruby geliefert. Ihr habt normale Strings und Fancy Strings kennengelernt. Es stellte sich heraus, dass Here Docs ebenfalls nur Strings mit einer zusätzlichen Dimension sind. Die funktionale Programmierung mit Symbol#to_proc macht Euch das Leben um einiges leichter. Und Fehlerbehandlung mit rescue ist nun zu einem selbstverständlichen Codefragment geworden, welches jeden unsicheren Code schmückt. Parallel hierzu möchten wir euch nun auf einer neuen Ebene einen Einblick in unseren Rubin verschaffen. Hierzu fahren wir die Schmelzanlage auf knapp 2050°C hoch und schauen uns an, was sich im inneren des Edelsteins befindet.
Was ist Ruby?
Subjektiv: eine interpretierte Programmiersprache
Objektiv: C Dateien mit ein paar Ruby Bibliotheken
Da wir Minenarbeiter u.a. sehr objektiv sind (vorsicht, diese Aussage war subjektiv), beschränken wir uns heute doch mal auf diese paar C-Dateien, welche im Verbund das Herzstück unserer Sprache ausmachen. Hierzu nun ein paar Fakten, die es dabei zu berücksichtigen gilt:
- Versionsverwaltung der Ruby-Sourcen läuft über CVS (Windows, Mac OS X, GNU/Linux).
- es handelt sich beim Quellcode größtenteils um C. Zum Anschauen ist ein Editor, der sowas highlighten kann, sehr empfehlenswert. Ich benutze hierfür Eclipse mit dem CDT, da es den geringsten Widerstand auf mich ausübt.
- Wenn Ihr den Code nicht nur anschauen, sondern auch kompilieren wollt, empfehle ich dringend eine Unixumgebung. Es werden hauptsächlich Unixtools für den Buildvorgang verwendet (z.B. gcc, make und bison). Ein Umweg über Borland- oder Visual-C++ ist zwar möglich, aber kein Kinderspiel. Für die bestmögliche Interaktion mit Eurem Rechner empfehle ich deshalb Mac OS X oder eine Linux Distribution eurer Wahl. Die ganz Harten unter Euch können Ihr Glück auch mit Cygwin auf die Probe stellen.
- Das Ruby-Mine.de-Team kann nicht für Unfälle haftbar gemacht werden, die sich bei der Benutzung des C-Compilers ereignen. Seit hiermit gewarnt, es kann bei der Benutzung desöfteren zu Tobsuchtsanfällen, Herzkreislaufbeschwerden und auch, in Folge von langsamen Turn Around-Zyklen, zu einem Herzinfakt aufgrund von Altersschwäche kommen.
Woher bekomme ich Ruby?
Ruby wird via CVS verwaltet. Folglich muss es einen Ruby-CVS-Server geben, der sämtlichen Sourcecode beinhaltet. Die Adresse zu diesem findet man auf der Ruby-Homepage.
- Servername: cvs.ruby-lang.org
- Repository-Pfad: /src
- Benutzername: anonymous
- Passwort:
Im Repository befinden sich derzeit 11 Module. Hierbei interessiert uns ganz speziell das Modul 'ruby'. Dieses beinhaltet nämlich den begehrten Sourcecode. Beim Auschecken dieser Sourcen werden wir bemerken, dass es eine Vielzahl von Branches und Tags gibt.
Branches (Auszug):
- new_gc (Testzweig für den generationalen Garbage Collector)
- ruby_1_8 (aktuelle Mainline)
- ruby_m17n (Testzweig für Internationalisierung)
Tags (Auszug):
- v1_8_4 (stabile Version 1.8.4)
- oniguruma_3_7_0_1 (letzte stabile Version von Oniguruma 3.7)
Der aktuelle Hauptbranch heißt ruby_1_8. Dieser interessiert uns jedoch nicht, da wir die gleichen Sourcen mit hoher Wahrscheinlichkeit schon besitzen (unser Standardinterpreter sollte nämlich eine Version aus diesem Branch sein). Unser Interesse richtet sich vielmehr auf den aktuellen HEAD des CVS-Moduls. Hier befindet sich nämlich der Entwicklerzweig mit der Versionsnummer 1.9.
Der innere Kern
Nach einem Checkout sehen wir u.a. folgende Verzeichnisse in unserer CVS Arbeitskopie:
- bcc32 (Buildunterstützung für den Borland C++ Compiler)
- bin (Rubytools wie irb und ri)
- cygwin (Buildunterstützung für den GNU-Emulator cygwin)
- djgpp (Buildunterstützung für DOS - kein Witz)
- doc (Dokumentation - unvollständig und veraltet)
- ext (Standardbibliothek: C-Extensions (z.B. zlib))
- lib (Standardbibliothek: in Ruby selbst (z.B. webrick))
- misc (Konfigurationsdateien für den Emacs)
- sample (Beispielcode für Ruby)
- test (Testcases für den Ruby-Interpreter)
- vms (Buildunterstützung für OpenVMS)
- win32 (Buildunterstützung für Visual C++)
- wince (Buildunterstützung für eMbedded Visual C++)
- x68 (Buildunterstützung für X68000)
Zusätzlich liegen dort noch viele einzelne Dateien herum, von denen uns im Moment nur die Datei ChangeLog interessiert. In dieser können wir in etwa sowas lesen:
Tue Apr 18 17:40:37 2006 Hidetoshi NAGAI
* ext/tk/lib/multi-tk.rb: add a binding to a
container for a slave IP.
* ext/tk/lib/tk.rb: update RELEASE_DATE.
* ext/tk/tcltklib.c: forget to reset a Tcl interpreter.
* ext/tk/stubs.c: fix potential bugs about handling rb_argv0.
Sat Apr 8 18:06:28 2006 Masaki Suketa
* ext/win32ole/win32ole.c: add WIN32OLE_METHOD#inspect,
WIN32OLE_PARAM#inspect.
* test/win32ole/test_win32ole_method.rb: ditto.
* add test/win32ole/test_win32ole_param.rb.
...
Als Laie würde ich sagen, die letzte Änderung fand am 18.04.2006 statt. Hierbei wurden ein paar TCLTK-Fehler gefixt. Also scheinbar passiert ja doch etwas bei den Ruby-Entwicklern.
Einen Rubin backen
Ein interessanter Befehl, mit dem wir starten wollen, ist autoconf. Dieser Befehl generiert uns eine erste configure-Datei, welche im CVS logischerweise nicht vorhanden ist. Auf dieser Basis könnten wir nun den allseits bekannten Dreisatz anwenden. Da ich euch persönlich nicht empfehlen würde, den Entwicklerinterpreter auf eurer Maschine zu installieren, werde ich das Target 'install' überspringen. Eine Installation ist selbstverständlich parallel zu einem anderen Interpreter möglich aber ich mülle meinen Rechner nicht gerne mit sowas voll. Weiter geht es also mit dem Befehl configure. Dieses Kommando akzeptiert alle möglichen Übergabeparameter wie z.B.:
- program-suffix=SUF (Suffix für Rubytools)
- enable-pthread (nutze die Posix Thread-Bibliothek)
- disable-install-doc (keine rdoc-Indizierung durchführen)
- with-sitedir=DIR (Pfad zur Site-Lib)
- enable-shared (soll von Programmen eingebunden werden)
- prefix=DIR (Installationspfad für bin und lib)
Unter Mac OS X ist es sinnvoll, den Schalter enable-pthread zu aktivieren, da es ansonsten zu Fehlern mit C-Extensions kommen kann, die standardmäßig mit dieser Option übersetzt wurden. Nach dem Durchlauf von configure finden wir ein Makefile in unserem Ordner. Jeder, der vergessen hat, einen Schalter beim Konfigurieren zu setzen hat nun die Möglichkeit, die entsprechenden Informationen direkt hier anzupassen. Interessant ist hierbei der C-Compiler (gcc ist Standard) und der Parser-Generator (bison ist Standard). Wer ein wenig spielen will, kann den Intel Compiler statt gcc oder yacc statt bison verwenden. Jedoch wird es hierbei zu Problemen kommen; wer also noch vollkommen unbelastet ist, kann mithilfe dieser Optionen die tollsten Fehlermeldungen produzieren. Lange Rede, kurzer Sinn: Ich starte den Buildvorgang jetzt einfach mal mit make.
Es werden die Kern-Elemente übersetzt und in die Datei libruby-static.a gepackt:
- ./array.c
- ./ascii.c
- ./bignum.c
- ./class.c
- ./compar.c
- ./dir.c
- ./dln.c
- ./enum.c
- ./enumerator.c
- ./error.c
- ./euc_jp.c
- ./eval.c
- ./file.c
- ./gc.c
- ./hash.c
- ./inits.c
- ./io.c
- ./marshal.c
- ./math.c
- ./numeric.c
- ./object.c
- ./pack.c
- ./parse.y (generiere ./parse.c mithilfe von bison)
- ./parse.c
- ./process.c
- ./prec.c
- ./random.c
- ./range.c
- ./re.c
- ./regcomp.c
- ./regenc.c
- ./regerror.c
- ./regexec.c
- ./regparse.c
- ./ruby.c
- ./signal.c
- ./sjis.c
- ./sprintf.c
- ./st.c
- ./string.c
- ./struct.c
- ./time.c
- ./utf8.c
- ./util.c
- ./variable.c
- ./version.c
- ./dmyext.c
Nun wird ein Mini-Ruby-Interpreter erstellt:
- ./main.c (Einsprungspunkt des Interpreters übersetzen)
- ./main.o und ./libruby-static.a binden => miniruby
C-Erweiterungen werden kompiliert:
- ./ext/bigdecimal/bigdecimal.c
- ./ext/curses/curses.c
- ./ext/dbm/dbm.c
- ./ext/digest/digest.c
- ./ext/digest/md5/md5init.c
- ./ext/digest/md5/md5ossl.c
- ./ext/digest/rmd160/rmd160init.c
- ./ext/digest/rmd160/rmd160ossl.c
- ./ext/digest/sha1/sha1init.c
- ./ext/digest/sha1/sha1ossl.c
- ./ext/digest/sha2/sha2.c
- ./ext/digest/sha2/sha2hl.c
- ./ext/digest/sha2/sha2init.c
- ./ext/dl/cfunc.c
- ./ext/dl/cptr.c
- ./ext/dl/dl.c
- ./ext/dl/handle.c
- ./ext/etc/etc.c
- ./ext/fcntl/fcntl.c
- ./ext/iconv/iconv.c
- ./ext/wait/wait.c
- ./ext/nkf/nkf.c
- ./ext/openssl/openssl_missing.c
- ./ext/openssl/ossl.c
- ./ext/openssl/ossl_asn1.c
- ./ext/openssl/ossl_bio.c
- ./ext/openssl/ossl_bn.c
- ./ext/openssl/ossl_cipher.c
- ./ext/openssl/ossl_config.c
- ./ext/openssl/ossl_digest.c
- ./ext/openssl/ossl_engine.c
- ./ext/openssl/ossl_hmac.c
- ./ext/openssl/ossl_ns_spki.c
- ./ext/openssl/ossl_ocsp.c
- ./ext/openssl/ossl_pkcs12.c
- ./ext/openssl/ossl_pkcs7.c
- ./ext/openssl/ossl_pkey.c
- ./ext/openssl/ossl_pkey_dh.c
- ./ext/openssl/ossl_pkey_dsa.c
- ./ext/openssl/ossl_pkey_rsa.c
- ./ext/openssl/ossl_rand.c
- ./ext/openssl/ossl_ssl.c
- ./ext/openssl/ossl_x509.c
- ./ext/openssl/ossl_x509attr.c
- ./ext/openssl/ossl_x509cert.c
- ./ext/openssl/ossl_x509crl.c
- ./ext/openssl/ossl_x509ext.c
- ./ext/openssl/ossl_x509name.c
- ./ext/openssl/ossl_x509req.c
- ./ext/openssl/ossl_x509revoked.c
- ./ext/openssl/ossl_x509store.c
- ./ext/pty/pty.c
- ./ext/racc/cparse/cparse.c
- ./ext/readline/readline.c
- ./parse.y (erzeuge ripper.y mithilfe von miniruby)
- ./ext/ripper/ripper.y (generiere ripper.c mithilfe von bison)
- ./ext/ripper/ripper.c
- ./ext/sdbm/_sdbm.c
- ./ext/sdbm/init.c
- ./ext/socket/socket.c
- ./ext/stringio/stringio.c
- ./ext/strscan/strscan.c
- ./ext/syck/bytecode.c
- ./ext/syck/emitter.c
- ./ext/syck/gram.c
- ./ext/syck/handler.c
- ./ext/syck/implicit.c
- ./ext/syck/node.c
- ./ext/syck/rubyext.c
- ./ext/syck/syck.c
- ./ext/syck/token.c
- ./ext/syck/yaml2byte.c
- ./ext/syslog/syslog.c
- ./ext/tk/stubs.c
- ./ext/tk/tcltklib.c
- ./ext/tk/tkutil/tkutil.c
- ./ext/zlib/zlib.c
Vollständiger Ruby Interpreter wird erstellt:
- ./main.o und ./libruby-static.a erneut binden => ruby
Nun haben wir also einen Ruby-Interpreter mit dem wohlklingenden Namen ruby in unserem Verzeichnis. Dieser meldet sich auch voller Stolz mit der Meldung: ruby 1.9.0 (2006-04-18) [powerpc-darwin8.6.0], wenn wir nach seiner Versionsnummer fragen.
In den nächsten Tagen werde ich mich mal hinsetzen und eine C-Erweiterung für CodeRay basteln. Dann werden wir endlich sehen, ob man Rubycode dadurch wirklich optimieren kann. Bis dahin.
Kommentar schreiben
Kommentare
thx fuer die uebersicht
[...] Wie ich hier kurz erwähnte, will ich mich heute ins Ruby-Ghetto wagen. Es geht darum C in Ruby einzubinden. [...]