Hallo Leute!
Ich bin gerade dabei mich ein wenig in Doxygen einzuarbeiten und hoffe,
dass ihr mir bei einem kleinen Problem helfen könnt.
Das Stichwort lautet bedingtes Kompilieren. Ich habe ein kleines
Programm (für einen Mikrocontroller geschrieben), das mit einem Sensor
per SPI kommuniziert. Es gibt verschiedene Sensortypen, die jeweils ein
klein wenig unterschiedlich sind. Unter anderem haben sie
unterschiedliche Register.
80% der Register sind jedoch bei allen Varianten identisch.
Mein Programm soll jedoch alle Sensortypen unterstützen. Der
entsprechende Typ wird vor dem Compilen per Präprozessoranweisung
definiert, bspw.
1
#define __SENSOR0
Die Registeradressen sind in Enumerations definiert. Je nach Sensortyp
wird durch die vorherige Präprozessor-Definition die korrekte Version
ausgewählt, also nach dem Schema:
1
#ifdef __SENSOR0
2
enumsensor_address{
3
SENSOR_ADDRESS0=0x1,
4
SENSOR_ADDRESS1=0x4,
5
...
6
}
7
#endif
8
9
#ifdef __SENSOR1
10
enumsensor_address{
11
SENSOR_ADDRESS0=0x1,
12
SENSOR_ADDRESS2=0x5,
13
...
14
}
15
#endif
Ich habe das bewusst nicht nach dem Schema
1
#ifdef __SENSOR0
2
...
3
#elif defined __SENSOR1
angelegt, da sonst der in Doxygen integrierte Präprozessor nur ein enum
auswählt und den Rest weg lässt (per PREDEFINED sind __SENSOR0 und
__SENSOR1 gleichzeitig definiert).
Das klappt alles soweit ganz gut, d.h. alle enums sind in der
HTML-Dokumentation zu sehen.
Das Problem: Bei jedem enum sind ALLE Adressen zu sehen, d.h. bezogen
auf obiges Beispiel würde jetzt bei "enum sensor_address" immer
SENSOR_ADDRESS0, SENSOR_ADDRESS1, SENSOR_ADDRESS2, ... stehen, egal ob
ich an der Stelle des ersten enums oder des zweiten enums bin.
Kann dieses Verhalten verhindert werden? Falls nicht, welche andere
Möglichkeit gibt es, das ganze sauber zu dokumentieren? Ich möchte
eigentlich nur ungern große Änderungen am Quellcode vornehmen, nur um
ihn per Doxygen besser dokumentieren zu könnnen.
Schon einmal Vielen Dank im voraus! :)
Was soll Doxygen ausgeben, wenn SENSOR_ADDRESS0 für Sensor 0 und 1
unterschiedlich wäre?
Alternativen:
- getrennte Dokumentation für die jeweiligen Sensoren
- Dummysensor mit allen Werte speziell für die Dokumentation
(ggf. speziell für diese relevanten Stellen ein zusätzliches Define
auswerten)
Unterschiedlich sind sie ja in keinem Fall, der Unterschied liegt nur
darin, dass es entweder zusätzliche Register(-adressen) oder weniger
sind.
Was meinst du mit getrennte Dokumentationen? Wie kann ich das einbauen?
Bin wie gesagt ganz neu in Sachen Doxygen ;)
Nur nebenbei, __SENSOR0 liegt im implementation namespace, ist also
für dich in einem Anwendungsprogramm tabu.
Sinnvoller als deine Methode hat es sich für uns erwiesen, solche
#ifdefs so zu gestalten:
1
#if defined(FEATURE1) || defined(DOXYGEN)
2
...
3
#endif
und dann im Doxyfile den Makro DOXYGEN vorzudefinieren. Damit kannst
du klar und deutlich ausdrücken, welche Teile des Codes halt für die
Dokumentation sichtbar sein sollen (und andere dafür nicht sichtbar
zu lassen), selbst sowas geht:
1
#if defined(DOXYGEN)
2
voidTIMER1_vect(void);
3
#else /* real code */
4
ISR(TIMER1_vect)
5
#endif
6
{
7
// implement timer1 ISR here
8
}
d. h. für die Dokumentation wird eine lesbarere Variante dargestellt
als tatsächlich implementiert werden muss.
Andi K. schrieb:> as Problem: Bei jedem enum sind ALLE Adressen zu sehen, d.h. bezogen> auf obiges Beispiel würde jetzt bei "enum sensor_address" immer> SENSOR_ADDRESS0, SENSOR_ADDRESS1, SENSOR_ADDRESS2, ... stehen, egal ob> ich an der Stelle des ersten enums oder des zweiten enums bin.>> Kann dieses Verhalten verhindert werden?
enum sensor_address {
SENSOR_ADDRESS0 = 0x1,
#ifdef __SENSOR0
SENSOR_ADDRESS1 = 0x4,
#endif
#ifdef __SENSOR1
SENSOR_ADDRESS2 = 0x5,
#endif
...
}
?!?
Sollte doch funktionieren, obwohl meine Donxygen Zeit länger her ist und
ich dieses Tool dank seiner Fehler und Unmöglichkeiten hasse.
Andi K. schrieb:> Was meinst du mit getrennte Dokumentationen? Wie kann ich das einbauen?
Für jeden Sensor ein eigenes Doxyfile mit den jeweiligen Settings für
den entsprechenden Sensor.
Ich denke aber, dass die von Jörg Wunsch beschriebene Methode sinnvoller
ist, da du schreibst, dass es viele Gemeinsamkeiten gibt.
Jörg Wunsch schrieb:> Nur nebenbei, __SENSOR0 liegt im implementation namespace, ist also> für dich in einem Anwendungsprogramm tabu.
Sorry, kannst du mir das nochmal erklären? Bin noch nicht so firm in
Sachen programmieren ;-)
Deine Methode ist gut, nur war das nicht genau mein Anliegen. Effektiv
kommt dabei das gleiche heraus, wie wenn ich schreibe
1
#ifdef _FEATURE0
2
...
3
#endif
4
5
#ifdef _FEATURE1
6
...
7
#endif
und jeweils _FEATURE0 und _FEATURE1 vordefiniere. Ich möchte aber (um
nochmal auf mein Eingangsbeispiel mit den Adressen zurück zu kommen),
dass Doxygen für alle enums, die die Adressen enthalten, einen eigenen
Abschnitt erzeugt, der nur die entsprechenden Adressen und deren
Erklärungen enthält. Bis jetzt werden zwar drei Abschnitte (ich habe
drei verschiedene enums) erzeugt, jedoch steht in jedem Abschnitt jede
Adresse und nicht nur die Adressen, die auch im Code tatsächlich im enum
stehen.
Das liegt vermutlich daran, dass die enums alle gleich heißen
(sensor_address) und alle gleichzeitig definiert sind. Daher nochmal
meine Frage: Gibts da eine geschickte Möglichkeit, das Ganze so
aufzuteilen, dass nur die passenden Adressen samt Erklärungen in den
Abschnitten stehen?
(ich hoffe das war einigermaßen verständlich ausgedrückt ;-))
Ich vermute mal, dass das so ohne Weiteres nicht möglich ist und eher
der Aufbau des Codes an sich geändert werden müsste, oder?
Andi K. schrieb:> Jörg Wunsch schrieb:>> Nur nebenbei, __SENSOR0 liegt im implementation namespace, ist also>> für dich in einem Anwendungsprogramm tabu.>> Sorry, kannst du mir das nochmal erklären?
Lass einfach die Finger von Bezeichnern, die mit zwei Unterstrichen
oder mit einem Unterstrich, gefolgt von einem Großbuchstaben beginnen,
es sei denn, die Dokumentation deines Compilers oder deiner
Systembibliothek fordert dich ausdrücklich dazu auf, diese in
irgendeiner Form zu benutzen.
Compiler und Bibliothek dürfen derartige Namen nämlich intern
benutzen, und diese Benutzung könnte dann mit deinen Intentionen
kollidieren.
> Das liegt vermutlich daran, dass die enums alle gleich heißen> (sensor_address) und alle gleichzeitig definiert sind.
Ja, wie soll sie das Doxygen denn dann auseinanderhalten? Die
Intention dort ist doch, dass du in der HTML-Doku auf den Namen
klicken kannst und dann zur Definition gelangst.
> Daher nochmal> meine Frage: Gibts da eine geschickte Möglichkeit, das Ganze so> aufzuteilen, dass nur die passenden Adressen samt Erklärungen in den> Abschnitten stehen?
Du kannst meine Methode natürlich soweit ausweiten, dass du für den
Doxygen-Fall Fake-Namen für die enums vergibst, damit sie alle
voneinander verschieden sind. Also etwa:
Jörg Wunsch schrieb:> Lass einfach die Finger von Bezeichnern, die mit zwei Unterstrichen> oder mit einem Unterstrich, gefolgt von einem Großbuchstaben beginnen,> es sei denn, die Dokumentation deines Compilers oder deiner> Systembibliothek fordert dich ausdrücklich dazu auf, diese in> irgendeiner Form zu benutzen.>> Compiler und Bibliothek dürfen derartige Namen nämlich intern> benutzen, und diese Benutzung könnte dann mit deinen Intentionen> kollidieren.
Okay, das wusste ich nicht. Dann werde ich das besser abändern, vielen
Dank!
Jörg Wunsch schrieb:> Du kannst meine Methode natürlich soweit ausweiten, dass du für den> Doxygen-Fall Fake-Namen für die enums vergibst, damit sie alle> voneinander verschieden sind.
Das wäre eine Möglichkeit. Aber wie du schon sagst, sinnvoll ist das
vielleicht nicht. Ich denke das würde dann zu unübersichtlich werden.
Vielen Dank für eure Hilfe!
Frage dich doch mal, ob es sinnvoll ist, die konkreten Enum-Werte in der
Doku zu haben? Mich als Anwender der Lib würde das relativ wenig
interessieren, welche konkreten Werte dahinter stehen und wenn, dann
würde ich im Source-Code nachsehen. Das ist ja auch der Sinn einer Enum.
Daher fände ich es ausreichend, wenn du für Doxygen eine eigene Enum
deklarierst und diese dann mit einem sauberen Kommentar versiehst.
In C++ würde ich dir vorschlagen, das in jeweils eigene namespaces zu
packen und am Ende eine using deklarative zu nutzen.