Comment utiliser les macros prédéfinies DATE et TIME en deux entiers, puis stringify?

voulez utiliser _ _ DATE __ et __ heure _ _ _ comme entier pour donner la version automatisée à mon code dans le temps de compilation.

#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

et obtenir COMPLETE_VERSION comme chaîne dans un const unsigned char [] .

const unsigned char completeVersion[] = ?? COMPLETE_VERSION;

devrait sortir 1.4.1432.2234 quelque chose.

une des solutions possibles pourrait être mais n'a pas fonctionné: convert - date - à-non signé-int

Dans le contexte de la compilation convertint-date-et-heure-string-à-just-entiers-en-c On peut se référer expanssion-et-stringification-comment-obtenir-le-marco-nom-pas-son-valeur

32
demandé sur Community 2012-07-28 06:40:48

6 réponses

si vous pouvez utiliser un compilateur C++ pour construire le fichier objet que vous voulez contenir votre chaîne de version, alors nous pouvons faire exactement ce que vous voulez! La seule magie ici est que C++ vous permet d'utiliser des expressions pour initialiser statiquement un tableau, alors que C ne le fait pas. Les expressions doivent être entièrement calculables au moment de la compilation, mais ces expressions le sont, donc il n'y a pas de problème.

nous construisons la chaîne de version un octet à la fois, et obtenons exactement ce que nous voulons.

// 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,
    '" 151920920"'
};


#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
}

ce n'est pas exactement le format que vous avez demandé, mais je ne comprends toujours pas comment vous voulez que les jours et les heures soient associés à un entier. Je pense qu'il est assez clair comment faire pour que cela produise n'importe quelle corde désirée.

37
répondu steveha 2013-05-09 22:42:15

Voici une version de travail du"build defs". C'est similaire à ma réponse précédente, mais j'ai trouvé le mois de construction. (Vous ne pouvez pas calculer le mois de construction dans une instruction #if , mais vous pouvez utiliser une expression ternaire qui sera compilée jusqu'à une constante.)

aussi, selon la documentation, si le compilateur ne peut pas obtenir l'Heure de la journée, il vous donnera des points d'interrogation pour ces chaînes. Donc j'ai ajouté des tests pour cette affaire, et j'ai fait les différents les macros renvoient une valeur manifestement erronée (99) si cela se produit.

#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

avec le code d'essai suivant, les travaux ci-dessus grand:

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

cependant, quand j'essaie d'utiliser ces macros avec votre macro de stringage, cela stringise l'expression littérale! Je ne sais pas comment obtenir le compilateur pour réduire l'expression à une valeur entière littérale et ensuite stringize.

aussi, si vous essayez d'initialiser statiquement un tableau de valeurs en utilisant ces macros, le compilateur se plaint avec un message error: initializer element is not constant . Si vous ne pouvez pas faire ce que vous voulez avec ces macros.

à ce stade, je pense que votre meilleure chance est le script Python qui génère juste un nouveau fichier include pour vous. Vous pouvez pré-calculer tout ce que vous voulez dans le format que vous voulez. Si vous ne voulez pas de Python, nous pouvons écrire un script AWK ou même un programme C.

12
répondu steveha 2013-05-09 19:13:35

j'ai une réponse partielle pour vous. C'est basé sur ce que J'obtiens de GCC:

__DATE__ donne quelque chose comme "Jul 27 2012"

__TIME__ donne quelque chose comme 21:06:19

mettez ce texte dans un fichier d'inclusion appelé build_defs.h :

#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

j'ai testé ce qui précède avec GCC sur Linux. Tout fonctionne très bien, sauf pour le problème que je ne peux pas trouver comment obtenir un nombre pour le mois. Si vous vérifiez la section qui est sous #if 0 vous verrez ma tentative de comprendre le mois. GCC se plaint avec ce message:

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

il serait trivial de convertir l'abréviation de trois lettres du mois en une sorte de nombre unique; il suffit de soustraire 'A' de la première lettre et 'a' de la deuxième et de la troisième, puis convertir en un nombre de base-26 ou quelque chose. Mais je veux le faire évaluer à 1 pour janvier et ainsi de suite, et je ne peux pas comprendre comment le faire.

EDIT: je viens de réaliser que vous avez demandé des Chaînes, pas des expressions qui évaluent à des valeurs entières.

j'ai essayé d'utiliser ces trucs pour construire une chaîne statique:

#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],
    '"151920920"'
};

GCC se plaint que "l'initialiseur de l'élément n'est pas constante" pour __DATE__ .

Désolé, Je ne sais pas comment vous aider. Peut-être que tu peux essayer ce truc avec ton compilateur? Ou peut-être que ça va donner vous avez une idée.

bonne chance.

P.S. si vous n'avez pas besoin que les choses soient des nombres, et que vous voulez juste une chaîne de construction unique, c'est facile:

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

avec GCC, cela donne quelque chose comme:

Version: 1.4 Jul 27 2012 21:53:59
8
répondu steveha 2012-07-28 04:50:18

vous pouvez toujours écrire un programme simple en Python ou quelque chose pour créer un fichier include qui a des instructions simples #define avec un numéro de build, l'heure et la date. Vous devez exécuter ce programme avant de faire une version.

si vous voulez, j'en écrirai un et je posterai la source ici.

Si vous êtes chanceux, votre outil de construction (IDE ou autre) pourrait avoir la capacité d'exécuter une commande externe, et vous pourriez avoir de l'outil externe réécrivez le fichier include automatiquement à chaque Compilation.

