Unofficial OpenOffice Hacker's guide

English | Japanese | German

# Anleitung zum Hacken von OpenOffice.org

Um OpenOffice.org (OOo) zu hacken/builden, bedarf es schon einiges an Geduld.

Dieses Dokument wird auf den kommenden Seiten versuchen, die Lernkurve steil verlaufen zu lassen und hoffentlich deinen Weg darauf erleichtern.

Es nimmt an, dass du ein relativ aktuelles und vernünftiges Linux System benutzt und dich ausreichend mit PC Programmierung auskennst (C++ wird vorausgesetzt, es sei denn du willst dir nur mal einen Überblick über den Buildablauf OOo's verschaffen).

Wahre Hacker benutzen freie Software und haben keine Zeit sich mit "unfreiem Zeug" zu beschäftigen. Ich persönlich empfehle hier neben OOo, SuSe && Gnome.

Wir werden zumindest die folgenden Fragen beantworten:

- Wie builde ich OOo?

- Wie gehe ich mit einer Entwicklungs-Iteration um?

- Wie kann ich OOo debuggen?

- Wie kann ich einen "Patch" einsenden?

Wenn du Hilfe brauchst an den Ximian ooo-Build zu gelangen oder beim Hacken mithelfen willst, dann trete bitte der Mailing-Liste bei (Kommunikation auf englisch). Dort werden deine Fragen sicher beantwort werden.

Die deutsche Version wird versuchen in möglichst vielen Situationen deutsche Wörter zu benutzen, jedoch ist klar, dass es auch eine ganze Menge an Begriffen in der IT Welt gibt, die im Sinne ihrer Originalität im Englischen verbleiben, oder sollte ich einen "OOo build" -> "OOo Bau" nennen? Dies nur mal als Beispiel. Ihr habt Kritik? Nehm ich gern an, hier gehts lang.

## 0. Inhaltsverzeichnis

- 1. OOo herunterladen

- 2. OOo builden

- 3. OOo installieren

- 4. OOo ausführen

- 5. OOo hacken

- 6. OOo debuggen

- 7. Patche bereitstellen

- 8. Sonstige Tipps

- 9. Nützliche Links

- 10. (F)AQ

- 11. Mit uns arbeiten

Der gesamte Prozess ist ausführlicher in der detaillierten Fassung (englisch) dargestellt.

Wir haben jedoch hart daran gearbeitet einen stabil durchführbaren Prozess für reine Programmierer bereitzustellen, und die einfache Version folgt nun..

## 1. OOo herunterladen

Es gibt eine riesige Menge an konkurrierenden OOo Versionen und viele Auswahlmöglichkeiten an Zweigen ("branches") mit vielzähligen qualitativen Patch Zusammenstellungen.

Ich empfehle CVS snapshots, die bekannt sind ordentlich zu builden, und mit Patch Zusammenstellungen, die sich einwandfrei einbinden lassen.

Um den Sourcecode zu erhalten gehen wir wie folgt vor:

    export CVSROOT=':pserver:anonymous@anoncvs.gnome.org:/cvs/gnome'
    cvs login
    cvs -z3 checkout -P ooo-build

Das wird eine Kopie des OOo-build (= OOo ximian version) Baumverzeichnisses bereitstellen. Wenn du CVS nicht magst, dann kannst du auch eine aktuelle Version von hier downloaden.

Beachte: Du wirst ca. 200 MB an komprimierten Sourcecode downloaden und solltest ca. 5Gb an freiem Speicherplatz haben, um alles zu entpacken und zu builden.

## 2. OOo builden

### 2.1. configure

Der komplette Buildprozess ist ziemlich kompliziert. Du hast erstmal die Wahl von zwei Befehlen, obwohl es eigentlich nichts ausmacht beide auszuführen:

            ./autogen.sh # the CVS version
            ./configure  # the packaged version

Das wird wird herausfinden welchen Snapshot-Zweig du builden möchtest. Wenn du andere Ideen hast, benutze bitte --with-tag Option, wie z.B.

    --with-tag=OOO_1_1_0

für einen Vermächtniszweig (="legacy branch").

### 2.2 download

Nach der Zeit, in der du dein System zu dem Stand gebracht hast, dass es alle benötigten Pakete hat (mozilla, libart etc.), ist fast schon der Zeitpunkt gekommen, den Sourcecode downzuloaden. Um das nach einem erfolgreichen configure Befehl zu machen, schreibe:

    ./download

und warte[...]

make

Nun kommt der Knackpunkt:

    make

und vergesse nicht <Enter> zu drücken. Gut möglich ist es auch, dass du die Ausgabe protokollieren willst, also warum nicht

    make 2>&1 | tee /tmp/log

.

## 3. OOo installieren

Das Ergebnis eines ordentlichen Builds ist ein perfektes Installationspaket in

    build/$TAG/instsetoo/unxlngi4.pro/01/normal/

oder ähnlich. Dann führe zum Installieren das Setup-Programm von dort aus, in dem du z.B.

    /opt/OOInstall

benutzt. Um das funktionsfähig zu vollenden, musst du erst noch deine

    ~/.sversionrc

Datei ausführen.

Nun da es schon mal installiert ist, wollen wir auch gleich mal in die Stimmung kommen, OOo zu hacken, indem wir den build-tree direkt auf das installierte Abbild verweisen, sodass wir beim re-compilen eines Code-Unterverzeichnisses, OOo einfach neu ausführen können. Dies kann den Build/Test-Lauf um einige Zehntel schneller machen. Um dies zu erreichen, schreibe:

    bin/linkoo /opt/OOInstall /opt/ooo-build/build/OOO_1_1_2

, schaue auch bitte die Linker Einschränkungen an.

## 4. OOo ausführen

Nun gehe man in

    /opt/OOInstall/program

und schreibe

    source ./ooenv

das wird die (bash) Shell darauf einstellen, OOo direkt auszuführen. Dann einfach

    soffice.bin

. Dies ist besser als schlicht soffice auszuführen oder ein "Wrapper-Skript", da es nun ganz einfach ist den Fehlersuchprogramm anzuhängen:

gdb soffice.bin

.

Beachte: Benutze *nicht*:

    ./soffice.bin

was wegen unerklärten Gründen nicht richtig funktioniert.

Beachte: Du musst zuvor den auf OOo basierten ooo-wrapper ausführen, sodass ~/.sversionrc ordentlich eingestellt ist, ansonsten wird die soffice.bin zum GUI setup Werkzeug verweisen. Tue:

    oowriter

vor dem Start.

## 5. OOo hacken

### 5.1 Der erste Hack

Alsoo - wir haben OOo nun gebuildet und ausgeführt, und wir wollen uns selbst nun beweisen, dass es wirklich möglich ist, das Biest zu hacken. In einem neuen Terminal machen wir also jenes:

    cd build/$TAG
    . ./LinuxIntelEnv.Set.sh
    cd vcl

Wie wärs nun mit einem Hack in vcl/source/window/toolbox2.cxx? Ich würde vorschlagen einfach mal ein

    nPos = 0

irgendwo vor dem m_aItems.insert in ToolBox::InsertItem( const ResId &rResId ...) hinzuzufügen. Dann abspeichern.

Noch in VCL, ja? Dann schreibe 'build debug=true'; warte darauf, dass der rollende Text stoppt; (5 Sekunden?). Nun neu ausführen..

    soffice -writer

Du solltest den Effekt mitbekommen haben.

Beachte: Dies stellt die Vorraussetzung, dass du die vorigen Schritte befolgt hast, speziell das linkoo in Sektion 3.

Beachte: Für simples ab-und-zumal hacken kannst du "build" im Source Tree ausführen. Führe "make" *nicht* im Hauptverzeichnis

    ooo-build/

aus, oder alle Änderungen können höchstwahrscheinlich weggeschmissen werden. Es macht daher Sinn eine separate Kopie von

    build/OOO_1_1_2

zu haben, schaue hier, um den Build schließlich wieder anzuordnen.

### 5.2 Lese das Handbuch

Mit der Stärke von C++ kommt die Fähigkeit sich selbst ins Knie zu schießen, vergleiche Holub, Rules for C and C++ programming, McGraw-Hill, 95.

Der beste Weg sich für die Herausforderung vorzubereiten, ist erst einmal die OOo Coding-Guidlines zu lesen und für alle, die es nicht wissen, c'tor / d'tor sind die Abkürzungen für constructor / destructor.

### 5.3 Patche einsenden

Selten ist klar welches Modul zu welchem Bugreport (Issuezilla) gehört. Ein möglichst kurzer Weg dies herauszufinden, ist:

    cvs status <somefile> | head

Das sollte eine 'Archiv-Version(="repository revision"):' Zeile geben, mit einem Pfad, dessen zweiter Teil den Modulnamen verrät.

### 5.4 Den Installer hacken

Da das Installationsabbild das ausführbare temporäre Setupabbild in `/tmp/sv001.tmp löscht, müsstest du es dabei verhindern dies zu tuen. Führe dazu bitte setup / install mit der -dontdeletetemp Option aus.`

### 5.5 Andere Bereiche hacken

Wenn ein funktionierender Installer vorliegt, ist der beste Weg den Hack zu integrieren, indem du `program/libfoo641li.so` zu der von dir gebuildeten Version symbolisch verweist - höchstwahrscheinlich in: `foo/unxlngi4.pro/lib/ -, dann sollten die Veränderungen eingearbeitet sein.`

Als Beispiel sagen wir mal, du willst "sal" (den System Abstraction Layer) hacken und du hast OOO_STABLE_1 in /opt/OOInstall installiert, dann führe das folgendes aus:

    cd /opt/OOInstall/program
    mkdir backup
    mv libsal.so.3.0.1 backup
    ln -s /opt/OpenOffice/OOO_STABLE_1/sal/unxlngi4.pro/lib/libsal.so.3.0.1

### 5.6 Dmake verstehen (man)

Während das Build-System sehr ähnlich ist zu anderen Systemen, hat es jedoch trotzdem noch seine besonderen Eigenheiten. Das gesamte Konzept besteht darin, dass jedes Modul einzeln gebuildet wird und die kompilierten Dateien in den Solver-Tree wandern.

Jedes Modul selbst kompiliert gegen die Headerdateien des Solvers, deshalb entstehen grundsätzlich auch keine unnötigen Komplikationen.

- built - Dieses Perl Skript solenv/bin/build.pl wird in Verbindung mit prj/build.lst benutzt, um sicher zu gehen, dass jedes Modul das gebraucht wird zuerst gebuildet wird.

- deliver - Dieses Perl Skript solenv/bin/deliver.pl installiert Headerdateien und Bibliotheken in den Solver, wie in prj/d.lst beschrieben. 'deliver' überprüft unter anderem, dass der Datumsstempel jeder in den Solver kopierten Datei der gleiche ist wie im Modulverzeichnis.

#### 5.6.1 Standardverzeichnisse

Es gibt einige Standardverzeichnisse, die in jedem OOo Modul vorhanden sind:

- prj

  - build.lst — dies beschreibt die generierten Verzeichnisse, '^#' Kommentare sind erlaubt, die Reihenfolge dieser Liste ist nicht von Belangen, siehe Details, es diktiert die Hauptoperationen von build.

  - d.lst — diese Datei beschreibt den "Deliverprozess", siehe Details.

- util — die Dateien dieses Verzeichnisses haben normalerweise die Aufgabe die Bibliotheken für jedes Untermodul in eine größere Bibliothek zusammenzuführen, es integriert dabei auch die gebrauchten System-Bibliotheken und buildet die GUI Resourcen etc. Die gesamte Vorgehensweise ist im makefile.mk beschrieben. Dies ist üblicherweise das letzte zu buildende Verzeichnis in einem Projekt.

- inc — allgemeine Headerdateien sind normalerweise im 'inc' Verzeichnis zu finden. Diese werden durch 'deliver' in den Solver kopiert (dabei wird prj/d.lst benutzt).

Es gibt mehrere Dateiformate die Build-spezifisch sind:

- makefile.rc — diese Dateien sind alle nebensächlich und gebrauchen keiner Erklärung.

- makefile.mk — diese hingegen sind die für jedes Modul wichtigen "dmake" Dateien

#### 5.6.2 build.lst

Auf den ersten Blick sieht build.lst ein bißchen schaurig aus:

    vc      vcl : nas freetype psprint rsc sot ucbhelper unotools sysui NULL
    vc      vcl                      usr1   -       all     vc_mkout NULL
    vc      vcl\source\unotypes      nmake  -       all     vc_unot NULL
    vc      vcl\source\glyphs        nmake  -       all     vc_glyphs vc_unot NULL

sodass wir uns also gleich ranmachen das ganze Stück für Stück unter die Lupe zu nehmen, was uns dann zeigen wird, dass es nicht so arg schlimm ist, wie es auf den ersten Blick erscheinen mag.

Als aller erstes fällt auf, dass jede Listenzeile mit einem 'NULL'-String endet (man kann hier von einem Sentinel sprechen). Außerdem verzeichnet jede Listenzeile über ein Kürzel ganz am Anfang, was aber für uns als irrelevant zu bezeichnen gilt.

- Die allererste Zeile der Datei enthält einen Doppelpunkt ':', dies beschreibt den Bestand, dass das Projekt (vcl) von anderen Modulen abhängig ist. 'nas', 'freetype', 'psprint' etc. müssen also zuvor gebuildet worden sein. Dies ist wichtig für das Ineinandergreifen der verschiedenen Projekte.

- Dann haben wir die eher überflüssige Zeile mit 'usr1' [ zum Spaß ? ], tatsächlich sind alle kommenden Zeilen nur gültig mit dem speziellen 'nmake' String!

- Die nächste Zeile beschreibt projektinterne Verzeichnisabhängigkeiten:

      [shortcut] [path to dir to build] nmake - [flags] [unique-name] [deps...] NULL
      vc           vcl\source\glyphs    nmake -   all     vc_glyphs   vc_unot   NULL

  shortcut wird funktional nicht benutzt, flags stellt fest, auf welcher Plattform das Projekt gebuildet wird. Normalerweise stehen die kurzen Plattformbezeichnungen: 'dnpum' 'u' für Unix. Je höher das System, desto mehr wird 'all' eingefügt.

  unique-name dies ist ein spezieller Name, der von anderen Zeilen für interne Zusammenhänge gebraucht wird. deps... variable Anzahl von Verzeichnissen in dieser Datei, die zuvor gebuildet werden müssen.

Im Falle von vcl (="Visual Component Library") sehen wir also, dass vcl\source\unotypes (vc_unot) noch vor vcl\source\glyphs (vc_glyphs) gebuildet werden muss. Es ist wirklich wichtig zu verstehen, dass die Reihenfolge der Liste unwesentlich ist und statt eine simple klar-geordnete Liste, haben wir eher ein komplexeres internes Beziehungssystem, das demzugrunde von anderen make-Konzepten abweicht.

Eine detailliertere Dokumentation findet man hier

#### 5.6.3 d.lst

d.lsts Syntax ist verständlicher als jene von build.lst, es unterlässt einge Standardfunktionen, wie z.B. das Kopieren von build.lst nach inc/<module>/build.lst.

Eine Zeile hat die folgende Form:

    [action]: [arguments]
    mkdir:    %_DEST%\inc%_EXT%\external

die standardgemäße Kopiefunktion wird durchgeführt, wenn '[action]:' weggelassen wird. Die typischen Ausführungen sind copy, mkdir, touch, hedabu, dos and linklib.

Speziell der 'hedabau' Befehl ist interessant, in der Weise, dass es die Headerdateien beim Installieren kürzer werden lässt (ansonsten ist es eigentlich nicht viel anders als das übliche Kopieren).

Während dieser Aktion werden verschiedene Macros verwendet, manche davon sind:

- %__SRC% - Distributionsverzeichnisname z.B. unxlngi4.pro

- %_DEST% - absoluter Pfad zum Solver z.B. /opt/OpenOffice/OOO_STABLE_1/solver/641/unxlngi4.pro

- %_EXT% - End-Versionsnummer bei Aktualisierungen, üblicherweise benutzt für jedes Unterverzeichnis im Hauptast("MasterWorkspace")

Wenn du wirklich eine bestimmte Regel einführen willst (wie z.B. impliziertes Verzeichniskopieren), dann wird dies dem folgenden Schema entsprechen:

    ..\%__SRC%\inc\sal\*.h %_DEST%\inc%_EXT%\sal\*.h

Achte darauf, dass Pfade relativ zum 'prj/' Verzeichnis sind.

### 5.7 Schnelle Iteration

Es gibt viele Wege zu schnellem Entwicklungsfortschritt, der wohl beste Weg ist linkoo zu benutzen, um die Bibliotheken aus dem Installationspaket direkt in den Build-Tree symbolisch zu verweisen. Dann kannst du auf einfache Art und Weise Unterverzeichnisse "re-builden" und zwar indem du:

    build

im Unterverzeichnis verwendest und soffice.bin neu ausführst.

Nun kommen wir dann mal zum Sourcecode selbst..

### 5.8 Kann ich `char * benutzen`?

Eher dürftig. OOo hat mindestens sechs String-Wrapper, wobei den C Umsetzungen nur sehr geringe Achtung geschenkt werden sollte:

- `rtl_String` - sal/inc/rtl/string.h
  "Normaler" String mit ref-counting. `rtlstring->buffer` ist hilfreich, wie auch `rtlstring->length`. Dieser String ist schon umgewandelt zu einem bestimmten Charakterset, siehe sal/inc/rtl/textenc.h - die einzigen interessanteren Fälle sind `RTL_TEXTENCODING_UTF8 und vielleicht noch RTL_TEXTENCODING_ASCII_US` . Fühle dich frei `rtlstring->buffer` als deinen beliebten C `char * anzusehen`.

- `OString` - sal/inc/rtl/string.hxx
  `Der `rtl_String` einfach als Klasse implementiert.` Du kannst `ostring.pData` benutzen, um direkt an den rtl_String zu gelangen. `OString` hat ganz sicher einige nützliche Funktionen.

- `rtl_uString` - sal/inc/rtl/ustring.h
  "Normaler" Unicode String, ähnlich wie rtl_String auch mit ref-counting. Wie auch immer, dieser String kommt immer im UCS-2 enkodierten Format, um mit Javas fraglicher Auswahl kompatible zu sein.

- `OUString` - sal/inc/rtl/ustring.hxx
  Ein rtl_uString `als Klasse`. Das ist der intern am häufigsten benutzte String um Daten auszutauschen.

- `String` - tools/inc/string.hxx
  Das ist ein veralteter Typ, der unter den Namen 'UniString' fällt. Es hat einige Einschränkungen wie ein rtl_uString `innerhalb einer Klasse`.

Da ja jeder richtige Programmierer `char *` UTF-8 enkodierte Strings verwendet, muss jeglicher System-API Aufruf wie z.B. 'printf' ein Chararray von `OUString` aus konvertieren:

    static char *
    gimme_utf8_please (const rtl::OUString &oustring)
    {
            rtl::OString ostring;

            ostring = ::rtl::OUStringToOString (oustring, RTL_TEXTENCODING_UTF8);
            return strdup (ostring.pData->buffer);
    }

und hier in entgegengesetzter Richtung:

    static rtl::OUString
    complicate_things_into_ucs2_please (const char *utf8_string)
    {
            rtl::OString ostring;

            ostring = rtl::OString (utf8_string);
            return rtl::OStringToOUString (ostring, RTL_TEXTENCODING_UTF8);
    }

Wenn du einfach nur einen String für Fehlersuch-Zwecke schreiben lassen willst, dann wirst du wahrscheinlich das hier haben.

#### 5.8.1 Strings mit GDB untersuchen

Wir haben schon gesehen, dass OOo nicht die bescheidenen `char *` Strings benutzt. Wenn du nun dachtest es wär schon anstrengend genug Code zu schreiben, dann warte lieber ab bis wir noch zum Debugging kommen. Glücklicherweise zeigen wir dir nun wie du an Strings von gdb/dbx - die selbst nicht mit Unicode umgehen - herankommst:

- vom CVS Zweig cws_srx645_ooo112fix1 aufwärts kann

      (gdb) print dbg_dump(sWhatEver)

  benutzt werden, um den Inhalt eines UniString/ByteString/rtl::OUString/rtl::OString's auf den Bildschirm zu drucken, dabei ist der Typ bei der Fehlerbeseitigung des C++ Codes egal. Siehe iz17295 für nähere Details.

Wenn das in deiner OOo Version noch nicht unterstützt wird, gibts noch eine Alternative...

- rtl_String: probier rum damit!

- String: Achte darauf, dass die Deklaration das macro 'UniString' benutzt, um Leser von tools/inc/string.hxx zu irritieren. Glücklicherweise können wir leicht und locker ein String zu einem OUString konvertieren ("casten").

- OString: p str->pData

- OUString, rtl_uString: (toller Tip von Kevin Hendricks) Der schnellste und einfachste Weg den String auszuwerfen ist wie folgt:

            p *theString; # grab the length (2nd field)
            x/<length>s theString->buffer

  für einen 20 Charakter-langen String wollen wir dann also

      x/20s theString->buffer

  . Das sollte dann den String als Array aus Elementen des Typs Short mit ASCII Werten sauber und fein in eine Rubrik schreiben.. Um programmtechnisch einen OUString (or String) zu erhalten:

      ::rtl::OString tmpStr = OUStringToOString (MyOUString, RTL_TEXTENCODING_UTF8);
      fprintf (stderr, "String is '%s'\n", tmpStr.getStr());

### 5.9 Linkoo Einschränkungen

Während Linkoo für sich recht "leistungsfähig" ist, wird es durch die Art und Weise wie OOo zusammengeflickt ist in seiner Stärke eingeschränkt. Es gibt hierbei zwei Musterprobleme:

- Sonderbares Verhalten beim Linken - wenn du die Bibliothek symbolisch verweist, dann folgt es dem Link während der Runtime und endet arg im Durcheinander.

  - soffice.bin - muss bei jedem Enwticklungsdurchgang von desktop/unxlngi4.pro/bin/soffice kopiert werden, ansonsten läuft die Fehlersuche durcheinander.

  - libcfgmgr2.so - muss jedes Mal von configmgr/unxlngi4.pro/lib kopiert werden, ansonsten kann die Konfiguration nicht richtig geladen werden.

- Merkwürdiges internes Bibliothekensystem

  - Dateifilter haben Prüfungs-Code ("detection code"), wie sc/source/ui/app/sclib.cxx (ScDLL::DetectFilter) z.B., welches zu statischen Bibliotheken kompiliert, installiert und dann zu libwrp in desktop/source/offwrp gelinkt wird. Um 'sc' erneut zu builden, mache:

        build && deliver

    dann im desktop/source/offwrp Ordner tue:

        touch wrapper.cxx && dmake.

## 6. OOo debuggen

Dieses Kapitel setzt die Benutzung des GNU debuggers von der Konsole her voraus.

### 6.1 Mit Debugging-Symbolen builden

OOo beinhaltet die Möglichkeit Debugging-Code pro Modul zu integrieren, nämlich via den `build debug=true` Befehl in jedem Modul. Unglücklicherweise ist dies jedoch nicht für den Gebrauch des gesamten Projektes zu empfehlen und neben vitalen Debugging-Symbolen werden auch Unmengen an "Assertions", aufkommende Warnungen und verschiedene andere Cheks mit eingeschlossen.

Wenn du deshalb also Debugging-Symbole für alles haben willst, musst du mehrere Makefiles hacken um Debugging-Symbole hinzuzufügen (sei gewarnt, dass dies die binaries zu ca. 1GB anwachsen lässt und den vollen Build-Tree sogar zu 8GB), wie hier beschrieben:

    --- solenv/inc/unxlngi4.mk
    +++ solenv/inc/unxlngi4.mk
    @@ -92,18 +92,18 @@ cc=gcc
     # do not use standard header search paths
     # if installed elsewhere
     .IF "$(BUILD_SOSL)"!=""
    -CFLAGS=
    +CFLAGS=-g
     .ENDIF
     CFLAGS+=-fmessage-length=0 -c $(INCLUDE)
     # flags for the C++ Compiler
    -CFLAGSCC= -pipe -mcpu=pentiumpro
    +CFLAGSCC= -g -pipe -mcpu=pentiumpro
     # Flags for enabling exception handling
     CFLAGSEXCEPTIONS=-fexceptions -fno-enforce-eh-specs
     # Flags for disabling exception handling
     CFLAGS_NO_EXCEPTIONS=-fno-exceptions

     # -fpermissive should be removed as soon as possible
    -CFLAGSCXX= -pipe -mcpu=pentiumpro -fno-for-scope -fpermissive -fno-rtti
    +CFLAGSCXX= -g -pipe -mcpu=pentiumpro -fno-for-scope -fpermissive -fno-rtti

     # HACK: enable Hamburg developers to build on glibc-2.2 machines but compile vs. glibc-2.1 headers
     .IF "$(BUILD_SOSL)"==""

Natürlich wird gdb recht sinnlos ohne Debugging-Symbole. Um den Patch also einzubringen, kopiere das oben stehende nach /tmp/foo und ins Hauptverzeichnis.

    patch -p0 < /tmp/foo

### 6.2 Breakpoints setzen

Wegen dem relativ groben Außmaß an Fehlern mit gdb, ist es sehr wahrscheinlich, dass das Benutzen von Breakpoints nicht rein funktionieren wird, deshalb ist wohl die beste Lösung das folgende:

    gdb ./soffice
    break main
    run # don't forget the arguments here
    # ... traps in main ...
    break osl_readFile
    continue

Offensichtlich wird dies niemals erfolgreich ablaufen, wenn der Code in einer Bibliothek implementiert ist, welche durch 'dlopen' später geladen wird, was auf die große Mehrheit des OOo Sourcecodes zutrifft. Deshalb sollte man den Code beim Laden abfangen, um dann erst den Breakpoint einzusetzen.

Um dies zu machen, hau einen Breakpoint in osl_psz_loadModule rein und nun leide!

Als Alternative dazu, wenn du den Code instrumentalisieren kannst, sollte es ziemlich einfach sein einfach #include <signal.h> beizufügen und einen SIGSTOP irgendwo im code zu werfen, welcher dann den Debugger aufspürt.

### 6.3 Wir beginnen immer am Anfang!

Wir starten mal mit einem sal Wrapper in 'main', der vcl/source/app/svmain.cxx (SVMain) anspricht. Main wird durch pSVData->mpApp ausgelöst, aber pSVData ist inline. Um dies zu auszutesten, benutze die globale Variable pImplSVData. Z. B.:

          p pImplSVData->maAppData

Diese 'Main' Methode ist typicherweise in desktop/source/app/app.cxx .

### 6.4 Strings untersuchen

Der C-Char-Array Typ (den gdb anzeigen kann) wird bei objekt-orientiertem Programmieren durch das "Wrappen" von unzähligen verschiedenen Klassen vermieden, da gdb diese Klassen naturell nicht versteht. Schlimmer noch, in vielen Fällen ist es besonders schwer sogar einfach nur den String zu drucken - eine der Konsequenzen von Sun's Strategie mit ucs-2 Enkodierung fortzufahren. Es gibt dabei neben veränderbaren auch unveränderbare Strings.

Bitte siehe dir Sektion 5.8 an, um zu sehen wie man in OOo mit Strings um gehen sollte, Debugging Tips sind dafür auch dabei.

### 6.5 Die Build-Abfolge auf die Reihe bekommen

Die Build-Abhängigkeiten der Module sind nicht sehr eindeutig und einfach, um einen sauberen Build hinzubekommen. Wenn du 'build' in einem Modul schreibst, wird erstmal prj/build.lst analysiert, wie neon/prj/build.lst zum Beispiel..

    xh      neon  :  soltools external expat NULL

dies macht klar, dass 'soltools', 'external' und 'expat' (mit Geduld!) vorher noch gebuildet werden und danach zugestellt ("deliver") werden müssen, bevor 'neon' erstmal gebuildet werden kann. Manchmal kommt es vor, dass diese Regeln gebrochen werden und eine Weile vergeht, in der sowas nicht bemerkt wird. Deshalb ist Vorsicht geboten!

### 6.6 Es crasht, aber nur in gdb

Was für ein Spaß das ganze ist - du hast im Installationsbaum desktop/unxlngi4.pro/bin/soffice zu soffice.bin verwiesen, oder nicht?! Das funktioniert ja auch ganz fein, wenn du es einfach ausführst. Aber es scheint, dass gdb den symbolischen Link entpackt und einen regulären Pfad als argv[0] sendet, was unglücklicherweise das Suchen nach dem binären Pfad auswirkt, sodass es also den Hauptfad des Programms als opt/OpenOffice/OOO_STABLE_1/desktop/unxlngi4.pro/bin zuweist und nun dort nach applicat.rdb (nur als Beispiel) am Suchen ist. Es ist deswegen auch klar wie Klosbrühe, dass es keine Setup Informationen findet und der Build-Prozess irgendwo - ganz weit entfernt - in der Prärie ausstirbt.

### 6.7 Es crasht, "stirbt" aber nicht

Wegen einigen Gründen werden Signalhandler aufgespürt, und das Leben kann dann ganz schön verwirrend werden, deshalb ist es für Entwickler durchaus gut etwas ähnliches, wie unten beschrieben, zu integrieren:

    --- sal/osl/unx/signal.c
    +++ sal/osl/unx/signal.c
    @@ -188,6 +188,8 @@ static sal_Bool InitSignal()
                 bSetILLHandler = sal_True;
            }

    +       bSetSEGVHandler = bSetWINCHHandler = bSetILLHandler = bDoHardKill = sal_False;
    +
            SignalListMutex = osl_createMutex();

            act.sa_handler = SignalHandlerFunction;

