Kompilieren Sie Datum und Uhrzeit mit cmake

Lesezeit: 8 Minuten

Ich möchte cmake verwenden, um VERSION im Falle von Release-Builds auf eine Release-Version und ansonsten auf die Kompilierzeit festzulegen.

Bei der Verwendung von make für Entwicklungs-Builds war das Abrufen der Kompilierzeit einfach über

-DVERSION=`date +%Y-%m-%d_%H:%M`

die direkt von c/c++ Quellcode verwendet werden könnte. Leider habe ich nicht herausgefunden, wie das gleiche mit cmake erreicht werden kann.

string(TIMESTAMP VERSION "%Y-%m-%d %H:%M")
add_definitions(-DVERSION="${VERSION}")

setzt VERSION auf die Zeit, zu der cmake ausgeführt wurde. Wie kann ich VERSION auf die Kompilierzeit setzen, wenn ich cmake verwende (um zu vermeiden, mit __DATE__ und __TIME__ in Abwesenheit eines RELEASE-Flags)?

  • Hier ist eine nützliche Antwort für Ihr Problem. Sie müssen sicherstellen, dass Sie einen Befehl wie haben date verfügbar mit Ihrer Host-Build-Umgebung. Eine generische Lösung mit der __DATE__ und __TIME__ Makros wären auch einfach, indem Sie einfach eine Header-Datei mit den erforderlichen Definitionen bereitstellen, die bei jedem Build generiert (oder zumindest berührt) wird (als Pre-Build-Aktion).

    – πάντα ῥεῖ

    18. Juni 2014 um 19:06 Uhr


  • Im Allgemeinen besteht der Zweck einer Versionsnummer darin, dies zu können Reproduzieren Sie die genauen Quelldateien, mit denen eine Binärdatei erstellt wurde. Verwenden Sie daher den Zeitstempel der Zusammenstellung ist ein sehr, sehr schlechte Wahl. Weisen Sie korrekte Versionsnummern zu und pflegen Sie sie, oder verwenden Sie etwas aus Ihrer Versionskontrollsoftware (Zweig / Revision für SVN, Hashcode für GIT), wenn Sie sich nicht darum kümmern können. Verwenden Sie einfach keinen Zeitstempel für die Kompilierung, es ist sogar noch schlimmer, als gar keine Version zu haben, weil Sie eine neuere Kompilation älterer Quellen haben könnten, was für alle, einschließlich Sie selbst, verwirrend wäre.

    – DevSolar

    14. Juli 2015 um 8:43 Uhr


  • @DevSolar Ich denke, Sie mischen hier verschiedene Ideen. Der Zweck der Revision, nicht der Version, ist es, die exakten Quelldateien reproduzieren zu können. Der Zweck der Build-ID besteht darin, die genauen Build-Artefakte auf unserem Build-/Entwicklungscomputer finden zu können. Der Zweck der App/Lib-Version ist eigentlich breit gefächert, angefangen bei Marketingzwecken bis hin zu Abwärtskompatibilitätsproblemen. Die App/Lib-Version kann eine Build-ID oder Revision enthalten oder nicht. Es liegt an den Entwicklern (Ops), wie eine bestimmte Version zum Erstellen oder Überarbeiten nachverfolgt wird. Der Zeitstempel kann sehr gut als Build-ID für Entwickler-Builds dienen.

    – Alex Che

    18. Oktober 2021 um 15:50 Uhr


  • @AlexChe: Das Problem mit einer Zeitstempel-Build-ID besteht darin, dass ein Zeitstempel es nicht erlaubt, die Binärdatei zu ihren Quellen zurückzuverfolgen, es sei denn, Sie arbeiten nur mit einem einzigen Codezweig – und selbst dann müssen Sie mit dem VCS herumspielen, das Sie sind verwenden. Eine VCS-Revision ist besser, verliert aber immer noch an Aussagekraft, wenn Sie zB Ihr VCS migrieren müssen (oder wollen). IMHO sollten Sie eine Produktversion und Komponentenversionen haben und idealerweise eine VCS-spezifische Methode verwenden, um die Quellen zu markieren, die in einen Komponenten-Build eingeflossen sind, den Sie bei Bedarf auf ein anderes VCS migrieren könnten.

    – DevSolar

    20. Oktober 2021 um 11:49 Uhr

Benutzer-Avatar
Mathias

Für relativ neue Versionen von CMake (>=2.8.11):

string(TIMESTAMP {output variable} [{format string}] [UTC])

