LINUX.ORG.RU

Задать значение переменной или define на этапе компиляции в CMake

 ,


0

1

Как в CMake присвоить значение переменной или создать define на этапе компиляции? Например из файла?

Например, требуется автоинкремент номера билда в проекте CMake при каждой последующей сборке. Номер билда генерируется внешним скриптом при каждой сборке.

Если делать вот так:

execute_process(COMMAND cat build-number.txt OUTPUT_VARIABLE VERSION_BUILD)
add_custom_target(generate_version ALL ./autobuild.sh COMMENT "build: ${VERSION_BUILD}")
то инкремент билда делается только при создании make (конфигурации проекта)

Пока не придумал ничего другого как вызывать cmake . при каждой сборке проекта make:

execute_process(COMMAND cat build-number.txt OUTPUT_VARIABLE VERSION_BUILD)
add_custom_target(generate_version ALL ./autobuild.sh COMMAND cmake . COMMENT "build: ${VERSION_BUILD}")

Знаю, что есть вариант с записью непосредственно в файлы проекта, динамическим созданием .h и т.п.

Интересует как в CMake задать значение переменной, чтобы в результирующем Makefile оно выглядело, например, как:

VERSION_BUILD=$(shell cat build-number.txt)
?


set( VERSION_BUILD )
exec_program( "cat" ARGS "build-number.txt"
              OUTPUT_VARIABLE VERSION_BUILD )
message("Version build: " ${VERSION_BUILD} )

Добавил ..

а, тебе при каждой сборке нужно инкремент. Тогда не то.

И еще добавил.

Все оказывается просто. смотри тут

https://github.com/erichschroeter/cmake-auto-increment-build-number

ossa ★★
()
Последнее исправление: ossa (всего исправлений: 2)
Ответ на: комментарий от ossa
..
set(VERSION_OUTPUT ${PROJECT_BINARY_DIR}/src/version.h)
..
-i
	> ${VERSION_OUTPUT}

это создается файл. Про такой способ знаю. Интересует конструкция CMake, которая генерирует аналог для Makefile:

VERSION_BUILD=$(shell cat build-number.txt)

zudwa
() автор топика
Ответ на: комментарий от Deleted

нужно не просто -DMYDEFINE, а -DMYDEFINE=`cat build-number.txt`, т.е. каждый раз при компиляции make вычислять значение MYDEFINE каким либо образом

zudwa
() автор топика

Интересует как в CMake задать значение переменной, чтобы в результирующем Makefile оно выглядело, например, как:
VERSION_BUILD=$(shell cat build-number.txt)

Это больше похоже на хак. Даже если ты запишешь эту переменную в результирующий Makefile, как ты ее потом будешь использовать? CMake ничего про нее не знает. Проще всего динамически создавать *.h файл кастомной командой на PRE_BUILD этапе. Команда будет вызываться перед каждой сборкой, при условии что исходники изменились и нужна пересборка. У меня это выглядит вот так:

add_custom_command(TARGET ${PROJECT_NAME} PRE_BUILD COMMAND update_version.sh WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/scripts)
А скрипт update_version.sh генерирует номер билда и записывает его в version.h, используя version.h.in в качестве шаблона.

archie
()

Во-первых, нужно сразу уяснить, что директорий сборки может быть больше одной, соответственно, на машинах разных пользователей эти номера будут генерировать по разному. Если сохранять номер сборки во временный файл (к примеру, в директорию сборки), то он будет удалён вместе с ней и вся информация о номере версии канет в лету. То-есть файл с номером сборки должен быть или персистентным (сохраняться в систему контроля версий для всех пользователей) или должен использоваться исключительно на одной машине (билд-сервере?).

Касательно реализации. Для безусловного увеличения версии и пересборке программы при каждом запуске в CMake 3.2+ специально добавили ключевое слово BYPRODUCTS:

https://cmake.org/cmake/help/v3.3/command/add_custom_command.html
https://cmake.org/cmake/help/v3.3/command/add_custom_target.html

Могу быстро набросать вариант кода как его использовать для инкремента номера. Остальные варианты предложенные выше работать не будут, поскольку инкрементальная сборка даже не запустится, ибо артефакты сборки уже новее исходников.

Dendy ★★★★★
()
Ответ на: комментарий от Dendy