### 6.8 Ich kann den Code im Fehlerprotokoll nicht finden

Manche Methoden haben eine spezielle Verbindung(=linkage), sodass sie dann in Callbacks benutzt werden können.

Diese haben typicherweise die Präfix 'LinkStub', such deshalb am besten für das letztere in einer Freitext-Suche:

          IMPL_LINK( Window, ImplHandlePaintHdl, void*, EMPTYARG )

Dies bildet dann die 'LinkStubImplHandlePaintHdl' Methode.

### 6.9 Wie kann ich die Dateien der Fehlersuche erneut builden?

Beim Benutzen von gdb kommt es oft vor, dass man es sich nicht leisten kann ewig lang zu warten (oowriter Modul Kompilierung wäre so ein Fall). Deswegen haben wir ein kleines Perl Skript geschrieben, mit dem du Klassen-Namen und/oder Methoden - in die du interessiert bist - vom Kellerspeicher ("stack") ausschneiden und einfügen kannst, und dann wird das Perl-Hilfswerkzeug nur diese Strings antasten ("touch"), um einen schnelleren und einfacheren Build erfolgreich hinzulegen. Hier ist ein typischer Ablauf von Fehlersuche und -beseitigung:

        gdb ./soffice.bin
        ...
        bt
    #0  0x40b4e0a1 in kill () from /lib/libc.so.6
    #1  0x409acfe6 in raise () from /lib/libpthread.so.0
    #2  0x447bcdbd in SfxMedium::DownLoad(Link const&) () from ./libsfx641li.so
    #3  0x447be151 in SfxMedium::SfxMedium(String const&, unsigned short, unsigned char, SfxFilter const*, SfxItemSet*) ()
       from ./libsfx641li.so
    #4  0x448339d3 in getCppuType(com::sun::star::uno::Reference const*) () from ./libsfx641li.so
    ...
        quit
        cd base/OOO_STABLE_1/sfx2
        ootouch SfxMedium
        build debug=true

