Компилировать дату и время с помощью cmake

Я хочу использовать cmake для установки версии VERSION для версии выпуска в случае релизов и времени компиляции.

При использовании make для создания сборки, получение времени компиляции было легко с помощью

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

который можно использовать прямо с исходным кодом c/С++. К сожалению, я не понял, как это можно сделать при использовании cmake.

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

устанавливает VERSION в момент выполнения cmake. Как установить VERSION во время компиляции при использовании cmake (чтобы избежать необходимости возиться с __DATE__ и __TIME__ при отсутствии флага RELEASE)?

Ответы

Ответ 2

Мое кроссплатформенное решение при первом запуске CMake создает файл timestamp.cmake в двоичном каталоге и определяет целевую timestamp которая запускает сгенерированный файл. Файл timestamp.cmake формирует строку timestamp.cmake ISO 8601 с помощью команды STRING CMake и записывает ее в файл timestamp.h с добавленной директивой препроцессора #define _TIMEZ_ (определения с одним #define _TIMEZ_; определения с двумя ведущими подчеркиваниями не должны быть определенным пользователем).

Включите следующее в ваш основной файл CMake.

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

Затем используйте команду ADD_DEPENDENCIES CMake, чтобы сделать вашу основную цель (возможно, главный исполняемый файл) зависимой от цели timestamp. CMake всегда считает его устаревшим, поэтому обновляется каждый раз, когда основная цель перестраивается, обновляя время сборки в соответствии с запросом.

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

С помощью этой команды вы можете указать несколько дополнительных зависимостей, разделенных пробелом, если вам нужно.

Затем вы можете просто #include "timestamp.h" (при условии, что двоичный каталог CMake находится в пути включения, который обычно есть. Если нет, то это просто: INCLUDE_DIRECTORIES (${CMAKE_BINARY_DIR})) и использовать _TIMEZ_ всякий раз, когда вы хотите иметь метку времени сборки в формате ISO 8601 (или, по сути, все, что вам нравится: вы можете указать ее самостоятельно, см. документацию CMake для использования команды STRING).

Это можно было бы упростить, напрямую (вручную) создав файл timestamp.cmake и добавив его в свой репозиторий кода, но я посчитал его недостаточно чистым. Общим недостатком CMake является то, что вы не можете получить доступ к процедуре формирования строки метки времени (той, которая используется в команде STRING CMake) на этапе, когда запускается сервер CMake, какой бы он ни был (например, GNU make), поэтому нужно использовать отдельный файл CMake и вызовите его на этом этапе. Это можно было бы сделать намного проще и понятнее, если бы вы могли вызвать процедуру формирования строки метки времени CMake в "режиме команд CMake" (тип вызова cmake -E), например, так: cmake -E date [format] [UTC], но увы. Я подал заявку в трекер ошибок CMake Mantis.

Вы можете помочь этому, поддержав мой запрос на добавление некоторых комментариев, показывающих, насколько вам это нужно.

Ответ 3

Возможно, вы могли бы использовать макросы компилятора __DATE__ __TIME__ внутри своего кода, а не получать его из cmake. Стоит упомянуть, что вам нужно будет очистить/сделать, чтобы обновить эти значения (поскольку GCC внедряет его, если объект уже скомпилирован, он не будет компилироваться снова, поэтому изменение даты и времени)

Ответ 4

Я получаю следующее решение:

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

Двоичная цель ${PROJECT_NAME} связана каждый раз с обновленным разделом.

Qt-код, чтобы получить эту метку времени:

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

Ответ 5

Некоторое время назад я столкнулся с этой же проблемой и в итоге написал этот репозиторий в качестве решения. Просто добавьте его как подкаталог CMake, и build_date_str будет содержать время ссылки вашей программы.

В случае, если github переходит в автономный режим до stackoverflow, идея этого решения:

  1. Создайте переменную BUILD_TIME CMake со string(TIMESTAMP... как в приведенных выше решениях.
  2. Скомпилируйте небольшую библиотеку, которая записывает BUILD_TIME в глобальную переменную (которую вы можете распечатать или что угодно) из вашей программы.
  3. Сделайте построение этой библиотеки зависимым от пользовательской цели, которая удаляет переменную из кэша CMake с помощью cmake -U BUILD_TIME.

Это означает, что каждый раз, когда вы строите свой проект, проверяются зависимости, и кэш CMake очищается, в результате чего CMake перезапускается для этой библиотеки отметок времени. Недостатком этого решения является то, что если у вас есть система CI, любые параметры, которые вы передаете своему шагу CMake, вы также должны помнить о том, чтобы передавать его на ваш шаг сборки.