Не очень понятно, почему файл должен удалиться, если только нет специальных целей для удаления генерируемых файлов по маске. Насколько понимаю, создаваемый при помощи cmake Makefile четко контролирует только созданные им же файлы.Исходники же не удаляются.

Да, интересно было бы посмотреть на ваш вариант с BYPRODUCTS

zudwa
() автор топика
Ответ на: комментарий от zudwa

Любая директория сборки временная, их может быть много, её полное удаление и переконфигурирование нормальная процедура. Кроме того, CMake сам удалит файл с версией если изменится командная строка для её генерации, в примере выше (от archie) если захочется поменять название update_version.sh на update_build_number.sh, то файл с версией будет удалён.

Dendy ★★★★★
()
Ответ на: комментарий от zudwa

Скрипты генерации сделал на самом языке CMake для кроссплатформенности, можно переписать на bash или чём-угодно. Номер версии сохраняется в директорию с исходниками. Кусок C++-кода генерируется в директорию сборки.

CMakeLists.txt

cmake_minimum_required(VERSION 3.2)

# generate build_number
add_custom_target(generate_build_number
	COMMAND ${CMAKE_COMMAND}
		-D "BUILD_NUMBER_FILE=${CMAKE_CURRENT_SOURCE_DIR}/build_number"
		-P "${CMAKE_CURRENT_SOURCE_DIR}/generate-build-number.cmake"
	BYPRODUCTS "${CMAKE_CURRENT_SOURCE_DIR}/build_number"
)

# generage cpp from build_number
add_custom_command(
	OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build_info.cpp"
	COMMAND ${CMAKE_COMMAND}
		-D "BUILD_NUMBER_FILE=${CMAKE_CURRENT_SOURCE_DIR}/build_number"
		-D "CPP_FILE=${CMAKE_CURRENT_BINARY_DIR}/build_info.cpp"
		-P "${CMAKE_CURRENT_SOURCE_DIR}/generate-build-info-cpp.cmake"
	DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/build_number"
)

add_executable(myapp main.cpp "${CMAKE_CURRENT_BINARY_DIR}/build_info.cpp")
add_dependencies(myapp generate_build_number)

generate-build-number.cmake

if ( NOT EXISTS "${BUILD_NUMBER_FILE}" )
	set(build_number 1)
else()
	file(READ "${BUILD_NUMBER_FILE}" build_number)
	string(STRIP "${build_number}" build_number)
	math(EXPR build_number "${build_number} + 1")
endif()

file(WRITE "${BUILD_NUMBER_FILE}" "${build_number}\n")

generate-build-info-cpp.cmake

file(READ "${BUILD_NUMBER_FILE}" build_number)
string(STRIP "${build_number}" build_number)

string(TIMESTAMP timestamp)

file(WRITE "${CPP_FILE}"
	"extern const int build_number = ${build_number};\n"
	"extern const char * const build_time = \"${timestamp}\";\n"
)

main.cpp

#include <iostream>

extern const int build_number;
extern const char * const build_time;

int main(int argc, char ** argv)
{
	std::cout << "number: " << build_number << ", time: " << build_time << "\n";
	return 0;
}

Dendy ★★★★★
()
Ответ на: комментарий от Dendy

Спасибо. Приведенный пример не совсем работает:

$ make
Scanning dependencies of target generate_build_number
[  0%] Built target generate_build_number
[ 33%] Generating build_info.cpp
CMake Error: Error processing file: /home/user/Test/cmake/autobuild/generate-build-info-cpp.cmake
CMakeFiles/myapp.dir/build.make:53: recipe for target 'build_info.cpp' failed
make[2]: *** [build_info.cpp] Error 1
CMakeFiles/Makefile2:91: recipe for target 'CMakeFiles/myapp.dir/all' failed
make[1]: *** [CMakeFiles/myapp.dir/all] Error 2
Makefile:75: recipe for target 'all' failed
make: *** [all] Error 2

хотя номер билда в файле инкрементируется.

zudwa
() автор топика
Ответ на: комментарий от Dendy
$ ls -1
build_info.cpp
build_number
CMakeCache.txt
CMakeFiles
cmake_install.cmake
CMakeLists.txt
generate-build-info-cpp.cmake
generate-build-number.cmake
main.cpp
Makefile

вроде бы да

zudwa
() автор топика
Ответ на: комментарий от Dendy

Спасибо. Вроде бы заработало. Что было - не разобрался, видимо, какие-то издержки копипаста...

zudwa
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.