Forum: PC-Programmierung Dokumentation mit Doxygen


von Andi K. (fry12)


Lesenswert?

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
enum sensor_address {
3
    SENSOR_ADDRESS0 = 0x1,
4
    SENSOR_ADDRESS1 = 0x4,
5
    ...
6
}
7
#endif
8
9
#ifdef __SENSOR1
10
enum sensor_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! :)

: Bearbeitet durch User
von Steffen R. (steffen_rose)


Lesenswert?

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)

von Andi K. (fry12)


Lesenswert?

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 ;)

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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
void TIMER1_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.

von MaWin (Gast)


Lesenswert?

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.

von Steffen R. (steffen_rose)


Lesenswert?

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.

von Andi K. (fry12)


Lesenswert?

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?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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:
1
#ifdef DOXYGEN
2
enum sensor_address_SENSOR0 {
3
   ...
4
};
5
enum sensor_address_SENSOR1 {
6
   ...
7
};
8
#else /* !DOXYGEN */
9
#  ifdef SENSOR0
10
enum sensor_address {
11
    SENSOR_ADDRESS0 = 0x1,
12
    SENSOR_ADDRESS1 = 0x4,
13
    ...
14
}
15
#  endif
16
17
#  ifdef SENSOR1
18
enum sensor_address {
19
    SENSOR_ADDRESS0 = 0x1,
20
    SENSOR_ADDRESS2 = 0x5,
21
    ...
22
}
23
#  endif
24
#endif /* DOXYGEN */

Aber ob das wirklich so sinnvoll ist?

von Andi K. (fry12)


Lesenswert?

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!

von Stephan (Gast)


Lesenswert?

Sorry, ich habs noch nicht ganz verstanden was der TO will, aber lt. der 
Doku
kann man doch die Enums Values einzeln beschreiben:

http://www.stack.nl/~dimitri/doxygen/manual/commands.html#cmdenum
1
class Test
2
{
3
  public:
4
    enum TEnum { Val1, Val2 };
5
};
6
7
/*! \var Test::TEnum Test::Val1
8
 * The description of the first enum value.
9
 */

und das kann er doch auch:
1
#ifdef __SENSOR0
2
enum sensor_address {
3
    SENSOR_ADDRESS0 = 0x1, /*!< value 1 */
4
    SENSOR_ADDRESS1 = 0x4, /*!< value 4 */
5
    ...
6
}
7
// oder indirekt:
8
/*! \var sensor_address SENSOR_ADDRESS0
9
 * The description of the first enum value.
10
 */
11
#endif
12
13
#ifdef __SENSOR1
14
enum sensor_address {
15
    SENSOR_ADDRESS0 = 0x1, /*!< value 1 */
16
    SENSOR_ADDRESS2 = 0x5, /*!< value 5 */
17
    ...
18
}
19
#endif

leider nicht getestet, aber möglich oder?

von Oliver (Gast)


Lesenswert?

Ich würde das 2-stufig machen, etwa so:
1
enum sensor0_address {
2
    SENSOR0_ADDRESS0 = 0x1,
3
    SENSOR0_ADDRESS1 = 0x4
4
};
5
6
enum sensor1_address {
7
    SENSOR1_ADDRESS0 = 0x1,
8
    SENSOR1_ADDRESS2 = 0x5
9
};
10
11
#ifdef __SENSOR0
12
enum sensor_address {
13
    SENSOR_ADDRESS0 = SENSOR0_ADDRESS0,
14
    SENSOR_ADDRESS1 = SENSOR0_ADDRESS1
15
};
16
#endif
17
18
#ifdef __SENSOR1
19
enum sensor_address {
20
    SENSOR_ADDRESS0 = SENSOR1_ADDRESS0,
21
    SENSOR_ADDRESS2 = SENSOR1_ADDRESS2
22
};
23
#endif

Oliver

von Sven (Gast)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.