webentwicklung-frage-antwort-db.com.de

Wie werden __DATE__ und __TIME__ vordefinierte Makros als zwei Ganzzahlen verwendet, dann stringify

Sie möchten _ DATE __ UND __ TIME _ als Ganzzahl verwenden, um meinem Code während der Kompilierungszeit eine automatisierte Version zu geben.

#define STRINGIZER(arg)     #arg
#define STR_VALUE(arg)      STRINGIZER(arg)

#define DATE_as_int_str useD(__DATE__) // What can be done ?
#define TIME_as_int_str useT(__TIME__) // What can be done ?

#define VERSION 1.4

#define COMPLETE_VERSION STR_VALUE(VERSION) "." DATE_as_int_str "." TIME_as_int_str

und COMPLETE_VERSION als Zeichenfolge in einem const unsigned char [] abrufen.

const unsigned char completeVersion[] = ?? COMPLETE_VERSION;

Sollte 1.4.1432.2234 etwas ausgeben.

Eine der möglichen Lösungen könnte sein, funktionierte jedoch nicht: convert -date -to-unsigned-int

Im Zusammenhang mit der Kompilierungszeit convertint-date-and-time-Zeichenfolge in gerade Ganzzahlen in -c Man kann sich auf expanssion-und-stringification-how-get-the-the beziehen. Markenname-nicht-sein-Wert

34
Rick2047

Wenn Sie einen C++ - Compiler zum Erstellen der Objektdatei verwenden können, die Ihre Versionszeichenfolge enthalten soll, können wir genau das tun, was Sie möchten! Die einzige Magie dabei ist, dass Sie mit C++ Ausdrücke verwenden können, um ein Array statisch zu initialisieren, während dies bei C nicht der Fall ist. Die Ausdrücke müssen zur Kompilierzeit vollständig berechenbar sein. Diese Ausdrücke sind jedoch keine Probleme.

Wir bauen die Versionszeichenfolge Byte für Byte auf und erhalten genau das, was wir wollen.

// source file version_num.h

#ifndef VERSION_NUM_H

#define VERSION_NUM_H


#define VERSION_MAJOR 1
#define VERSION_MINOR 4


#endif // VERSION_NUM_H

// source file build_defs.h

#ifndef BUILD_DEFS_H

#define BUILD_DEFS_H


// Example of __DATE__ string: "Jul 27 2012"
//                              01234567890

#define BUILD_YEAR_CH0 (__DATE__[ 7])
#define BUILD_YEAR_CH1 (__DATE__[ 8])
#define BUILD_YEAR_CH2 (__DATE__[ 9])
#define BUILD_YEAR_CH3 (__DATE__[10])


#define BUILD_MONTH_IS_JAN (__DATE__[0] == 'J' && __DATE__[1] == 'a' && __DATE__[2] == 'n')
#define BUILD_MONTH_IS_FEB (__DATE__[0] == 'F')
#define BUILD_MONTH_IS_MAR (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r')
#define BUILD_MONTH_IS_APR (__DATE__[0] == 'A' && __DATE__[1] == 'p')
#define BUILD_MONTH_IS_MAY (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y')
#define BUILD_MONTH_IS_JUN (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n')
#define BUILD_MONTH_IS_JUL (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l')
#define BUILD_MONTH_IS_AUG (__DATE__[0] == 'A' && __DATE__[1] == 'u')
#define BUILD_MONTH_IS_SEP (__DATE__[0] == 'S')
#define BUILD_MONTH_IS_OCT (__DATE__[0] == 'O')
#define BUILD_MONTH_IS_NOV (__DATE__[0] == 'N')
#define BUILD_MONTH_IS_DEC (__DATE__[0] == 'D')


#define BUILD_MONTH_CH0 \
    ((BUILD_MONTH_IS_OCT || BUILD_MONTH_IS_NOV || BUILD_MONTH_IS_DEC) ? '1' : '0')

