Forum: Mikrocontroller und Digitale Elektronik Extrahieren eines Teil-Strings aus einer Konstanten


von Werz (Gast)


Lesenswert?

Hallo,

ich verwende folgende Konstante:
1
#define SVNVERSION "$Revision: 214 $"

damit die SVN Revision bei jedem Update automatisch auch im Code 
upgedated wird (Die Revision wird auf einem User interface angezeigt).

Ich muss aber den tag "$Revision:$" verwenden, damit hier immer die 
Version upgedated wird (im Beispiel oben wurde beim letzten Update die 
Nummer 214 eingefügt).

Ich will aber nun nur den String 214 anzeigen, nicht den gesamten mit 
"$...$". Wie kann ich das aus einer Konstanten extrahieren?

von Sascha W. (sascha-w)


Lesenswert?

Hallo,

du musst SVNREVISION einem Chararray zuweisen und dann den Teil kopieren 
den du brauchst. Mit deiner Zeile oben und nur an dieser Stelle wird der 
String in deinem Programm nicht enthalten sein.
Vielleicht kann man auch mit dem Preprozessor schon den relevanten Teil 
rausscheiden, da kenne ich mich aber nicht aus.

Sascha

von Stefan F. (Gast)


Lesenswert?

1
#include <stdio.h>
2
#include <string.h>
3
4
#define SVNVERSION "$Revision: 214 $"
5
6
int main(int agrc, char**argv)
7
{
8
    // Definition ins RAM kopieren
9
    char svnversion[] = SVNVERSION;
10
    
11
    // Die letzen beiden Zeichen abschneiden (ende-Markierung setzen)
12
    svnversion[sizeof(svnversion)-2] = '\0';
13
    
14
    // Auf die Nummer hinter dem Anfang der Zeichenkette zeigen
15
    char* zeiger = svnversion+11;
16
    
17
    // Nummer ausgeben
18
    puts(zeiger);
19
    
20
    return 0;
21
}

Ausgabe:
1
214

Achtung: sizeof() funktioniert hier nur deswegen, weil die Größe des 
Arrays schon zur Compile-Zeit feststeht, da SVNVERSION eine bekannte 
Länge hat (die ändert sich nach dem Compilieren nicht mehr).

Wenn du das mit einem String machen willst, dessen Länge erst zur 
Laufzeit bekannt wird, musst du stattdessen strlen() benutzen. strlen() 
ist langsamer.

von Werz (Gast)


Lesenswert?

Perfekt, ich habe es jetzt so gemacht:
1
#define SVNVERSION "$Revision: 215 $\0"

wobei die Zahl 215 immer automatisch bei jedem SVN Commit upgedated 
wird.

Dann:
1
char SVNVersion[] = SVNVERSION;
2
char FWVersion[30] = "SVN                          \0"
3
4
for(uint8_t i = 3; i<=7; i++)
5
{
6
     FWVersion[i] = SVNVersion[i+7];
7
}

Außer dass es etwas umständlich ist, seht ihr hier irgendeinen Fehler im 
Stringhandling etc?

von H.Joachim S. (crazyhorse)


Lesenswert?

Werz schrieb:
> char FWVersion[30] = "SVN                          \0"

\0 brauchst du nicht, wird automatisch eingefügt am Ende.
[30] auch unnötig, überlass es dem Compiler:
char FWVersion[] = "SVN                          "

Ansonsten: für sowas gibt's die Funktionen strncpy.

von Werz (Gast)


Lesenswert?

Danke fürs Feedback!

