Ответ 1
Для относительно недавних версий CMake (> = 2.8.11):
string(TIMESTAMP {output variable} [{format string}] [UTC])
(см. http://www.cmake.org/cmake/help/v3.0/command/string.html). Например:
string(TIMESTAMP TODAY "%Y%m%d")
Я хочу использовать 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)?
Для относительно недавних версий CMake (> = 2.8.11):
string(TIMESTAMP {output variable} [{format string}] [UTC])
(см. http://www.cmake.org/cmake/help/v3.0/command/string.html). Например:
string(TIMESTAMP TODAY "%Y%m%d")
Мое кроссплатформенное решение при первом запуске 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.
Вы можете помочь этому, поддержав мой запрос на добавление некоторых комментариев, показывающих, насколько вам это нужно.
Возможно, вы могли бы использовать макросы компилятора __DATE__
__TIME__
внутри своего кода, а не получать его из cmake. Стоит упомянуть, что вам нужно будет очистить/сделать, чтобы обновить эти значения (поскольку GCC внедряет его, если объект уже скомпилирован, он не будет компилироваться снова, поэтому изменение даты и времени)
Я получаю следующее решение:
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"));
Некоторое время назад я столкнулся с этой же проблемой и в итоге написал этот репозиторий в качестве решения. Просто добавьте его как подкаталог CMake, и build_date_str
будет содержать время ссылки вашей программы.
В случае, если github переходит в автономный режим до stackoverflow, идея этого решения:
BUILD_TIME
CMake со string(TIMESTAMP...
как в приведенных выше решениях.BUILD_TIME
в глобальную переменную (которую вы можете распечатать или что угодно) из вашей программы.cmake -U BUILD_TIME
.Это означает, что каждый раз, когда вы строите свой проект, проверяются зависимости, и кэш CMake очищается, в результате чего CMake перезапускается для этой библиотеки отметок времени. Недостатком этого решения является то, что если у вас есть система CI, любые параметры, которые вы передаете своему шагу CMake, вы также должны помнить о том, чтобы передавать его на ваш шаг сборки.