Demzufolge werden alle Dateien, die sich auf SfxMedium beziehen oder irgendwas davon implementieren angetastet und mit Debugging-Symbolen neu gebuildet.

### 6.10 Wie kann ich alle Dateien eines Ordners builden?

Wenn du schlicht und weg den code in deinem aktuellen Arbeitsverzeichnis kompilieren willst, dann verwende den killobj dmake Befehl, um alle bereits existierende Objektdateien zu löschen:

        dmake killobj
        dmake

### 6.11 Es crasht immer in sal_XErrorhdl

Huch, dann bist du ein Opfer von asynchronem (oder einfacher: "one-way") X Fehlerreport, das

    export SAL_SYNCHRONIZE=1

wird jegliche "X-Verkehrweichen" auf synchron stellen, und den Fehler mit dem Benennen der Methode ausspucken. Es wird OOo auch um einiges langsamer machen und das OOo Zeitsystem umstellen.

### 6.12 Stillschweigend schlägt es Fehl beim Importieren meiner Word Datei

Unser Caolan schlägt hier vor, Stopppunkte (fast schon Schifffahrt-mässig mit drei "f" ;) ) oberhalb und unterhalb von SwWW8ImplReader::LoadDoc in ww8par.cxx einzufügen, und zu gehe sicher, dass das Dokument so weit geht wie der Importfilter.

Ein gemütlicher Platz für einen Stopppunkt wäre bei SwWW8ImplReader::ReadPlainChars, wo du ganze Brocken an Text (wie sie eingelesen werden) sehen kannst. Eine Alternative wäre auch SwWW8ImplReader::AppendTxtNode für jeden eingefügten Paragraph.

### 6.13 Wie benutze ich die Debug-Konsole?

OOo beinhaltet eine ziemlich deftige Infrastruktur; seht hier selbst. Bedauerlicherweise ist das Durchsetzen nicht ganz so einfach. Zuerst einmal geht nichts davon in einen offiziellen Produkt-Build, sodass wir also dazu gezwungen sind einige OOo Kernstücke neu zu builden. Und schließlich sollten wir linkoo neu ausführen, um diese neuen Builds in unser Paket einzubinden.

Kreiere eine Umgebungsvariable (="environment variable"), ich nenn sie hier LinuxIntelEnv.Set.debug:

    TMPFILE=~/.Env.Set.debug

    # Purge .pro bits
    sed 's/\.pro//g' LinuxIntelEnv.Set.sh > $TMPFILE
    . $TMPFILE
    rm $TMPFILE

    # Clobber product parts
    unset PRODUCT PROSWITCH PROFULLSWITCH

Nun tue

    source ./LinuxIntelEnv.Set.debug