Komischerweise funktioniert nun das automatische Update der Version 
nicht mehr... D.h. die Zeile bleibt gleich:
1
#define SVNVERSION "$Revision: 215 $"
bleibt gleich, auch wenn ich ein neues SVN Update mache. Vorher hat es 
noch funktioniert :(

Kennt sich jemand damit aus? Woran könnte das liegen?

Danke

von Johannes S. (Gast)


Lesenswert?

Das #define im Code weglassen, das sollte doch nur zum testen sein. Das 
muss „von außen“ durch das Buildsystem gesetzt werden.

von Peter D. (peda)


Lesenswert?

1
#define SVNVERSION_NO "214"
2
#define SVNVERSION "$Revision: " SVNVERSION_NO " $"

von my2ct (Gast)


Lesenswert?

Werz schrieb:
> ich verwende folgende Konstante:
> #define SVNVERSION "$Revision: 214 $"

Damit definiert du eine Textersetzung, die der Preprozessor ausführt, 
mehr nicht.

von Werz (Gast)


Lesenswert?

Yes, danke!!

jetzt funktioniert es damit:
1
char SVNVersion[] = "$Revision: 220 $";

von Hugo H. (hugohurtig1)


Lesenswert?

Werz schrieb:
> jetzt funktioniert es damit:char SVNVersion[] = "$Revision: 220 $";

Zeig mal bitte den Code und vergleiche mit dem Vorschlag von

Peter D. schrieb:
> #define SVNVERSION_NO "214"
> #define SVNVERSION "$Revision: " SVNVERSION_NO " $"

: Bearbeitet durch User
von Werz (Gast)


Lesenswert?

Codezeile siehe oben, damit funktioniert es auch...

Allerdings gibt es noch ein Problem:

Ich habe in EINEM SVN repository mehrere Projekte, weil das 
Gesamtprojekt aus mehreren Teilprojekten besteht. Wenn ich nun in dem 
Projekt, in dem die Codestelle:
1
char SVNVersion[] = "$Revision: 220 $";
steht, etwas ändere, dann einen SVN Commit mache, dann wird die Revision 
auch korrekt upgedated.

Wenn ich aber in einem anderen projekt dieses Repositories etwas ändere, 
das commite (dann wird die "HEAD Version" erhöht, die Version des 
ursprünglichen Projekts, indem die o.a. Codestelle steht, aber nicht), 
dann bleibt die Version gleich.

Gibt es irgendeine Möglichkeit, die "HEAD Version" abzudaten?

Danke :)

von Hugo H. (hugohurtig1)


Lesenswert?

Werz schrieb:
> Codezeile siehe oben, damit funktioniert es auch...

Umständlich.

von Werz (Gast)


Lesenswert?

Update, mein letzter Eintrag ist nicht ganz korrekt:
Mit dem Schlüsselwort "Revision" wird nur die letzte Version DIESES 
Files angezeigt, in dem das Schlüsselwort steht. Wenn ich aber in einem 
anderen File des Projektes etwas ändere, dann ändert sich die HEAD 
Revision, nicht aber die Version dieses Files.

Ich würde aber gerne immer die Head Revision automatisch anzeigen, weil 
dies auch dem letzten SW Stand des Projektes entspricht, der SW Stand, 
der dem User angezeigt wird, soll ja schließlich auch der sein, der dem 
Gesamtprojekt entspricht.

Ich habe danach gegooglet und kann einfach nicht glauben, dass es dafür 
keine Lösung gibt, das muss doch ein häufiger Anwendungsfall sein, dass 
die SW Version des Gesamtprojektes immer upgedated und angezeigt wird?!

Weiß jemand ob und wie das funktioniert?

DANKE!!!

von Walter T. (nicolas)


Lesenswert?

Werz schrieb:
> Weiß jemand ob und wie das funktioniert?

subwcrev.exe

von Stefan F. (Gast)


Lesenswert?

In Java Projekten benutzt man dazu ein Plugin für den Maven Build 
Prozessor. Er fragt die Revisionsnummer des Projektes beim Source 
Repository ab und ersetzt dann in irgendeiner Datei einen entsprechenden 
Platzhalter.

Ich denke, so etwas in der Art wirst du wohl auch brauchen.

In C bietet es sich an, keine Platzhalter zu benutzen, sondern sie als 
gcc Parameter (-D) anzugeben. Im Quelltext kannst du solche Definitionen 
dann genau so benutzen, als seien sie mit #define definiert worden:
1
#include <stdio.h>
2
3
int main(int argc, char** argv)
4
{
5
    puts(SVNVERSION);
6
}

Compilieren:
1
stefan$ gcc -D 'SVNVERSION="1234"' test.c
2
stefan$ ./a.out

Ausgabe:
1
1234

von Werz (Gast)


Lesenswert?

Danke für Eure Beiträge.