#define BUILD_MONTH_CH1 \
    ( \
        (BUILD_MONTH_IS_JAN) ? '1' : \
        (BUILD_MONTH_IS_FEB) ? '2' : \
        (BUILD_MONTH_IS_MAR) ? '3' : \
        (BUILD_MONTH_IS_APR) ? '4' : \
        (BUILD_MONTH_IS_MAY) ? '5' : \
        (BUILD_MONTH_IS_JUN) ? '6' : \
        (BUILD_MONTH_IS_JUL) ? '7' : \
        (BUILD_MONTH_IS_AUG) ? '8' : \
        (BUILD_MONTH_IS_SEP) ? '9' : \
        (BUILD_MONTH_IS_OCT) ? '0' : \
        (BUILD_MONTH_IS_NOV) ? '1' : \
        (BUILD_MONTH_IS_DEC) ? '2' : \
        /* error default */    '?' \
    )

#define BUILD_DAY_CH0 ((__DATE__[4] >= '0') ? (__DATE__[4]) : '0')
#define BUILD_DAY_CH1 (__DATE__[ 5])



// Example of __TIME__ string: "21:06:19"
//                              01234567

#define BUILD_HOUR_CH0 (__TIME__[0])
#define BUILD_HOUR_CH1 (__TIME__[1])

#define BUILD_MIN_CH0 (__TIME__[3])
#define BUILD_MIN_CH1 (__TIME__[4])

#define BUILD_SEC_CH0 (__TIME__[6])
#define BUILD_SEC_CH1 (__TIME__[7])


#if VERSION_MAJOR > 100

#define VERSION_MAJOR_INIT \
    ((VERSION_MAJOR / 100) + '0'), \
    (((VERSION_MAJOR % 100) / 10) + '0'), \
    ((VERSION_MAJOR % 10) + '0')

#Elif VERSION_MAJOR > 10

#define VERSION_MAJOR_INIT \
    ((VERSION_MAJOR / 10) + '0'), \
    ((VERSION_MAJOR % 10) + '0')

#else

#define VERSION_MAJOR_INIT \
    (VERSION_MAJOR + '0')

#endif

#if VERSION_MINOR > 100

#define VERSION_MINOR_INIT \
    ((VERSION_MINOR / 100) + '0'), \
    (((VERSION_MINOR % 100) / 10) + '0'), \
    ((VERSION_MINOR % 10) + '0')

#Elif VERSION_MINOR > 10

#define VERSION_MINOR_INIT \
    ((VERSION_MINOR / 10) + '0'), \
    ((VERSION_MINOR % 10) + '0')

#else

#define VERSION_MINOR_INIT \
    (VERSION_MINOR + '0')

#endif



#endif // BUILD_DEFS_H

// source file main.c

#include "version_num.h"
#include "build_defs.h"

// want something like: 1.4.1432.2234

const unsigned char completeVersion[] =
{
    VERSION_MAJOR_INIT,
    '.',
    VERSION_MINOR_INIT,
    '-', 'V', '-',
    BUILD_YEAR_CH0, BUILD_YEAR_CH1, BUILD_YEAR_CH2, BUILD_YEAR_CH3,
    '-',
    BUILD_MONTH_CH0, BUILD_MONTH_CH1,
    '-',
    BUILD_DAY_CH0, BUILD_DAY_CH1,
    'T',
    BUILD_HOUR_CH0, BUILD_HOUR_CH1,
    ':',
    BUILD_MIN_CH0, BUILD_MIN_CH1,
    ':',
    BUILD_SEC_CH0, BUILD_SEC_CH1,
    '\0'
};


#include <stdio.h>

int main(int argc, char **argv)
{
    printf("%s\n", completeVersion);
    // prints something similar to: 1.4-V-2013-05-09T15:34:49
}

Dies ist nicht genau das Format, nach dem Sie gefragt haben, aber ich verstehe immer noch nicht, wie Tage und Stunden einer ganzen Zahl zugeordnet werden sollen. Ich denke, es ist ziemlich klar, wie man eine beliebige gewünschte Saite produzieren kann.

40
steveha