(sehen http://www.cmake.org/cmake/help/v3.0/command/string.html). Zum Beispiel:

string(TIMESTAMP TODAY "%Y%m%d")

  • Könnten Sie bitte einige Beispiele hinzufügen?

    – Alfisch

    9. August 2017 um 18:39 Uhr

  • string(TIMESTAMP ... wird zwischengespeichert, bis Sie ihn bearbeiten CMakeLists.txt

    – Tomilov Anatoliy

    14. Juni 2018 um 13:11 Uhr

Benutzer-Avatar
dbnet

Meine plattformübergreifende Lösung erstellt beim ersten Lauf von CMake eine Datei timestamp.cmake im Binärverzeichnis und definiert ein Ziel timestamp die die generierte Datei ausführt. Die Datei timestamp.cmake bildet eine ISO 8601-Zeitstempelzeichenfolge mit der STRING CMake-Befehl und schreibt ihn in eine Datei timestamp.h mit einer #define _TIMEZ_ Präprozessordirektive vorangestellt (Definitionen mit einem führenden Unterstrich sind in Ordnung; Definitionen mit zwei führenden Unterstrichen sollten nicht benutzerdefiniert sein).

Fügen Sie Folgendes in Ihre CMake-Hauptdatei ein.

# build time in UTC ISO 8601
FILE (WRITE ${CMAKE_BINARY_DIR}/timestamp.cmake "STRING(TIMESTAMP TIMEZ UTC)\n")
FILE (APPEND ${CMAKE_BINARY_DIR}/timestamp.cmake "FILE(WRITE timestamp.h \"#ifndef TIMESTAMP_H\\n\")\n")
FILE (APPEND ${CMAKE_BINARY_DIR}/timestamp.cmake "FILE(APPEND timestamp.h \"#define TIMESTAMP_H\\n\\n\")\n")
FILE (APPEND ${CMAKE_BINARY_DIR}/timestamp.cmake "FILE(APPEND timestamp.h \"#define _TIMEZ_ \\\"\${TIMEZ}\\\"\\n\\n\")\n")
FILE (APPEND ${CMAKE_BINARY_DIR}/timestamp.cmake "FILE(APPEND timestamp.h \"#endif // TIMESTAMP_H\\n\")\n")
ADD_CUSTOM_TARGET (
    timestamp
    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/timestamp.cmake
    ADD_DEPENDENCIES ${CMAKE_BINARY_DIR}/timestamp.cmake)

Dann nutzen Sie die ADD_DEPENDENCIES CMake-Befehl, um Ihr Hauptziel (wahrscheinlich die ausführbare Hauptdatei) von der timestamp Ziel. Es wird von CMake immer als veraltet angesehen, daher wird es jedes Mal aktualisiert, wenn das Hauptziel neu erstellt wird, wodurch die Erstellungszeit wie angefordert aktualisiert wird.

ADD_DEPENDENCIES (${CMAKE_BINARY_DIR}/${BINARY_NAME} timestamp)

Mit diesem Befehl können Sie bei Bedarf mehrere zusätzliche Abhängigkeiten angeben, die durch Leerzeichen getrennt sind.

Dann kannst du eben #include "timestamp.h" (vorausgesetzt, das CMake-Binärverzeichnis befindet sich im Include-Pfad, was normalerweise der Fall ist. Wenn nicht, ist das einfach: INCLUDE_DIRECTORIES (${CMAKE_BINARY_DIR})) und verwenden _TIMEZ_ wann immer Sie den Build-Zeitstempel im ISO 8601-Format haben möchten (oder was auch immer Sie möchten: Sie können es selbst festlegen, siehe CMake-Dokumentation für STRING Befehlsverwendung).

Dies hätte einfacher gemacht werden können, indem die Datei direkt (von Hand) erstellt wurde timestamp.cmake und es zu Ihrem Code-Repository hinzufügen, aber ich habe es als nicht sauber genug angesehen. Es ist ein allgemeiner Nachteil von CMake, dass Sie nicht auf das Verfahren zum Erstellen von Zeitstempelzeichenfolgen zugreifen können (das in der STRING CMake-Befehl) in der Phase, in der das Backend von CMake, was auch immer es ist (z. B. GNU make), ausgeführt wird, sodass man eine separate CMake-Datei verwenden und in dieser Phase aufrufen muss. Dies hätte viel einfacher und sauberer gemacht werden können, wenn Sie die CMake-Zeitstempel-String-Bildungsprozedur im “CMake-Befehlsmodus” aufrufen könnten (cmake -E Art des Aufrufs), zum Beispiel so: cmake -E date [format] [UTC], aber leider. Ich habe hat ein Ticket im Bugtracker Mantis von CMake eingereicht.

Sie können dazu beitragen, indem Sie meine Feature-Anfrage unterstützen und einige Kommentare posten, die zeigen, wie sehr Sie dies benötigen.

  • Definiert mit führendem Unterstrich und dann ein Großbuchstabe ist eigentlich nicht ok. (Nicht, dass das zu wichtig wäre.)

    – Praxeolit

    24. Mai 2016 um 14:11 Uhr

  • (das ist alt, aber) so verstehe ich das alle (unscoped) Symbole, die mit einem führenden Unterstrich beginnen, sind der Implementierung vorbehalten.

    – jwm

    1. Juni 2020 um 20:24 Uhr

Vielleicht könnten Sie die Compiler-Makros verwenden __DATE__ __TIME__ in Ihrem Code, anstatt es von cmake zu bekommen. Erwähnenswert ist, dass Sie clean/make ausführen müssen, um diese Werte zu aktualisieren (da GCC es einbettet, wird es nicht erneut kompiliert, wenn das Objekt bereits kompiliert ist, also keine Datums-/Uhrzeitänderung)

  • Dies ist ein vernünftiger Ratschlag, hat aber den Nachteil, dass vollständig reproduzierbare Builds seit dem verhindert werden __DATE__ und __TIME__ ändert sich je nach Kompilierzeit. Stattdessen kann es besser sein, diese Werte zur Kompilierzeit als verschiedene Makros zu übergeben.

    – ddavella

    17. November 2021 um 14:24 Uhr

  • Ein paar Jahre später stimme ich dir wirklich zu. Mit DATUM und ZEIT man wird nicht in der Lage sein, eine 1:1-Binärdatei von einer bestimmten Version zu erstellen.

    – Lucas Teske

    17. November 2021 um 16:34 Uhr

Benutzer-Avatar
Tomilov Anatoliy

Am Ende komme ich auf folgende Lösung:

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
    add_custom_target(
        "linktimestamp"
        ALL
        COMMAND date +'%Y-%m-%d %H:%M:%S' > "linktimestamp.txt"
        COMMAND objcopy --input binary --output elf64-x86-64 --binary-architecture i386:x86-64 --rename-section .data=.rodata,CONTENTS,ALLOC,LOAD,READONLY,DATA "linktimestamp.txt" "linktimestamp.o"
        WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
        COMMENT "link timestamp: ${LINK_TIMESTAMP}"
        )
else()
    add_custom_target(
        "linktimestamp"
        ALL
        COMMAND date +'%Y-%m-%d %H:%M:%S' > "linktimestamp.txt"
        COMMAND objcopy --input binary --output elf32-i386 --binary-architecture i386 --rename-section .data=.rodata,CONTENTS,ALLOC,LOAD,READONLY,DATA "linktimestamp.txt" "linktimestamp.o"
        WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
        COMMENT "link timestamp: ${LINK_TIMESTAMP}"
        )
endif()
#add_dependencies(${PROJECT_NAME} "linktimestamp")
target_link_libraries(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/linktimestamp.o")

Binäres Ziel ${PROJECT_NAME} jedes Mal mit aktualisiertem Abschnitt verlinkt.

Qt Code, um diesen Zeitstempel zu erhalten:

extern char _binary_linktimestamp_txt_start[];
//extern char _binary_linktimestamp_txt_end[];
extern char _binary_linktimestamp_txt_size[];
const auto text = QByteArray::fromRawData(_binary_linktimestamp_txt_start, reinterpret_cast< std::intptr_t >(_binary_linktimestamp_txt_size));
qDebug() << QDateTime::fromString(QString::fromUtf8(text), "yyyy-MM-dd HH:mm:ss\n"));

Ich bin vor einiger Zeit auf dasselbe Problem gestoßen und habe schließlich geschrieben dieses Repo als Lösung. Fügen Sie es einfach als CMake-Unterverzeichnis hinzu und build_date_str wird die enthalten Linkzeit Ihres Programms.

Für den Fall, dass github vor dem Stackoverflow offline geht, ist die Idee dieser Lösung:

  1. Ein … kreieren BUILD_TIME CMake-Variable mit string(TIMESTAMP ... wie in den obigen Lösungen.
  2. Stellen Sie eine kleine Bibliothek zusammen, die die aufzeichnet BUILD_TIME in eine globale Variable (die Sie drucken können oder was auch immer) aus Ihrem Programm.
  3. Machen Sie das Erstellen dieser Bibliothek von einem benutzerdefinierten Ziel abhängig, mit dem die Variable aus dem CMake-Cache entfernt wird cmake -U BUILD_TIME.

Dies bedeutet, dass jedes Mal, wenn Sie Ihr Projekt erstellen, die Abhängigkeiten überprüft und der CMake-Cache gelöscht wird, wodurch CMake für diese Zeitstempelbibliothek erneut ausgeführt wird. Ein Nachteil dieser Lösung ist, dass Sie bei einem CI-System alle Parameter, die Sie an Ihren CMake-Schritt übergeben, daran denken müssen, sie auch an Ihren Build-Schritt zu übergeben.

1384670cookie-checkKompilieren Sie Datum und Uhrzeit mit cmake

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy