Doxygen für MatLab benutzen

MatLab’s eingebaute Dokumentationswerkzeuge sind … unzureichend.

Deswegen habe ich mich für meine Bachelor-Thesis nach anderen Werkzeugen umgesehen, da Dokumentation von Quellcode für mich ein wesentlicher Bestandteil wissenschaftlichen Arbeitens ist — sollen andere doch schließlich auf der eigenen Arbeit aufbauen.

Bekannte Vertreter sind Doxygen und Sphinx neben anderen. Für Doxygen hat jemand ein Paket geschnürt, dessen Anwendung Thema dieses Artikels sein soll.

Doxygen 1.5.8
Flickr: Doxygen von Mehdi Kabab
(CC BY-NC-SA)

Grob gegliedert erkläre ich Folgendes:

  1. Anpassen des Paketes an GNU/Linux-Systeme
  2. Anpassen der Konfigurationsdatei
  3. Anpassungen im Quellcode eurer MatLab-Dateien

Anpassen des Paketes an GNU/Linux-Systeme

Das Paket wird heruntergeladen und entpackt. Ich hab mir persönlich eine Kopie in mein Arbeitsverzeichnis geschoben.

Unter GNU/Linux muss dann zunächst die Shebang angepasst werden, d.h. m2cpp.pl in einem Editor öffnen und
#!/usr/bin/perl.exe in #!/usr/bin/perl umwandeln, anschließend ausführbar machen mit chmod u+x m2cpp.pl.

Dann wirft die Shell eine Fehlermeldung wegen bad interpreter. Wie sich an der Shebang schon ablesen lässt, wurde das Script für ein Windows-System geschrieben. Demnach besitzt es nicht nur ein LineFeed am Zeilenende, sondern auch ein CarriageReturn. In Vim lässt es sich am ^M erkennen, wenn die Ansicht mit :e ++ff=dos umgestellt wurde. Wenn ihr den Artikel eh schon offen habt, könnt ihr auch nachlesen, wie sich das Problem in Vim lösen lässt. Alle anderen lassen dos2unix drüber laufen 🙂

Anpassung der Konfigurationsdatei

Nachdem das geklärt wurde geht’s an’s Doxyfile. Dies ist die Konfigurationsdatei, nach der sich doxygen bei der Arbeit richtet. Wer eine graphische Oberfläche braucht, greift zum doxywizard.

Ein paar Einstellungen müssen auch dort angepasst werden:

  • Projektnamen anpassen: PROJECT_NAME = Bachelorthesis
  • Zielverzeichnis anpassen: OUTPUT_DIRECTORY = ../../../doc/ – meiner Beobachtung nach richtet sich der Pfad nach dem Speicherort des Doxyfiles.
  • Sprache anpassen: OUTPUT_LANGUAGE        = German
  • Pfad-Abschnitte aus der Doku herausschneiden (lies Pfad zum Arbeitsverzeichnis angeben): STRIP_FROM_PATH        = /home/username/src/Bachelorthesis/ – ich weiß nicht, ob Doxygen Umgebungsvariablen wie $HOME auswerten kann.
  • Tabgröße anpassen: TAB_SIZE               = 4
  • Aliase definieren, beispielsweise für Lizenz: ALIASES                = license=@copyright
    • Alternativ kann die Lizenz auch in einen eigenen Abschnitt umgewandelt werden: license=@par Lizenz\n
    • Hier definiert ihre neue Doxygen-Anweisungen (bspw. @license) 😉
  • Ganz wichtig: Dateiendungen aufeinander abbilden: EXTENSION_MAPPING      = m=C++ – Damit behandelt Doxygen .m-Files wie .cpp-Dateien. Optional kann auch der Punkt vor dem m angegeben werden.
  • Die restlichen Angaben könnt ihr selber entscheiden. Ich find den doxywizard ausnahmsweise einmal ganz brauchbar, auch wenn die Benutzerführung noch stark verbessert werden könnte. Vergesst das Speichern dort nicht 😉

Anpassungen im Quellcode eurer MatLab-Dateien

Nachdem jetzt also das Programm eingerichtet ist, geht es an euren Quellcode. Wie der Paket-Autor beschrieben hat, können MatLab-Kommentare (%) neben Doxygen-Kommentaren (%>) stehen. Einziger Haken: Die Doxygen-Doku muss vor dem Funktionskopf stehen und wird damit auch in help eureFunktion angezeigt.