, dies wird deine Umgebung für einen Build erschaffen

    cd vcl; build dbgutil=true --all linkoo

nun führe OOo aus und wenn es gerade voll im Arbeitsprozess ist, drücke <Alt>-<Shift>-<Control> 'D' in genannter Reihenfolge. Das sollte ein Popup-Debugging-Fenster zum Erscheinen bringen. Die Fehlersuch-Optionen sind anschließend in die dbgsv.init Datei gespeichert für den nächsten Durchlauf. Du kannst den Ort dessen mit

    export DBGSV_INIT=$(HOME)/.dbgsv.init

kontrollieren, leider handelt es sich hier um eine binäre Datei

### 6.14 Excel Interoperabilitäts-Debugging

Das ist ganz einfach: Editiere sc/source/filter/inc/biffdump.hxx, definiere EXC_INCL_DUMPER mit dem Wert 1 und dann builde 'sc' erneut. Hinzuzufügen wäre noch sc/source/filter/excel/biffrecdumper.ini zu xxx zu kopieren. Dann führe

    soffice.bin foo.xls

aus und und voila es sollte eine foo.txt mit Debugging-Informationen erstellt worden sein. Wenn du nichts erhalten haben solltest, dann kannst du die sc-biffdump.diff hier finden.

## 7. Patche bereitstellen