EDIT: voici un programme Python. Cela écrit un fichier appelé build_num.h et a un nombre de construction entier qui commence à 1 et augmente chaque fois que ce programme est exécuté; il écrit également #define valeurs pour l'année, le mois, la date, les heures, les minutes et les secondes du temps que ce programme est exécuté. Il dispose également d'un #define pour les parties principales et mineures du numéro de version, plus le VERSION et COMPLETE_VERSION " que vous vouliez. (Je n'étais pas sûr de ce que vous vouliez pour les numéros de date et d'heure, donc je suis allé pour les chiffres concaténés de la date et l'heure. Vous pouvez changer ça facilement.)

chaque fois que vous l'exécutez, il lit dans le fichier build_num.h , et le Parse pour le numéro de compilation; si le fichier build_num.h n'existe pas, il commence le numéro de compilation à 1. De même, il analyse les numéros de version majeurs et mineurs, et si le fichier n'existe pas, par défaut, ceux de la version 0.1.

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

j'ai fait que toutes les définitions sont simplement des entiers, mais comme ce sont des entiers simples, vous pouvez utiliser les trucs de string standard pour construire une chaîne à partir d'eux si vous voulez. Vous pouvez également l'étendre trivialement pour construire des chaînes pré-définies supplémentaires.

ce programme devrait fonctionner correctement sous Python 2.6 ou plus tard, y compris tout Python 3.x version. Vous pourriez l'exécuter sous un vieux Python avec quelques modifications, comme ne pas utiliser .partition() pour analyser chaîne.

6
répondu steveha 2012-07-30 21:12:25

courte réponse (version demandée): (format 3.33.20150710.182906)

s'il vous Plaît, utilisez simplement un makefile :

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

et si vous ne voulez pas un makefile , plus court encore, compilez simplement avec:

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

brève réponse (version suggérée): (format 150710.182906)

Utiliser un double pour le numéro de version:

MakeFile:

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

ou une simple commande de bash:

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

Astuce: Vous n'aimez toujours pas makefile ou est-ce juste pour un programme de test pas si petit? Ajouter la ligne suivante:

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

à votre ~/.profile , et souvenez-vous compiler avec gcc $CPPFLAGS ...


réponse longue:

je sais que cette question est plus ancienne, mais j'ai une petite contribution à faire. La meilleure pratique est toujours d'automatiser ce qui peut autrement devenir une source d'erreur (ou d'oubli).

j'ai été habitué à une fonction qui a créé le numéro de version pour moi. Mais je préfère cette fonction pour retourner un float . Mon numéro de version peut être imprimé par: printf("%13.6f\n", version()); qui publie quelque chose comme: 150710.150411 (étant L'année (2 chiffres) MOIS JOUR HEURE point minutes secondes).

mais la question Est la vôtre. Si vous préférez le "grand.mineur.date.temps", il devra être une chaîne de caractères. (Croyez-moi, le double est mieux. Si vous insistez sur une majuscule, vous pouvez toujours utiliser double si vous définissez la majuscule et laissez les décimales être date+heure, comme: major.datetime = 1.150710150411

Permet d'obtenir des affaires. L'exemple ci-dessous fonctionnera si vous compilez comme d'habitude, en oubliant de le définir, ou utilisez -DVERSION pour définir la version directement à partir de shell, mais mieux que tout, je recommande la troisième option: Utiliser un makefile .


trois formes de compilation et les résultats:

utilisant la marque:

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

en cours d'Exécution:

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

utilisant-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")\"

en cours d'Exécution:

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

utilisant la fonction d'intégration:

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

en cours d'Exécution:

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

code Source

  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

veuillez noter que la chaîne est limitée par MAJOR<=9999 et MINOR<=9999 . Bien sûr, j'ai mis cette valeur élevée qui nous l'espérons ne jamais déborder. Mais utiliser double est encore mieux (en plus, c'est complètement automatique, pas besoin de régler MAJOR et MINOR à la main).

Maintenant, le programme ci-dessus est un peu trop. Mieux est de supprimer complètement la fonction, et de garantir que la macro VERSION est défini, soit par -DVERSION directement dans la ligne de commande GCC (ou un alias qui l'ajoute automatiquement afin que vous ne pouvez pas oublier), ou la solution recommandée, pour inclure ce processus dans un makefile .

le makefile j'utilise:


MakeFile source:

  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 $@

une meilleure version avec DOUBLE

maintenant que je vous ai présenté "votre" solution préférée, voici ma solution:

compiler avec (A) makefile ou (b) gcc directement:

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 $@

(b) Ou une simple commande bash:

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

code Source (double 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;
}

Note: Cette double fonction n'est présente que si vous oubliez de définir la version macro. Si vous utilisez un makefile ou définissez un alias gcc gcc -DVERSION=$(date +"%g%m%d.%H%M%S") , vous pouvez supprimer cette fonction complètement en toute sécurité.


C'est tout. Une façon très soignée et facile de configurer votre contrôle de version et ne vous en souciez plus jamais!

3
répondu Dr Beco 2015-07-11 03:07:09

c'est très simple....

[dans le fichier],

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

OBJS=....\

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

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

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

tous les:de la version $(ProgramID) <<== la version ajouter à la première

version: < < = = ajouter

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

[au programme]

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

extern char szVersionStr[20];

[ aide ]

=== 4 ====

printf( "Version: %s\n", szVersionStr );
0
répondu turningeagle 2016-06-08 04:42:55