__date__ und __time__ und source_date_epoch?

OP #7371566

Mahlzeit!

Der gcc¹ kann ja --date-- und --time-- entsprechend der Environment Variable SOURCE_DATE_EPOCH setzen. So weit so gut, solange ein Programm aus den Quellen komplett neu gebaut wird. Mit Makefile und mehreren *.c funktioniert das nur zufällig, weil die Datei mit diesen Variablen selten geändert und übersetzt wird. Dann funktioniert auch die Empfehlung² nicht, eine RTC erstmalig zu stellen. Außerdem sieht man in dem Beitrag, wie mega umständlich das ist. Und evt. ist nicht klar, ob man UTC oder localtime bekommt.

Mit CFLAGS += SOURCE_DATE_EPOCH=$(SOURCE_DATE_EPOCH) entfällt der Umstand, man bekommt die UNIX-Sekunden direkt als Konstante. Aber trotzdem muss die entsprechende Quelldatei jedes Mal übersetzt werden. So geht's also auch nicht.

Wie kann man so eine Konstante per Makefile dem Linker übergeben? Oder wie macht "man" das?

  1. Beitrag "Re: Datum und Uhrzeit auf Mikrocontroller"
  2. https://gcc.gnu.org/onlinedocs/cpp/Environment-Variables.html
OP

Danke, das ist auch ein netter Trick. Aber für diesen Zweck ist das alles ein Krampf. Wenn SOURCE_DATE_EPOCH nicht definiert ist, setzt der gcc (vorschriftsmäßig) die aktuelle Uhrzeit ein, noch dazu die lokale. Dazu kommt der Umweg über mühsame Dekodierung von mühsam erzeugtem Text.

Diese beiden Präprozessor-Konstanten sind für etwas anderes gedacht. Es ist toll, dass der gcc auch Leute unterstützt, die diese Konstanten brauchen. Aber eigentlich will man doch nur eine einzige Zahl.

Mein Problem für heute war: -Wl,-defsym=SOURCE_DATE_EPOCH=$(UTC) benutze ich für die Cortex-M und früher ging es auch auf dem PC. AMD mit ihrem 64-Bit Befehlssatz ist schuld, dass auf dem PC per Default PIC erzeugt wird. Deshalb geht -defsym nicht mehr ganz so einfach.

Jetzt schreibe ich sinngemäß:

1
SDE := $(shell stat -L -c %Y $(PROJECT)/src/*/*.c | sort | tail -1)
2
-Wl,-defsym=S_D_E_BASE=0 \
3
-Wl,-defsym=S_D_E=$(SDE)
4

5
extern char S_D_E_BASE, S_D_E;
6
time_t source_date_epoch = (time_t)(&S_D_E - &S_D_E_BASE);

OK, es gibt keinen Schönheitspreis, aber es ist doch völlig legal? Gibt es irgend welche Einwände?

OP

Rick schrieb:

Warum verwendest Du nicht date?date +%d.%m.%Y_%H:%M

Wenn schon, dann date +%s. Dein Format muss ich ja auch wieder mühsam auseinander fieseln. Aber hier geht es eben nicht um die aktuelle Zeit, sondern um die Zeit der letzten Änderung der Quellen. Der entscheidende Unterschied: man kann das Programm später neu bauen und bekommt Bit für Bit das gleiche Binary.

https://reproducible-builds.org

Und muß es der Linker sein? In solchen Fallen erstelle ich mir per Skript eine passende Quelltextdatei.

Ja, mit Haralds FORCE-Trick geht das auch. Aber auch in dem Fall würde ich nicht den Umweg über die offiziellen Macros gehen, sondern über ein define mit date +%s (in Wirklichkeit: stat -c %Y).

Ja, time_t als Differenz von 2 Adressen zu übergeben, ist sicher überraschend. Aber die Lösung mit define und FORCE finde ich auch nicht elegant. Ich hatte mich so an -Wl,-defsym gewöhnt und nur wegen PIC geht das nicht mehr so einfach.

Ich warte noch auf Alternativ-Vorschläge ;)

OP

Rick schrieb:

Und muß es der Linker sein? In solchen Fallen erstelle ich mir per Skript eine passende Quelltextdatei.

Theoretisch muss es der Linker machen, aber scheinbar gibt es keine vernünftige Möglichkeit. Praktisch lohnt es sich auch nicht. Es würde nur dann richtig funktionieren, wenn der gcc DATE und TIME so umbauen würde, dass der Linker die aktuellen Werte einsetzen könnte. Aber das sind nun mal String-Konstanten.

So eine Quelltextdatei sollte aber nicht vom Script erzeugt werden, ein touch reicht auch. "touch -d@$SOURCE_DATE_EPOCH version.c" muss ja sowieso gemacht werden, sonst hätte version.c den Build- und nicht den Source-Zeitstempel.

Nebenbei sorgt dieses touch dafür, dass version.c (nur) genau dann übersetzt wird, wenn das nötig ist. Mit FORCE gibt es nie die Meldung "make: 'foo' is up to date". Also so:

1
#!/bin/sh
2
# source_date_epoch.sh
3
# Liefert die mtime der neuesten Quelldatei.
4
#
5
# Dank "touch" wird version.c immer genau dann neu compiliert,
6
# wenn es irgendetwas neues gibt. Das Makefile erzeugt aus dem
7
# Zeitstempel mit -D ein Macro und versorgt per export den gcc.
8
#
9
# Das Macro darf nur in version.c benutzt werden und __DATE__
10
# und __TIME__ eigentlich garnicht. Die funktionieren nur dann
11
# reproduzierbar, wenn alles komplett neu gebaut wird.
12

13
SOURCE_DATE_EPOCH=$(stat -L -c %Y \
14
                    $HOME/src/makefile.mk \
15
                    $HOME/src/make-flags.mk \
16
                    $HOME/src/*/Makefile \
17
                    $HOME/src/*/*.c \
18
                    $HOME/src/*/*.h \
19
                    | sort | tail -1)
20

21
touch -d@$SOURCE_DATE_EPOCH version.c
22
echo $SOURCE_DATE_EPOCH

im Makefile dann so:

1
# die offizielle Variable, z.B. fuer den gcc
2
export SOURCE_DATE_EPOCH:=$(shell ./source_date_epoch.sh)
3
# und
4
CFLAGS+=-DSOURCE_DATE_EPOCH=$(SOURCE_DATE_EPOCH)

und schließlich:

1
// version.c
2
#include <time.h>
3

4
time_t
5
source_date_epoch (void)
6
{
7
   time_t  sde = SOURCE_DATE_EPOCH;
8

9
   return sde;
10
}
11

12

13
char *
14
version_string (void)
15
{
16
   time_t  sde = source_date_epoch ();
17

18
   if (sde <= 0) { return "--"; }
19
   return isotime (6, sde);
20
}

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 3 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.