Hier ist eine funktionierende Version der "Build Defs". Dies ist ähnlich zu meiner vorherigen Antwort, aber ich habe den Build-Monat herausgefunden. (Sie können den Erstellungsmonat in einer #if-Anweisung einfach nicht berechnen, Sie können jedoch einen ternären Ausdruck verwenden, der auf eine Konstante heruntergerechnet wird.)

Laut der Dokumentation erhalten Sie, wenn der Compiler die Tageszeit nicht ermitteln kann, Fragezeichen für diese Zeichenfolgen. Ich fügte Tests für diesen Fall hinzu und ließ die verschiedenen Makros einen offensichtlich falschen Wert (99) zurückgeben, wenn dies der Fall ist.

#ifndef BUILD_DEFS_H

#define BUILD_DEFS_H


// Example of __DATE__ string: "Jul 27 2012"
// Example of __TIME__ string: "21:06:19"

#define COMPUTE_BUILD_YEAR \
    ( \
        (__DATE__[ 7] - '0') * 1000 + \
        (__DATE__[ 8] - '0') *  100 + \
        (__DATE__[ 9] - '0') *   10 + \
        (__DATE__[10] - '0') \
    )


#define COMPUTE_BUILD_DAY \
    ( \
        ((__DATE__[4] >= '0') ? (__DATE__[4] - '0') * 10 : 0) + \
        (__DATE__[5] - '0') \
    )


#define BUILD_MONTH_IS_JAN (__DATE__[0] == 'J' && __DATE__[1] == 'a' && __DATE__[2] == 'n')
#define BUILD_MONTH_IS_FEB (__DATE__[0] == 'F')
#define BUILD_MONTH_IS_MAR (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r')
#define BUILD_MONTH_IS_APR (__DATE__[0] == 'A' && __DATE__[1] == 'p')
#define BUILD_MONTH_IS_MAY (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y')
#define BUILD_MONTH_IS_JUN (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n')
#define BUILD_MONTH_IS_JUL (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l')
#define BUILD_MONTH_IS_AUG (__DATE__[0] == 'A' && __DATE__[1] == 'u')
#define BUILD_MONTH_IS_SEP (__DATE__[0] == 'S')
#define BUILD_MONTH_IS_OCT (__DATE__[0] == 'O')
#define BUILD_MONTH_IS_NOV (__DATE__[0] == 'N')
#define BUILD_MONTH_IS_DEC (__DATE__[0] == 'D')


#define COMPUTE_BUILD_MONTH \
    ( \
        (BUILD_MONTH_IS_JAN) ?  1 : \
        (BUILD_MONTH_IS_FEB) ?  2 : \
        (BUILD_MONTH_IS_MAR) ?  3 : \
        (BUILD_MONTH_IS_APR) ?  4 : \
        (BUILD_MONTH_IS_MAY) ?  5 : \
        (BUILD_MONTH_IS_JUN) ?  6 : \
        (BUILD_MONTH_IS_JUL) ?  7 : \
        (BUILD_MONTH_IS_AUG) ?  8 : \
        (BUILD_MONTH_IS_SEP) ?  9 : \
        (BUILD_MONTH_IS_OCT) ? 10 : \
        (BUILD_MONTH_IS_NOV) ? 11 : \
        (BUILD_MONTH_IS_DEC) ? 12 : \
        /* error default */  99 \
    )

#define COMPUTE_BUILD_HOUR ((__TIME__[0] - '0') * 10 + __TIME__[1] - '0')
#define COMPUTE_BUILD_MIN  ((__TIME__[3] - '0') * 10 + __TIME__[4] - '0')
#define COMPUTE_BUILD_SEC  ((__TIME__[6] - '0') * 10 + __TIME__[7] - '0')


#define BUILD_DATE_IS_BAD (__DATE__[0] == '?')

#define BUILD_YEAR  ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_YEAR)
#define BUILD_MONTH ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_MONTH)
#define BUILD_DAY   ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_DAY)

#define BUILD_TIME_IS_BAD (__TIME__[0] == '?')

#define BUILD_HOUR  ((BUILD_TIME_IS_BAD) ? 99 :  COMPUTE_BUILD_HOUR)
#define BUILD_MIN   ((BUILD_TIME_IS_BAD) ? 99 :  COMPUTE_BUILD_MIN)
#define BUILD_SEC   ((BUILD_TIME_IS_BAD) ? 99 :  COMPUTE_BUILD_SEC)


#endif // BUILD_DEFS_H

Mit dem folgenden Testcode funktioniert das Obige hervorragend:

printf("%04d-%02d-%02dT%02d:%02d:%02d\n", BUILD_YEAR, BUILD_MONTH, BUILD_DAY, BUILD_HOUR, BUILD_MIN, BUILD_SEC);

Wenn ich jedoch versuche, diese Makros mit Ihrem Stringizing-Makro zu verwenden, wird der Literal-Ausdruck in eine Zeichenfolge gebracht! Ich kenne keine Möglichkeit, den Compiler dazu zu bringen, den Ausdruck auf einen ganzzahligen Literalwert zu reduzieren und dann stringize.

Wenn Sie versuchen, ein Array von Werten mithilfe dieser Makros statisch zu initialisieren, beschwert sich der Compiler mit einer error: initializer element is not constant-Nachricht. Mit diesen Makros können Sie also nicht das tun, was Sie möchten.

An dieser Stelle denke ich, dass Sie am besten das Python-Skript verwenden, das nur eine neue Include-Datei für Sie generiert. Sie können alles, was Sie möchten, in einem beliebigen Format vorberechnen. Wenn Sie Python nicht möchten, können Sie ein AWK-Skript oder sogar ein C-Programm schreiben.

14
steveha

Ich habe eine teilweise Antwort für Sie. Dies basiert auf dem, was ich von GCC bekomme:

__DATE__ gibt so etwas wie "Jul 27 2012"

__TIME__ gibt so etwas wie 21:06:19

Fügen Sie diesen Text in eine Include-Datei mit dem Namen build_defs.h ein:

#ifndef BUILD_DEFS_H

#define BUILD_DEFS_H


#define BUILD_YEAR ((__DATE__[7] - '0') * 1000 +  (__DATE__[8] - '0') * 100 + (__DATE__[9] - '0') * 10 + __DATE__[10] - '0')

#define BUILD_DATE ((__DATE__[4] - '0') * 10 + __DATE__[5] - '0')


#if 0
#if (__DATE__[0] == 'J' && __DATE__[1] == 'a' && __DATE__[2] == 'n')
    #define BUILD_MONTH  1
#Elif (__DATE__[0] == 'F' && __DATE__[1] == 'e' && __DATE__[2] == 'b')
    #define BUILD_MONTH  2
#Elif (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r')
    #define BUILD_MONTH  3
#Elif (__DATE__[0] == 'A' && __DATE__[1] == 'p' && __DATE__[2] == 'r')
    #define BUILD_MONTH  4
#Elif (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y')
    #define BUILD_MONTH  5
#Elif (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n')
    #define BUILD_MONTH  6
#Elif (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l')
    #define BUILD_MONTH  7
#Elif (__DATE__[0] == 'A' && __DATE__[1] == 'u' && __DATE__[2] == 'g')
    #define BUILD_MONTH  8
#Elif (__DATE__[0] == 'S' && __DATE__[1] == 'e' && __DATE__[2] == 'p')
    #define BUILD_MONTH  9
#Elif (__DATE__[0] == 'O' && __DATE__[1] == 'c' && __DATE__[2] == 't')
    #define BUILD_MONTH 10
#Elif (__DATE__[0] == 'N' && __DATE__[1] == 'o' && __DATE__[2] == 'v')
    #define BUILD_MONTH 11
#Elif (__DATE__[0] == 'D' && __DATE__[1] == 'e' && __DATE__[2] == 'c')
    #define BUILD_MONTH 12
#else
    #error "Could not figure out month"
#endif
#endif

#define BUILD_HOUR ((__TIME__[0] - '0') * 10 + __TIME__[1] - '0')
#define BUILD_MIN ((__TIME__[3] - '0') * 10 + __TIME__[4] - '0')
#define BUILD_SEC ((__TIME__[6] - '0') * 10 + __TIME__[7] - '0')

#endif // BUILD_DEFS_H

Ich habe das oben genannte mit GCC unter Linux getestet. Es funktioniert alles super, abgesehen von dem Problem, dass ich nicht herausfinden kann, wie ich eine Nummer für den Monat bekomme. Wenn Sie den Abschnitt unter #if 0 überprüfen, wird mein Versuch angezeigt, den Monat zu ermitteln. GCC beschwert sich mit dieser Nachricht:

error: token ""Jul 27 2012"" is not valid in preprocessor expressions

Es wäre trivial, die aus drei Buchstaben bestehende Monatsabkürzung in eine Art eindeutige Zahl umzuwandeln. subtrahieren Sie einfach 'A' vom ersten Buchstaben und 'a' vom zweiten und vom dritten Buchstaben und konvertieren Sie dann in eine Basis-26-Nummer oder etwas. Aber ich möchte, dass es für Januar usw. auf 1 gesetzt wird, und ich kann nicht herausfinden, wie das geht.

EDIT: Ich habe gerade festgestellt, dass Sie nach Strings gefragt haben, nicht nach Ausdrücken, die zu ganzzahligen Werten ausgewertet werden.

Ich habe versucht, mit diesen Tricks eine statische Zeichenfolge zu erstellen:

#define BUILD_MAJOR 1
#define BUILD_MINOR 4
#define VERSION STRINGIZE(BUILD_MAJOR) "." STRINGIZE(BUILD_MINOR)

char build_str[] = {
    BUILD_MAJOR + '0', '.' BUILD_MINOR + '0', '.',
    __DATE__[7], __DATE__[8], __DATE__[9], __DATE__[10],
    '\0'
};

GCC beschwert sich darüber, dass "Initializer-Element für __DATE__ nicht konstant ist".

Sorry, ich bin mir nicht sicher, wie ich Ihnen helfen kann. Vielleicht kannst du das mit deinem Compiler ausprobieren? Oder vielleicht bekommen Sie eine Idee.

Viel Glück.

P.S. Wenn Sie keine Zahlen als Zahlen benötigen und nur eine eindeutige Build-Zeichenfolge möchten, ist das ganz einfach:

const char *build_str = "Version: " VERSION " " __DATE__ " " __TIME__;

Bei GCC führt dies zu etwas wie:

Version: 1.4 Jul 27 2012 21:53:59
10
steveha

Sie können immer ein einfaches Programm in Python oder etwas schreiben, um eine Include-Datei zu erstellen, die einfache #define-Anweisungen mit Build-Nummer, -Zeit und -Datum enthält. Sie müssen dieses Programm dann ausführen, bevor Sie einen Build ausführen.

Wenn Sie möchten, schreibe ich eine und poste hier.

Wenn Sie Glück haben, kann Ihr Build-Tool (IDE oder was auch immer) einen externen Befehl ausführen, und dann könnte das externe Tool die Include-Datei bei jedem Build automatisch neu schreiben.

EDIT: Hier ist ein Python-Programm. Dies schreibt eine Datei mit dem Namen build_num.h und hat eine ganzzahlige Build-Nummer, die bei 1 beginnt und bei jeder Ausführung dieses Programms inkrementiert wird. Es schreibt auch #define-Werte für Jahr, Monat, Datum, Stunden, Minuten und Sekunden des Zeitpunkts, zu dem dieses Programm ausgeführt wird. Es hat auch einen #define für Haupt- und Nebenbestandteile der Versionsnummer sowie die vollständige VERSION und COMPLETE_VERSION, die Sie wollten. (Ich war mir nicht sicher, was Sie für die Datums- und Zeitangaben wollten, also habe ich nur verkettete Ziffern aus Datum und Uhrzeit gewählt. Sie können dies leicht ändern.)

Jedes Mal, wenn Sie es ausführen, liest es die Datei build_num.h und analysiert es für die Build-Nummer. Wenn die Datei build_num.h nicht vorhanden ist, startet sie die Build-Nummer bei 1. Ebenso werden die Haupt- und Nebenversionsnummern analysiert, und wenn die Datei nicht vorhanden ist, werden diese standardmäßig auf Version 0.1 gesetzt.

import time

FNAME = "build_num.h"

build_num = None
version_major = None
version_minor = None

DEF_BUILD_NUM = "#define BUILD_NUM "
DEF_VERSION_MAJOR = "#define VERSION_MAJOR "
DEF_VERSION_MINOR = "#define VERSION_MINOR "

def get_int(s_marker, line):
    _, _, s = line.partition(s_marker) # we want the part after the marker
    return int(s)

try:
    with open(FNAME) as f:
        for line in f:
            if DEF_BUILD_NUM in line:
                build_num = get_int(DEF_BUILD_NUM, line)
                build_num += 1
            Elif DEF_VERSION_MAJOR in line:
                version_major = get_int(DEF_VERSION_MAJOR, line)
            Elif DEF_VERSION_MINOR in line:
                version_minor = get_int(DEF_VERSION_MINOR, line)
except IOError:
    build_num = 1
    version_major = 0
    version_minor = 1

assert None not in (build_num, version_major, version_minor)


with open(FNAME, 'w') as f:
    f.write("#ifndef BUILD_NUM_H\n")
    f.write("#define BUILD_NUM_H\n")
    f.write("\n")
    f.write(DEF_BUILD_NUM + "%d\n" % build_num)
    f.write("\n")
    t = time.localtime()
    f.write("#define BUILD_YEAR %d\n" % t.tm_year)
    f.write("#define BUILD_MONTH %d\n" % t.tm_mon)
    f.write("#define BUILD_DATE %d\n" % t.tm_mday)
    f.write("#define BUILD_HOUR %d\n" % t.tm_hour)
    f.write("#define BUILD_MIN %d\n" % t.tm_min)
    f.write("#define BUILD_SEC %d\n" % t.tm_sec)
    f.write("\n")
    f.write("#define VERSION_MAJOR %d\n" % version_major)
    f.write("#define VERSION_MINOR %d\n" % version_minor)
    f.write("\n")
    f.write("#define VERSION \"%d.%d\"\n" % (version_major, version_minor))
    s = "%d.%d.%04d%02d%02d.%02d%02d%02d" % (version_major, version_minor,
            t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec)
    f.write("#define COMPLETE_VERSION \"%s\"\n" % s)
    f.write("\n")
    f.write("#endif // BUILD_NUM_H\n")

Ich habe alle Definitionen nur zu ganzen Zahlen gemacht, aber da es sich um einfache ganze Zahlen handelt, können Sie die standardmäßigen Stringisierungstricks verwenden, um aus ihnen eine Zeichenfolge zu erstellen, wenn Sie möchten. Sie können es auch einfach erweitern, um zusätzliche vordefinierte Zeichenfolgen zu erstellen.

Dieses Programm sollte unter Python 2.6 oder höher einwandfrei laufen, einschließlich aller Python 3.x-Versionen. Sie könnten es mit ein paar Änderungen unter einem alten Python ausführen, z. B. nicht mit .partition(), um die Zeichenfolge zu analysieren.

6
steveha

Kurze Antwort (angefragte Version): (Format 3.33.20150710.182906)

Bitte verwenden Sie einfach eine makefile mit:

MAJOR = 3
MINOR = 33
BUILD = $(Shell date +"%Y%m%d.%H%M%S")
VERSION = "\"$(MAJOR).$(MINOR).$(BUILD)\""
CPPFLAGS = -DVERSION=$(VERSION)

program.x : source.c
       gcc $(CPPFLAGS) source.c -o program.x

und wenn Sie keine makefile wollen, noch kürzer, kompilieren Sie einfach mit:

gcc source.c -o program.x -DVERSION=\"2.22.$(date +"%Y%m%d.%H%M%S")\"

Kurze Antwort (vorgeschlagene Version): (Format 150710.182906)

Verwenden Sie ein double für die Versionsnummer:

MakeFile:

VERSION = $(Shell date +"%g%m%d.%H%M%S")
CPPFLAGS = -DVERSION=$(VERSION)
program.x : source.c
      gcc $(CPPFLAGS) source.c -o program.x

Oder ein einfacher Bash-Befehl:

$ gcc source.c -o program.x -DVERSION=$(date +"%g%m%d.%H%M%S")

Tipp: Sie mögen makefile immer noch nicht oder ist es nur für ein nicht so kleines Testprogramm? Fügen Sie diese Zeile hinzu:

 export CPPFLAGS='-DVERSION='$(date +"%g%m%d.%H%M%S")

zu Ihrem ~/.profile, und vergessen Sie nicht, mit gcc $CPPFLAGS ... zu kompilieren


Lange Antwort:

Ich weiß, dass diese Frage älter ist, aber ich muss einen kleinen Beitrag dazu leisten. Best Practice ist immer automatisieren, was sonst zu einer Fehlerquelle (oder Vergessenheit) wurde.

Ich war an eine Funktion gewöhnt, die die Versionsnummer für mich erstellt hat. Aber ich bevorzuge diese Funktion, um eine float zurückzugeben. Meine Versionsnummer kann gedruckt werden durch: printf("%13.6f\n", version());, die etwa Folgendes ausgibt: 150710.150411 (Jahr (2-stellig) Monat Tag DOT Stunde Minute Sekunden).

Aber gut, die Frage liegt bei Ihnen. Wenn Sie "major.minor.date.time" bevorzugen, muss es eine Zeichenfolge sein. (Vertrauen Sie mir, double ist besser. Wenn Sie auf einem Major bestehen, können Sie auch double verwenden, wenn Sie den Major festlegen und die Dezimalstellen auf Datum + Uhrzeit setzen, z. B.: major.datetime = 1.150710150411

Lasst uns zur Sache kommen. Das folgende Beispiel funktioniert, wenn Sie wie gewohnt kompilieren, die Einstellung vergessen oder die Version über -DVERSION direkt von Shell aus festgelegt wird. Ich empfehle jedoch die dritte Option: makefile.


Drei Formen der Zusammenstellung und die Ergebnisse:

Verwenden von make:

beco> make program.x
gcc -Wall -Wextra -g -O0 -ansi -pedantic-errors -c -DVERSION="\"3.33.20150710.045829\"" program.c -o program.o
gcc  program.o -o program.x

Laufen:

__DATE__: 'Jul 10 2015'
__TIME__: '04:58:29'
VERSION: '3.33.20150710.045829'

Verwenden von -DVERSION:

beco> gcc program.c -o program.x -Wall -Wextra -g -O0 -ansi -pedantic-errors -DVERSION=\"2.22.$(date +"%Y%m%d.%H%M%S")\"

Laufen:

__DATE__: 'Jul 10 2015'
__TIME__: '04:58:37'
VERSION: '2.22.20150710.045837'

Verwenden der eingebauten Funktion:

beco> gcc program.c -o program.x -Wall -Wextra -g -O0 -ansi -pedantic-errors

Laufen:

__DATE__: 'Jul 10 2015'
__TIME__: '04:58:43'
VERSION(): '1.11.20150710.045843'

Quellcode

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #define FUNC_VERSION (0)
  6 #ifndef VERSION
  7   #define MAJOR 1
  8   #define MINOR 11
  9   #define VERSION version()
 10   #undef FUNC_VERSION
 11   #define FUNC_VERSION (1)
 12   char sversion[]="9999.9999.20150710.045535";
 13 #endif
 14 
 15 #if(FUNC_VERSION)
 16 char *version(void);
 17 #endif
 18 
 19 int main(void)
 20 {
 21 
 22   printf("__DATE__: '%s'\n", __DATE__);
 23   printf("__TIME__: '%s'\n", __TIME__);
 24 
 25   printf("VERSION%s: '%s'\n", (FUNC_VERSION?"()":""), VERSION);
 26   return 0;
 27 }
 28 
 29 /* String format: */
 30 /* __DATE__="Oct  8 2013" */
 31 /*  __TIME__="00:13:39" */
 32
 33 /* Version Function: returns the version string */
 34 #if(FUNC_VERSION)
 35 char *version(void)
 36 {
 37   const char data[]=__DATE__;
 38   const char tempo[]=__TIME__;
 39   const char nomes[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
 40   char omes[4];
 41   int ano, mes, dia, hora, min, seg;
 42 
 43   if(strcmp(sversion,"9999.9999.20150710.045535"))
 44     return sversion;
 45 
 46   if(strlen(data)!=11||strlen(tempo)!=8)
 47     return NULL;
 48 
 49   sscanf(data, "%s %d %d", omes, &dia, &ano);
 50   sscanf(tempo, "%d:%d:%d", &hora, &min, &seg);
 51   mes=(strstr(nomes, omes)-nomes)/3+1;
 52   sprintf(sversion,"%d.%d.%04d%02d%02d.%02d%02d%02d", MAJOR, MINOR, ano, mes, dia, hora, min, seg);
 53 
 54   return sversion;
 55 }
 56 #endif

Bitte beachten Sie, dass die Zeichenfolge auf MAJOR<=9999 und MINOR<=9999 beschränkt ist. Natürlich habe ich diesen hohen Wert eingestellt, der hoffentlich nie überlaufen wird. Die Verwendung von double ist jedoch noch besser (außerdem ist es vollständig automatisch, es ist nicht notwendig, MAJOR und MINOR von Hand einzustellen).

Jetzt ist das Programm etwas zu viel. Besser ist es, die Funktion vollständig zu entfernen und zu gewährleisten, dass das Makro VERSION entweder durch -DVERSION direkt in der GCC-Befehlszeile definiert wird (oder durch einen Aliasnamen, der es automatisch hinzufügt, damit Sie es nicht vergessen können) oder die empfohlene Lösung, um diesen Prozess aufzunehmen in eine makefile.

Hier ist das makefile, das ich verwende:


MakeFile-Quelle:

  1   MAJOR = 3
  2   MINOR = 33
  3   BUILD = $(Shell date +"%Y%m%d.%H%M%S")
  4   VERSION = "\"$(MAJOR).$(MINOR).$(BUILD)\""
  5   CC = gcc
  6   CFLAGS = -Wall -Wextra -g -O0 -ansi -pedantic-errors
  7   CPPFLAGS = -DVERSION=$(VERSION)
  8   LDLIBS =
  9   
 10    %.x : %.c
 11          $(CC) $(CFLAGS) $(CPPFLAGS) $(LDLIBS) $^ -o [email protected]

Eine bessere Version mit DOUBLE

Nun, da ich Ihnen "Ihre" bevorzugte Lösung präsentiert habe, ist dies meine Lösung:

Kompilieren Sie mit (a) makefile oder (b) gcc direkt:

(a) MakeFile:

   VERSION = $(Shell date +"%g%m%d.%H%M%S")
   CC = gcc
   CFLAGS = -Wall -Wextra -g -O0 -ansi -pedantic-errors 
   CPPFLAGS = -DVERSION=$(VERSION)
   LDLIBS =
   %.x : %.c
         $(CC) $(CFLAGS) $(CPPFLAGS) $(LDLIBS) $^ -o [email protected]

(b) Oder ein einfacher Bash-Befehl:

 $ gcc program.c -o program.x -Wall -Wextra -g -O0 -ansi -pedantic-errors -DVERSION=$(date +"%g%m%d.%H%M%S")

Quellcode (doppelte Version):

#ifndef VERSION
  #define VERSION version()
#endif

double version(void);

int main(void)
{
  printf("VERSION%s: '%13.6f'\n", (FUNC_VERSION?"()":""), VERSION);
  return 0;
}

double version(void)
{
  const char data[]=__DATE__;
  const char tempo[]=__TIME__;
  const char nomes[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
  char omes[4];
  int ano, mes, dia, hora, min, seg;
  char sversion[]="130910.001339";
  double fv;

  if(strlen(data)!=11||strlen(tempo)!=8)
    return -1.0;

  sscanf(data, "%s %d %d", omes, &dia, &ano);
  sscanf(tempo, "%d:%d:%d", &hora, &min, &seg);
  mes=(strstr(nomes, omes)-nomes)/3+1;
  sprintf(sversion,"%04d%02d%02d.%02d%02d%02d", ano, mes, dia, hora, min, seg);
  fv=atof(sversion);

  return fv;
}

Hinweis: Diese Doppelfunktion ist nur vorhanden, wenn Sie vergessen, die Makro-VERSION zu definieren. Wenn Sie eine makefile verwenden oder eine alias gcc gcc -DVERSION=$(date +"%g%m%d.%H%M%S") einstellen, können Sie diese Funktion sicher löschen.


Das war's. Eine sehr ordentliche und einfache Möglichkeit, Ihre Versionskontrolle einzurichten und sich nie wieder darum zu kümmern!

3
Dr Beco

Für alle, die nur das zusätzliche '' (Leerzeichen) ersetzen möchten, wenn der Tag kürzer als 10 ist, verwenden Sie:

#define BUILD_DATE (char const[]) { __DATE__[0], __DATE__[1], __DATE__[2], __DATE__[3], (__DATE__[4] == ' ' ?  '0' : __DATE__[4]), __DATE__[5], __DATE__[6], __DATE__[7], __DATE__[8], __DATE__[9], __DATE__[10], __DATE__[11] }

Ausgabe: 06. September 2019

0
hueman

es ist sehr einfach....

[in make datei]

==== 1 ====================

OBJS = .... \

version.o <<== add to your obj lists

==== 2 ====================

DATE = $ (Shell-Datum + 'char szVersionStr [20] = "% Y-% m-% d% H:% M:% S";') << == add 

all: version $ (ProgramID) << == version zuerst hinzufügen

version: << == hinzufügen

echo '$(DATE)' > version.c  <== add ( create version.c file)

[im Programm]

===== 3 ==============

extern char szVersionStr [20];

[mit]

=== 4 ====

printf( "Version: %s\n", szVersionStr );
0
turningeagle