ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/pws2004/goofed.pod
Revision: 1.6
Committed: Wed May 19 01:23:30 2004 UTC (22 years, 4 months ago) by root
Branch: MAIN
Changes since 1.5: +25 -10 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.5 =encoding utf8
2    
3 root 1.1 =head1 GOOFED - Generic Object Oriented Flexible Extensible Daemon
4    
5     =head2 Abstract
6    
7 root 1.2 Perl ist eine tolle Sprache. Leider hat sie auch viele
8     Abhängigkeiten. Besonders bei Embedding muss man im Allgemeinen eine
9     ganze Perl-Installation "mitschleppen". Bei einem bestimmten Projekt
10     musste ich ohne externe Dateien oder andere Abhängigkeiten auskommen. Um
11     trotzdem Perl einsetzen zu können, musste alles in das Binary
12     wandern. Die Probleme und Lösungen, die ich fand, sind im Folgenden
13     beschrieben.
14 root 1.1
15 root 1.2 =head1 Wozu, weshalb und warum?
16    
17     Das Projekt, für das Goofed entstand, bestand darin, den Radius-Server
18     eines großen Internet-Providers in einigen Funktionen zu ersetzen. Da die
19     Anforderungen durch viele Jahre hinweg sehr speziell wurden (ein typisches
20     "I<Wir> setzen den Standard"-Phänomen) und die alte Codebasis neuen
21     Anforderungen nicht mehr gut gewachsen war, musste ein neuer Daemon her.
22    
23     Recht früh kam die Idee, im Kern für die komplizierten Regeln eine
24     High-Level-Skriptsprache zu verwenden und nur für das eigentliche
25     Radius-Paket-Management C zu verwenden.
26    
27     Perl schien zuerst an vielen Gründen zu scheitern: kompliziertes
28     Build-System, viele Abhängigkeiten und Dateien, keine gute Kontrolle
29     über den Speicherbedarf (Leaks wären tödlich für einen Daemon, der
30     meherre Monate durchhalten muss) und Last-not-Least stand zu befürchten,
31     daß die Server-Abteilung die Lösung sofort ablehnen würde, sobald
32 root 1.3 bekannt würde, daß sie Perl benutzt (typisches "Real-World - macht
33     keinen Sinn"-Phänomen).
34 root 1.2
35 root 1.3 =head2 Eckpunkte der Implementierung
36 root 1.1
37 root 1.3 Trotz dieser Gegenanzeigen versprach Perl auch wichtige Vorteile, der
38     wichtigste war das Vorhandensein einer grossen Codebasis und viele
39     Module. Das und Perl selbst führen meist sehr schnell zu verwertbaren
40     Ergebnissen.
41    
42     Um die Anforderungen zu Erfüllen, habe ich folgende Entscheidungen
43     gefällt:
44    
45     =over 4
46    
47     =item einzelnes Binary
48    
49     Bis auf die Konfigurationsdateien sollte alles - Perl-Interpreter, Module,
50     Bibliotheksdateien - in einer einzigen Datei sein und keine externen
51     Dateien benötigen oder anlegen.
52    
53     Dies schließt leider das (ansonsten hervorragende) PAR-Modul aus, da
54     dieses alle Bibliotheksdateien zwar in eine Datei packt, zur Laufzeit
55     diese aber lediglich entpackt und entsprechend viele Dateien schreibt.
56    
57     =item festgelegte Perl-Version
58    
59     Die Perl-Version sollte hartverdrahtet werden. Der Grund liegt in vielen,
60     kleinen Änderungen auch innerhalb stabiler Release-Zyklen, die zu
61     Build-Problemen oder Fehler zur Laufzeit führen können. I<Never change a
62     running system> war hier ausschlaggebend.
63    
64     Ausserdem kann man, sobald man die Kontrolle über dei Perl-Quellen
65     hat, bedenkenlos Anpassungen vornehmen (ich nenne das die "Lizenz zum
66     Rumsauen"-Regel).
67    
68     Es sollte möglich sein, den Perl-Kern upzugraden, wobei aber klar sein
69     sollte, das dies Veränderungen am Quellcode nach sich zieht.
70    
71     =item festgelegte Module und festgelegte Versionen
72    
73     Ähnliches gilt für Module: es sollte möglich sein, fast beliebige
74     Module einzubauen, aber auch diese sollten in einer festen Version kommen.
75    
76     Perl-Module auf CPAN haben - seien wir ehrlich - fast immer kleine und
77     große Bugs. Meistens kann man mit ihnen leben oder Workarounds finden
78     - häufig muss man dazu auf Interna zugreifen, die sich von Version zu
79     Version ändern.
80    
81     =item "normales" Build-System, kein Configure
82    
83     Configure nichtinteraktiv auszuführen ist kompliziert, und sehr viel kann
84     schiefgehen. Ein einfaches Makefile fühlt sich wesentlich stabiler und
85     einfacher wartbar an.
86    
87     =back
88    
89     Da der Daemon sehr viele Anfragen erhält und in anderer Form
90     weiterleitet, wäre es schön, wenn man die Bearbeitung der Anfragen
91     verzahnen könnte. Dazu braucht man ein vernünftiges Event-System (der
92     Name sagts schon - das Event-Modul) und etwas, mit dem man effizient
93     und vor allem einfach Pseudoparallelität erreichen kann - Coroutinen,
94     implementiert mit dem Coro-Modul.
95    
96     Coro greift auf viele Perl-Interna zu und ist eigentlich recht
97     experimentell, ich hatte aber Erfahrungen mit langlaufenden Servern und
98     Coro und wußte daher, das es sehr stabil läuft, sobald es läuft.
99    
100     Daß das Umfeld stabil ist, gab den Ausschlag.
101    
102     =head1 Implementierung
103    
104     Nachdem ein paar grundlegende Gedanken gedacht waren, konnte ich an die
105     Implementierung gehen. Flexibilität ist alles, wenn etwas schiefgeht.
106 root 1.1
107     =head2 Perl? .... Microperl!
108 root 1.3
109     Wenig bekannt ist, daß es auch eine Microperl-"Distribution" gibt,
110     die ein sehr kleines und portables Perl verspricht - ohne Module, ohne
111     Systemabhängigkeiten und ohne interaktives Configure.
112    
113     Die "Distribution" ist sehr klein: sie besteht nur aus den drei Dateien
114     C<README.micro>, C<Makefile.micro> und C<uconfig.sh>. Daher ist bei Perl
115     gleich mit dabei.
116    
117     Ich habe das Makefile und die nötigen Perl-Sourcen in ein
118     Unterverzeichnis kopiert und dann die Konfiguration, die standardmäßig
119     nur ISO-C89 + einige wenige Erweiterungen wie C<rename()> benötigt,
120     solange getuned, bis ich Zugriff auf die meisten POSIX-Funktionen hatte.
121    
122     Dazu habe ich die C<CFLAGS> von:
123    
124     -DPERL_CORE -DPERL_MICRO -DSTANDARD_C -DPERL_USE_SAFE_PUTENV
125    
126     auf
127    
128     -DPERL_CORE=1 -DPERL_MICRO=1
129    
130     geändert und die Konfiguration in C<uconfig.sh> getuned, compiliert und
131     solange iteriert, bis ich zum Link-Stadium kam.
132    
133     Danach hatte ich folgende Dateien in meinem C<uperl>-Verzeichnis:
134    
135     embed.h mg.h perlio.c proto.h thrdvar.h
136     EXTERN.h embedvar.h miniperlmain.c perlio.h reentr.c thread.h
137     INTERN.h ext.libs nostdio.h perliol.h reentr.h toke.c
138     Makefile form.h numeric.c perlsdio.h reentr.inc uconfig.sh
139     XSUB.h globals.c op.c perlvars.h regcomp.c universal.c
140     av.c gv.c op.h perly.c regcomp.h unixish.h
141     av.h gv.h opcode.h perly.h regexec.c utf8.c
142     config_h.SH handy.h opnames.h pp.c regexp.h utf8.h
143     configpm hv.c pad.c pp.h regnodes.h util.c
144     cop.h hv.h pad.h pp_ctl.c run.c util.h
145     cv.h intrpvar.h patchlevel.h pp_hot.c scope.c warnings.h
146     deb.c iperlsys.h perl.c pp_pack.c scope.h xsutils.c
147     doio.c keywords.h perl.h pp_proto.h sv.c
148     doop.c locale.c perlapi.c pp_sort.c sv.h
149     dump.c mg.c perlapi.h pp_sys.c taint.c
150    
151 root 1.6 Beim Bauen bekommt man die C<libuperl.a>, das Microperl-Äquivalent
152     zur C<libperl> und C<microperl>, das zum Bauen benötigt wird und auch
153     beim weiteren Build-Prozess hilfreich sein kann. C<microperl> wird z.B.
154     benutzt, um aus der C<uconfig.sh> das C<Config.pm>-Modul zu basteln.
155 root 1.3
156 root 1.6 Mit C<microperl>, C<libuperl.a>, C<Config.pm> und den Header-Dateien hat
157     man alles, was man zum Embedden benötigt.
158 root 1.3
159     Dieser Schritt war relativ leicht. Er wäre noch leichter gewesen, wenn
160 root 1.6 ich auf die meisten esoterischen Funktionen wie C<getpwnam>, C<mkdir>
161     oder Signal-Handling verzichtet hätte, da ich fast alles über die
162     C<POSIX>- und C<Event>-Module erreichen kann, und im Notfall auch auf C
163     zurückgreifen könnte. Im absoluten Notfall.
164 root 1.1
165 root 1.4 =head2 Bibliothek
166    
167 root 1.6 Im nächsten Schritt geht es um die Bilbiotheksdateien, genaugenommen das
168     I<lib>-Verzeichnis, in dem sich die C<.pm>-Dateien befinden. Theoretisch
169     könnte man Microperl ganz ohne dieses betreiben: das Ergebnis
170     wäre jedoch kaum noch "Perl" zu nennen, da auch Pragmas als Module
171     implementiert sind. Und wie man an anderen, einfacher embeddbaren Sprachen
172     sieht, ist Perl ohne Standardbibliothek ist eine nutzlosere embeddete
173     Sprache, als man denkt.
174    
175     Üblicherweise sind die C<.pm>-Dateien in den jeweiligen
176     Modul-Distributionen, aber bei Perl sind sie schon fertig abgepackt im
177     C<lib>-Verzeichnis.
178    
179     Das größte Problem war es, alle Dateien und Unterverzeichnisse in CVS
180     einzuchecken, nachdem ich sie aus der Perl-Distribution kopiert hatte
181     (C<cp -rp ~/../perl-5.8.x/lib lib-perl>).
182 root 1.4
183 root 1.1 =head2 Module Embedden
184    
185 root 1.4 Header und Library sind zwar genug, aber Perl-Module wollen ein
186     lauffähiges Perl und Zugriff auf Kleinkram wie C<ExtUtils::MakeMaker>,
187     damit man sie übersetzen kann.
188 root 1.1
189     =head2 Bootstrapping
190