Ich finde es echt komisch, dass dies nicht von SVN unterstützt wird, 
sollte doch eine Standardanwendung sein, die viele benötigen...

von Walter T. (nicolas)


Lesenswert?

Werz schrieb:
> Ich finde es echt komisch, dass dies nicht von SVN unterstützt wird

Walter T. schrieb:
> subwcrev

Man schreibt eine Template-Header-Datei, lässt bei jedem Build subwcrew 
drüberlaufen und hat immer den aktuellen Revisionsstring inkl. 
Markierung von Veränderungen gegenüber dem Stand des Repos. Was will man 
mehr?

: Bearbeitet durch User
von Werz (Gast)


Lesenswert?

Ja, es gibt aber folgendes Problem:

Angenommen es gibt ein Softwareupdate, dass zu einer SVN Version 300 
führt (Commit bereits ausgeführt, sonst gäbe es ja die Version 300 gar 
nicht). Im Header mit der Svn Revision steht aber in diesem Moment nicht 
die 300, weil dieses Update mit einem Batch File oder wie oben 
beschrieben ja erst mit (vor) dem nächsten Build passieren kann (nach 
dem SVN Commit, damit es auch tatsächlich die letzte Version ist). Wenn 
es also danach diese Änderung der Version im Header gibt, muss es wieder 
committed werden, was wiederum zu einer neuen Revision führt...

von Stefan F. (Gast)


Lesenswert?

Werz schrieb:
> Ja, es gibt aber folgendes Problem

Ja ist blöd, aber ist halt so. Alle anderen mir bekannten Source 
Repositories verhalten sich ebenso. Deswegen schreibe ich die 
Revisionsnummer auch gar nicht in den Quelltext, sondern in eine 
Textdatei, die der Lieferung beigelegt wird.

von Jim M. (turboj)


Lesenswert?

Werz schrieb:
> Angenommen es gibt ein Softwareupdate, dass zu einer SVN Version 300
> führt (Commit bereits ausgeführt, sonst gäbe es ja die Version 300 gar
> nicht). Im Header mit der Svn Revision steht aber in diesem Moment nicht
> die 300,

SubWCRev löst das Problem.

Im Repository steht nur ein Template, das eigentliche .h File wird von 
SubWCrev via Make (oder anderen Build Tools) erst beim Bauen erzeugt und 
nie comitted - am Besten man trägt es in die "ignored" Liste ein.

Beispiel Template (svnversion.h.template):
1
/**
2
 @file svnversion.h
3
 
4
 @brief Definitions generated from Subversion
5
6
*/
7
8
9
#ifndef SVN_VERSION_H
10
#define SVN_VERSION_H
11
12
#define SVN_REVISION    "$WCREV$"
13
#define SVN_REVISION_MOD  "$WCREV$$WCMODS?m:$"
14
#define SVN_MODIFIED    "$WCMODS?Modified:Not modified$"
15
#define SVN_MODIFIED2    "$WCMODS?Modified:$"
16
#define SVN_DATE    "$WCDATE=%Y-%m-%d %H:%M:%S$"
17
#define SVN_BUILDTIME   "$WCNOW=%Y-%m-%d %H:%M:%S$"
18
#define SVN_BUILDTIME_REV  "$WCNOW=%Y-%m-%d %H:%M:%S$ r$WCREV$$WCMODS?m:$"
19
20
#endif

Daraus macht SubWCRev dann das .h:
1
/**
2
 @file svnversion.h
3
 
4
 @brief Definitions generated from Subversion
5
6
*/
7
8
9
#ifndef SVN_VERSION_H
10
#define SVN_VERSION_H
11
12
#define SVN_REVISION    "2181"
13
#define SVN_REVISION_MOD  "2181"
14
#define SVN_MODIFIED    "Not modified"
15
#define SVN_MODIFIED2    ""
16
#define SVN_DATE    "2019-10-30 10:33:09"
17
#define SVN_BUILDTIME   "2020-01-31 12:27:18"
18
#define SVN_BUILDTIME_REV  "2020-01-31 12:27:18 r2181"
19
20
#endif

Als Bonus werden lokal modifizierte Builds hier mit "m" am Ende der 
Revisionsnummer markiert.

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.