### 7.1. Diff Tool

Wende diff immer im standardgemäßen 'cvs -z3 diff -u' an, da dies die am einfachsten lesbaren diff-Dateien erstellt.

### 7.2. Kommunikation

Bevor man einen eigens ausgearbeiteten Fix (für einen Programmfehler) implementiert, ist es ratsam sich mit dem ein oder anderen Entwickler vorher darüber zu unterhalten. Einer der besten Wege mit anderen Entwicklern in Kontakt zu treten ist an dev@openoffice.org zu schreiben, oder im channel #openoffice.org auf dem IRC Server: irc.freenode.net (Port: 6667) Ausschau zu halten. IRC ist ein ziemlich stupides Kommunikationsmedium, aber es ist immer noch viel besser als gar keine Kommunikation. Schaue hier nach, um zu erfahren, wer wer ist im channel.

### 7.3. ooo-build Patchsystem

Schaue hier nach, um mehr über unsere Patch-Struktur zu erfahren.

### 7.4 Programmfehler mitteilen

Hier kannst du unsere mildere Version des OpenOffice IssueZilla Systems sehen und beruhigt benutzen :-).

Da wir oftmals die Hauptperson eines Moduls durch das Checken des ADMIN_FILE_OWNER Tags herausbekommen können, haben wir dafür extra ein kleines Tool für den ooo-build eingebaut:

bin/owner <Dateiname> hilft dir dabei, wem du bezüglich eines bestimmten Moduls e-mailen solltest. Es ist es in jedem Fall Wert bei sehr spezifisch einzuordnenden Programmfehlern mit dieser Person in Kontakt zu treten.

## 8. Sonstige Tipps

### 8.1. Wie stelle ich eine Verbindung mit CVS Account her?

Über die sichere SSH Methode. Dieser Abschnitt beschreibt die Benutzung von CVS Accounts für den offiziellen OpenOffice.org up-stream Server, ooo-build Accounts werden anders behandelt. Siehe auch i7270 im OOo Issuezilla. Sobald du den Account hast, kannst du den CVS Server etwa in dieser Art "tunneln":

    ssh -f -2 -P -L 2401:localhost:2401 tunnel@openoffice.org sleep 1400 < /dev/null > /dev/null