Vergesst nicht, dass MatLab Probleme mit nicht-ASCII-Zeichen bekommen kann. Insbesondere, wenn ihr den Quellcode in LaTeX einbinden wollt, empfiehlt es sich, auf Umlaute und dergleichen zu verzichten 😦

Einige Anregungen, wie so eine Doku aussehen kann:

%> @brief Short explanation of what this class represents
%> @todo Write unit tests
%> @author Andre Jaenisch
%> @version 0.0.1
%> @date 11th September 2014
%> @license
%> Eiffel Forum License v2,
%> http://www.eiffel-nice.org/license/
classdef MyClass
    %> @property
    properties
        %> What does this property represents?
        coolProperty;
    end % properties

    %> @private
    %> @property
    properties (SetAccess = private)
    %> Defaults to 'secret'
        dareYou = 'secret';
    end % private properties

    %> @name Private and Abstract
    %> These members are private and abstract, that is, their value
    %> is calculated at access time.
    %> @{
    %> @private
    %> @property
    properties (Dependent = true, SetAccess = private)
        mySecret;
    end % private, dependent properties
    %> @}

    methods
        %> @param cp Double. Here goes the description
        %> @param s  String. Another parameter
        %> @note inputParser would be handy here instead of nargin
        %> @todo Add optional parameters
        function myclass = myClass(cp, s)
            if nargin > 0
                myclass.coolProperty = cp;
                myclass.dareYou      = s;
            end
        end % myClass Constructor

        %> @param obj self, i.e. myClass instance
        %> @return
        %> Prints properties to STDOUT
        function disp(obj)
            msg = ['%s:\n', ...
                   '- coolProperty: %d\n', ...
                   '- dareYou: %s\n'];
            fprintf(msg, 'These are the properties of myClass', ...
                          obj.coolProperty, obj.dareYou)
        end % disp

        %> @param obj self, i.e. myClass instance
        %> @implements myClass.mySecret
        %> @retval myClass.mySecret
        function mySecret = get.mySecret(obj)
            mySecret = someStrangeFunctionWith(obj.mySecret);
        end % get.mySecret

        %> @param obj self, i.e. myClass instance
        %> @param ignoredArg Ignored
        %> @throw Exception You cannot set mySecret directly!
        function obj = set.mySecret(obj,~)
            error('%s\n', 'You cannot set mySecret directly!');
        end % set.mySecret
    end % methods
end % classdef

Ein paar Anmerkungen: MatLab hat ein ganz komisches Verständnis von OOP, wenn es um das Überschreiben von Getter und Setter in geerbten Klassen geht.

Das Perl-Script wandelt ~ in ignoredArg um, weswegen sich Doxygen beschwert, wenn ihr diesen Parameter nicht dokumentiert. Ich hab das Script noch nicht gehackt (Perl X_x), um nachzuvollziehen, warum ~ nicht einfach beibehalten werden konnte … oder gleich ganz ignoriert werden kann.

Den Rest findet ihr sicher auch alleine raus. Denkt nur daran, bei der offiziellen Doku \ durch @ zu ersetzen und ab dafür 😉

Ich finde es nur schade, dass keine Instanz-Variablen dokumentiert werden können. myClass::disp und myClass#disp sind beides Auszeichnungen für statische Methoden und myClass.coolProperty ist Eigenschaften vorbehalten. C++ würde ja eigentlich myClass->disp für eine Instanz-Methode benutzen …

Die Konvention mit dem . beißt sich übrigens derbe mit MatLab’s Syntax für Getter und Setter

Mindestens würde ich gerne Typ und Name der Parameter einer Funktion sowie des Rückgabe-Wertes dokumentieren. Auf keinen Fall sollte Doxygen den Funktionskörper auswerten. Anhand der Dokumentation kann auch der Test geschrieben werden (oder anders herum).

Wo ich noch Nachhol-Bedarf habe sind Unit-Tests und das Definieren eigener Fehler-Klassen. Der Style-Guide und das Wikia sind auch gute Ressourcen.

Ach ja, falls euer Doxygen sich über @abstract beklagt … das hab ich auch selber definiert als abstract=\xrefitem abstract \"Abstract\" \"Abstracts\" (Quoting ist wichtig, siehe \xrefitem). Eigentlich ist @pure dafür gedacht, aber das traf nicht meinen Anforderungen.

Advertisements

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s