В проекте CMake я использую теги git для номеров версий. Используя подход из https://github.com/iPenguin/version_git, Я могу получить номер версии в исходных кодах (то есть CMake создает файл version.cpp со строкой const, содержащей номер версии, который я затем могу использовать в моих исходных кодах C ++). Проблема в том, что когда я создаю исходный пакет с использованием CPack, я исключаю каталог .git, а при компиляции исходных кодов, извлеченных из пакета, номер версии недоступен.
Как заставить CPack поместить номер версии в исходный пакет?
У меня есть следующие требования:
Я не хочу, чтобы каталог сборки был включен в мой пакет с исходным кодом. Важно отметить, что я делаю сборку вне исходного кода из каталога в корневом каталоге проекта. То есть, если мой уровень CMakeLists.txt находится в каталоге my_project, я запускаю «cmake ..» и «make» в каталоге my_project / build.
Я не хочу включать каталог .git в мой пакет с исходным кодом.
Я хочу, чтобы все файлы, сгенерированные cmake и «make package_source», находились внутри каталога сборки. Кроме того, я не хочу, чтобы cmake изменил или удалил какой-либо файл за пределами каталога сборки.
Я не хочу использовать недокументированное поведение cmake и cpack, в частности пути, используемые cpack.
До сих пор я не смог найти решение, которое отвечало бы всем моим требованиям. Вот что я попробовал:
Я позволил cmake создать файл versionForSourcePackage.cmake, который при последующем включении в cmake установит переменную VERSION. Затем я хочу поместить этот файл в исходный пакет, чтобы при запуске cmake в извлеченном пакете для него была установлена переменная VERSION. Этот файл создается в каталоге сборки, но я не знаю, как правильно позволить CPack скопировать его в исходные пакеты.
Первая возможность это небольшая модификация https://github.com/iPenguin/version_git, но это не удовлетворяет моему требованию № 4. Полный пример на https://github.com/josefcibulka/version_git.
При сборке из репозитория я получаю номер версии из git и сохраняю его в $ {PROJECT_BINARY_DIR} /versionForSourcePackage.cmake. Затем я использую CPACK_INSTALL_COMMANDS, чтобы позволить CPack скопировать этот файл в $ {PROJECT_BINARY_DIR} / _ CPack_Packages / Linux-Source / $ {CPACK_SOURCE_GENERATOR} / $ {CPACK_SOURCE_PACKAGE_FILE_NAME} /, чтобы он был включен в пакет. Это нарушает требование № 4 и, более того, если я хочу в будущем создавать пакеты TGZ и ZIP, мне нужно внести некоторые изменения. Есть ли какая-нибудь переменная, которую я мог бы использовать в CPACK_INSTALL_COMMANDS, чтобы получить путь к каталогу, где CPack готовит содержимое пакета?
CMakeLists.txt выглядит так:
cmake_minimum_required(VERSION 2.8)
project("version_from_git")
# Appends the cmake/modules path to MAKE_MODULE_PATH variable.
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH})
# When in the extracted package, use the previously generated file, otherwise get the current version from git.
if(EXISTS "${PROJECT_SOURCE_DIR}/versionForSourcePackage.cmake")
include("${PROJECT_SOURCE_DIR}/versionForSourcePackage.cmake")
else()
include(GetGitRevisionDescription)
git_describe(VERSION --tags --dirty=-dirty)
endif()
# Parse the version information into pieces.
string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" VERSION_MAJOR "${VERSION}")
string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${VERSION}")
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERSION_PATCH "${VERSION}")
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+(.*)" "\\1" VERSION_SHA1 "${VERSION}")
set(VERSION_SHORT "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
set(CPACK_SOURCE_GENERATOR "TGZ")
set(CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${VERSION_PATCH}")
# The following will copy the version file to the source package.
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_SHORT}-Source")
set(CPACK_INSTALL_COMMANDS "${CMAKE_COMMAND} -E make_directory \
${PROJECT_BINARY_DIR}/_CPack_Packages/Linux-Source/${CPACK_SOURCE_GENERATOR}/${CPACK_SOURCE_PACKAGE_FILE_NAME}/""${CMAKE_COMMAND} -E copy \
${PROJECT_BINARY_DIR}/versionForSourcePackage.cmake \
${PROJECT_BINARY_DIR}/_CPack_Packages/Linux-Source/${CPACK_SOURCE_GENERATOR}/${CPACK_SOURCE_PACKAGE_FILE_NAME}/")
# Exclude the build and .git directory from the source package.
set(CPACK_SOURCE_IGNORE_FILES "${PROJECT_SOURCE_DIR}/.git/;${PROJECT_BINARY_DIR}/;${CPACK_SOURCE_IGNORE_FILES}")
include (CPack)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/version.cpp.in
${CMAKE_CURRENT_BINARY_DIR}/version.cpp)
# Prepare the versionForSourcePackage.cmake file that will be included in the source package.
configure_file(
${PROJECT_SOURCE_DIR}/versionForSourcePackage.cmake.in
${PROJECT_BINARY_DIR}/versionForSourcePackage.cmake @ONLY)
set(version_file "${CMAKE_CURRENT_BINARY_DIR}/version.cpp")
set(source_files "${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp")
#Add the version_file to the project build.
add_executable(${PROJECT_NAME} ${source_files} ${version_file})
Файл versionForSourcePackage.cmake.in:
set(VERSION "v@VERSION_SHORT@")
Вторая возможность этот подход используется в https://github.com/lcw/cmake_git_version. Полный пример находится в ветке second_possibility в https://github.com/josefcibulka/version_git. Файл versionForSourcePackage.cmake помещается в подкаталог version_file каталога сборки, и этот каталог добавляется среди CPACK_SOURCE_INSTALLED_DIRECTORIES. Это хорошо работает, когда каталог проекта и сборки находятся на одном уровне.
Проблема в том, что если каталог сборки находится в каталоге проекта, я добавляю каталог сборки в CPACK_SOURCE_IGNORE_FILES для удовлетворения требования 1. Затем, даже когда я устанавливаю CPACK_SOURCE_INSTALLED_DIRECTORIES для включения каталога version_file, он будет игнорироваться. Это можно сделать так, чтобы я игнорировал только все в каталоге сборки, кроме каталога version_file. Тогда каталог сборки в исходном пакете содержит только каталог version_file, который лучше, чем весь каталог сборки, но все же не идеален.
Обновить: Кажется, что требование 4 также не выполнено, потому что я не могу найти CPACK_SOURCE_INSTALLED_DIRECTORIES в документация CMake.
Отличия от первой возможности в CMakeLists.txt:
# The following will transfer the version from git to the source package.
set(CPACK_SOURCE_INSTALLED_DIRECTORIES "${PROJECT_SOURCE_DIR};/;${PROJECT_BINARY_DIR}/version_file;/")
# Exclude the build and .git directory from the source package.
set(CPACK_SOURCE_IGNORE_FILES "${PROJECT_SOURCE_DIR}/.git/;${PROJECT_BINARY_DIR}/([^v].*|v[^e].*|ve[^r].*|ver[^s].*|vers[^i].*|vers[^i].*|versi[^o].*|versio[^n].*|version[^_].*|version_[^f].*|version_f[^i].*|version_fi[^l].*|version_fil[^e].*);${CPACK_SOURCE_IGNORE_FILES}")
include (CPack)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/version.cpp.in
${CMAKE_CURRENT_BINARY_DIR}/version.cpp)
configure_file(
${PROJECT_SOURCE_DIR}/versionForSourcePackage.cmake.in
${PROJECT_BINARY_DIR}/version_file/versionForSourcePackage.cmake @ONLY)
В конце я использую модификацию первой возможности, но проблемы решаются только частично.
Вместо CPACK_INSTALL_COMMANDS, я использую CPACK_INSTALL_SCRIPT и сценарий CMake. Этот сценарий выполняется для каждого создаваемого пакета, и приятно то, что внутри этого сценария CMAKE_CURRENT_BINARY_DIR указывает на каталог, в котором собирается содержимое пакета. То есть все, что я копирую в этот каталог, попадет внутрь пакета.
Это, однако, выглядит недокументированным поведением CMAKE_CURRENT_BINARY_DIR. Например, CMAKE_BINARY_DIR а также PROJECT_BINARY_DIR пустые при использовании в скрипте CMake, выполняемом CPack. Так что, может быть, в какой-то другой версии CMake, CMAKE_CURRENT_BINARY_DIR также будет пустым при выполнении CPack.
Другая проблема заключается в том, что я хочу, чтобы файл версии копировался только в исходные пакеты, а не в двоичные пакеты. То, как я делаю различие в том, что если CMAKE_CURRENT_BINARY_DIR заканчивается на «Source», я предполагаю, что скрипт выполняется во время подготовки исходного пакета.
Полный пример в using_cpack_install_script филиал https://github.com/josefcibulka/version_git. Измененные части CMakeLists.txt:
# The following will transfer the version from git to the source package.
set(CPACK_INSTALL_SCRIPT "${CMAKE_BINARY_DIR}/versionNumberToPackage.cmake")
configure_file(${CMAKE_SOURCE_DIR}/versionNumberToPackage.cmake.in
${CMAKE_BINARY_DIR}/versionNumberToPackage.cmake @ONLY)
Содержимое versionNumberToPackage.cmake.in:
# Copies VersionForSourcePackage.cmake to the source package (it should not be copied to binary package).
# Detection if this is the source package is that the path ends with "Source" and an optional slash.
if("${CMAKE_CURRENT_BINARY_DIR}" MATCHES "Source/?$")
file(COPY @CMAKE_BINARY_DIR@/versionForSourcePackage.cmake DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
endif()
Других решений пока нет …