Dann kannst du deinen CVSROOT auf-deine-Festplatte-zeigend wechseln, da dies ja der Ausgangspunkt des Tunnels ist:

    :pserver:cj@localhost:/cvs

Dein Account Name und Passwort werden dieselben sein, wie im openoffice.org Mitgliedsportal. Log dich ein und du wirst schnell erkennen, dass du deine CVS Einstellungen zum neuen Server migrieren musst. Das folgende sollte gut funktionieren:

    bin/re-root /path/to/checkout ":pserver:<account-name-here>@localhost:/cvs"

Um etwas direkt einzubinden, brauchst du natürlich mehrere Projektprivilegien - und nebenbei musst du noch gegen die Bürokratie ankämpfen :-).

### 8.2 patch / diff Benutzung

patch/diff sind wunderbare Werkzeuge, doch leider kommt es gar nicht mal so selten vor, dass wir Menschen Daten angeben, die diese total durcheinander bringen; ein wirres "Klamaust" entsteht als Folge. Hier sind ein paar Tricks, um dieses Durcheinander zu ordnen:

- Wenn generell unsicher, führe patch mit der --dry-run Option aus, der dann anspringende Prozess wird so erscheinen als verrichte er den Patch, tatsächlich wird aber nichts repariert ("gepatcht"). (Trotz einiger Nebenwirkungen, kann dieses "Simulieren" in etlichen Situationen sehr hilfreich sein)

- In den meisten Situationen solltest du patch -p0 benutzen. Die 0 steht für die Anzahl der Pfadelemente, die vom Anfang des Dateipfades - wo diff hinzeigt - abgeschnitten wird.

- Wenn du es durcheinander bringst, und schon die Hälfte des Patches angelegt hast und du willst mit einem sauberen Patch wieder von vorne beginnen, dann lösche entweder die Dateien und aktualisiere cvs, oder patche von neuem mit der '-R' Option, um den Spieß (der Patch Prozess ist hier gemeint) umzudrehen.

- Manchmal macht diff das Lesen der Patches schwerer, wenn viele Lücken("white-space")-Veränderungen zwischen den Modulen vorhanden sind. Der Bitschalter ("flag") '-w' zum cvs diff macht das ganze hierbei um einiges leichter.

### 8.3 Make clean

Schreib einfach dmake clean im Hauptverzeichnis. In alten Versionen, die noch über kein HEAD verzeichneten, war kein allgemeines 'clean' Ziel, sodass man stattdessen etwas wie in der folgenden Art tuen musste:

    find -name 'unxlngi4.pro' -exec rm -Rf {} \;

### 8.4 CVS setup

Um die Bandbreite voll auszunutzen, generiere vernünftige .diffs als Standard und folge dem Trend, du brauchst das in deiner ~/.cvsrc.

    cvs -z3 -q
    diff -upN
    update -dP
    checkout -P
    status -v

### 8.5. Headerdateien zum Build integrieren

Die Integration von neuen Headerdateien in den Build Prozess ist ziemlich umständlich. Um Headerdateien unter external/ einzubringen, gehe ganz sicher, dass diese dann auch in external/prj/d.lst aufgelistet sind, sodass sie beim Builden in das solver/641/unxlngi4.pro/inc/external Verzeichnis kopiert werden.

### 8.6. Beim Hacken die richtige Datei finden

Einen Programmfehler zu beheben, oder anderes, kann schon einige Zeit durch den OOo Dateiendschungel in Anspruch nehmen. Oft gibt es einen Verweis zu einem GUI Element in unmittelbarer Nähe, wo du gerade suchst. Finde also so einen String und suche mit LXR's Text Suche, das sollte dann einen Identifier zum String enthüllen, wie z.B. SID_AUTOFORMAT oder FN_NUM_BULLET_ON. Nachdem du diesen herausgefunden hast, starte eine neue Suchanfrage und du wirst die Benutzung, oder sogar Definition/Deklaration des betreffenden Identifiers finden.

## 9. Nützliche Links

### 9.1 www.openoffice.org

Während das meiste des openoffice.org Portals nicht wirklich Hacker-orientiert ist, gibt es trotzdem einiges an Dokumentation für das Thema, du musst nur danach suchen. Die Tools-Projektseite schließt z.B. das richtige Kompilieren und Builden mit verschiedenen Compilern auf verschiedenen Plattformen ein.

ooodocs.org ist zwar nun seit einiger Zeit ein wenig veraltet, bietet jedoch trotzdem einiges an nennenswerten Informationen.

Persönlich kann ich das oooforum empfehlen, eines der wohl aktivsten Support-Forums im OpenSource Bereich.

Andere verwandte Seiten sind: OOODI ein Gtk+ Bibliotheken Installierer. OOExtras bietet Templates, Macros und Clip Art. Quickstart applet für GNOME (und KDE). Dictionaries & Docs von Kevin Hendricks.

Seit kürzerer Zeit - genauer genommen seit Sun versprach eine neue CWS-Regelung zu erschaffen, um es für außenstehende einfacher zu machen ein bestimmtes Feature für OOo zu entwickeln - gibt es auch den EIS-Service, in dem CWSs (Plural !) organisiert werden können. Für nähere Informationen, kann ich nur die speziellen Präsentationen der OOo Konferenz 2004 empfehlen.

### 9.2 Patch Archiv

Während viele verschiedene Versionen von OOo produziert werden, sind viele Projekte in der letzten Zeit mit eigenen beeindruckend großen Patch-Zusammenstellungen für OOo hervorgekommen.

- Ximians OOo Patche and Build-Werkzeuge / Snapshots sind als Pakete oder Patche verfügbar.

- Debians hilfreiche OOo Seite, mit diversen Patchen. Und Debians CVS.

- Mandrakes OOo Patch Archiv.

- FreeBSDs OOo Port-Patche.

- Red Hats .spec Datei (basierend auf Mandrake) ist auch Wert zu lesen: von ihrer SRPM Seite

- Leute, die OOo lokalisieren wollen, können diese Patche von Pavel Janik studieren.

## 10 (F)AQ

Warum (F)..? Nunja, der gute Michael hat sich die folgenden Fragen eher selbst gestellt.

### 10.1 Wieso enthalten Zweignamen, wie 'mws_srx644', ungerade Zahlen?

Theoretisch erhöht sich die Nummer wöchentlich und da wöchentlich "Freezes" vollzogen werden, gibt es auch wöchentliche Solver und Entwicklungsumgebungen. Wie auch immer, seit kürzester Zeit nimmt das Auskristallisieren eines einzigen Buildes mehr Zeit als eine Woche in Anspruch - das führt dann zum Dilemma der gemischten alphanumerischen "Versionstags". Das 'mws' steht für 'Master Workspace'.

### 10.2 Wieso wird Java unbedingt für einen Build gebraucht ?

Essenziell sieht es so aus, als seien, neben unterschiedlichen anderen Services, eine Menge an XML Dateien an der Komponentenregistration beteiligt. Es scheint so zu sein, dass dieser Prozess am einfachsten mit Java zu vollziehen ist. Hinzu kommt, dass Java effizient während der Run-Time benutzt werden kann.

Von "Tag" SRC680_m44 an gibt es nun jedoch eine Alternative (geschrieben in Python), um das Problem des Analysierens der XML Dateien und hauptsächlich ihrer Registration zu addressieren, sodass es also möglich sein sollte nach m44 den Build ohne Java hinzubekommen.

### 10.3 Was zum Teufel ist mit [t]csh los?

Ganz einfach, csh funktioniert schlicht und einfach nicht richtig. "Warum?" ist natürlich die große Frage und soweit ich es weiß hängt es mit der speziellen Art zusammen, wie die Piping-Befehle für stdin verlaufen, nämlich ganz anders als von tty ausgehend:

    echo 'echo #define DLL_NAME "libsch641li.so" >./foo.hxx' | /bin/tcsh -s

Das ganze schlägt normalerweise Fehl, wobei es beim direkten Schreiben in die Shell jedoch funktioniert,

    tcsh -fc 'echo #define DLL_NAME "libsch641li.so" >./foo.hxx'

bringt das erwünschte Ergebnis. Siehe auch csh.

### 10.4 Ich habe gerade versucht den Build woanders zu lokalisieren, wieso schlägt es nun Fehl ?

Die verblüffende Antwort ist..... du musst

    bin/relocate /path/to/new/build

ausführen. Eine andere Antwortweise wäre um einiges länger:

Wenn davon ausgegangen wird, dass du die nötigen Dinge neu konfiguriert hast (auch LinuxIntelEnv.Set wird Rumbasteln der Pfade brauchen und in die Shell reimport werden müssen) - dann liegt das Problem wohl an den absoluten Pfaden, die vor allem in '.dpc*' vorkommen. Versuche:

    find -name '*.dpc*' -exec rm {} \;

Der stlport schwächelt in einigen Dingen, sodass du also auch 'stl_gcc.h' innerhalb des solver/ Verzeichnisses editieren und die dortigen beiden Pfad-Erwähnungen ersetzen musst (siehe inc/stl/config/stl_gcc.h).

### 10.5 CVS sagt 'Fatal Error aborting. [acc] no such user', wieso das denn jetzt ?

Während es natürlich möglich ist, dass dein Username nicht registriert ist, meint es oftmals jedoch dass deine ~/.cvspass Datei verschwunden ist und/oder, dass du dich nicht eingeloggt hast. cvs login, daraufhin wiederhole den Befehl.

### 10.6 Was habe ich unter '.pro' in 'unxlngi4.pro' zu verstehen ?

Product - ist das nicht offensichtlich? :-)

### 10.7 Wie ist OpenOffice intern aufgebaut ?

### 10.8 Wie nehme ich einen Screenshot von OOo auf ?

Manche konventionelle Screenshot Programme bekommen keine scharfen Bilder auf die Reihe, weil OOo manche recht komische Dinge mit den X Resourcen anstellt. ImageMagicks 'import' sollte jedoch seinen Zweck erfüllen, benutze:

    import foo.png

von der Konsole, oder stattdessen

    sleep 2; import -window root foo.png

. Es sei denn du willst deine "Welt" klein aussehen lassen, solltest du die "Toolbar icons" vorher auf groß stellen, versteht sich.

### 10.9 Meine prefix Option beinhaltet "BUILD", wieso schlägt der Build Fehl?

Das hängt wieder mal mit unserem stlport zusammen, diesmal aber wirklich ein krummes Ding. Im Grunde genommen kommt es hier zum Überschreiben einer Headerdatei und sie (denkt dir selbst, wer das sein könnte) wollen sich die Option freihalten zum vorigen Header - mit dem selben Namen - zurückfallen lassen zu können. Deswegen müssen die Pfade hart kodiert werden. Um sich das an vielen Plätzen zu ersparen, benutzen sie einen #define mit Macro Expansion. Wenn deshalb deine gcc prefix ein Element enthält, was auch ein Macro ist - kommt es knüppelhart:

stlport config header:

    #define _STLP_NATIVE_INCLUDE_PATH \
            /home/michael/ximian-desktop/ooo/BUILD/ooo/include/c++/3.2.2

stlport nützliche Macros:

    # define _STLP_MAKE_HEADER(path, header) <path/header>
    # define _STLP_NATIVE_CPP_C_HEADER(header)  \
            _STLP_MAKE_HEADER(_STLP_NATIVE_INCLUDE_PATH,header)

und schließlich stlport`s schlaue Einbeziehung (=include directive):

    #include _STLP_NATIVE_CPP_C_HEADER(foo)

Resultat:

          g++ ... -DBUILD=7663 ...
          ...
    from /home/michael/ximian-desktop/ooo/BUILD/ooo/OOO_1_0_2/xml2cmp/source/xcd/main.cxx:62:
    /home/michael/ximian-desktop/ooo/BUILD/ooo/OOO_1_0_2/solver/641/unxlngi4.pro/inc/stl/cstddef:35:46:
    /home/michael/ximian-desktop/ooo/7663/ooo/include/c++/3.2.2/cstddef: No such file or directory

### 10.10 Für was ist die UNO-Komponentendoku in XML da?

Nicht viel. Obwohl es durchaus von Wert ist, diese mal runterzuladen, wird ihr zur Zeit jedoch sogut wie überhaupt keine Beachtung geschenkt.

###

## 11. Mit uns arbeiten

Siehe das About ooo-build Dokument an (englisch).

auf deutsch übersetzt von Christian Junker °v0.8°