zip файлы с помощью CMake?

tl;dr версия:

Возможно ли с помощью CMake (›= 2.8) создавать zip-файлы из некоторых файлов и помещать упакованный zip-файл в определенное место?

более длинная версия:

У меня есть CMakeLists.txt, который создает мой проект в файле .exe, и этот файл exe будет считывать данные из zip-файла. Содержимое, которое нужно упаковать в zip-файл, находится в моем репозитории git, так что его тоже можно редактировать. Но программе нужны эти данные в zip-файле. Поэтому было бы хорошо, если бы сценарий CMake мог взять данные, поместить их в zip-файл и поместить рядом с exe. Я уже слышал о CPack, но не нашел простых примеров и не уверен, что это вообще подходящий инструмент для моей задачи.

Это возможно? Если да, то как?


person blubberbernd    schedule 13.08.2011    source источник


Ответы (6)


Начиная с версии 3.2 CMake имеет встроенную функцию создания zip-файла. режим командной строки CMake подкоманда tar поддерживает создание архивов zip и 7zip.

Например, если текущий исходный каталог CMake содержит файл testfile.txt и каталог testdir, вы можете использовать следующие команды CMake для создания ZIP-файла, содержащего оба элемента:

add_custom_target(create_zip COMMAND
    ${CMAKE_COMMAND} -E tar "cfv" "archive.zip" --format=zip
       "${CMAKE_CURRENT_SOURCE_DIR}/testfile.txt"
       "${CMAKE_CURRENT_SOURCE_DIR}/testdir")

В качестве обходного пути для более ранних версий CMake вы можете использовать jar, которая является частью стандартной установки Java JRE.

find_package(Java)

execute_process(
    COMMAND
        "${Java_JAR_EXECUTABLE}" "cfM" "archive.zip" 
        "-C" "${CMAKE_CURRENT_SOURCE_DIR}" "testfile.txt" 
        "-C" "${CMAKE_CURRENT_SOURCE_DIR}" "testdir"
    RESULT_VARIABLE _result
)

ZIP-файл будет создан в текущем каталоге двоичных файлов CMake (CMAKE_CURRENT_BINARY_DIR).

person sakra    schedule 13.08.2011
comment
Этот метод создает пустой zip-файл. Однако, похоже, я могу создать заполненный архив, указав опцию files-from=files.txt. Кажется, сбой с каталогами и файлами в каталогах - person Begui; 07.01.2018
comment
Ааа, только что понял. Ниже я объясню, что я сделал, чтобы заставить это работать. - person Begui; 07.01.2018

Никогда не поздно показать реальный ответ:

function(create_zip output_file input_files working_dir)
    add_custom_command(
        COMMAND ${CMAKE_COMMAND} -E tar "cf" "${output_file}" --format=zip -- ${input_files}
        WORKING_DIRECTORY "${working_dir}"
        OUTPUT  "${output_file}"
        DEPENDS ${input_files}
        COMMENT "Zipping to ${output_file}."
    )
endfunction()

Используйте как

file(GLOB ZIP_FILES "${CMAKE_CURRENT_SOURCE_DIR}/zip/*")
create_zip("${CMAKE_CURRENT_BINARY_DIR}/native_data.zip" "${ZIP_FILES}" "${CMAKE_CURRENT_SOURCE_DIR}/zip")

Это упакует все файлы из подкаталога zip/ в native_data.zip (в каталоге сборки). Затем либо включите свой архив (путь будет отличаться для разных CMakeLists.txt!) в качестве исходного файла, либо добавьте его в качестве цели:

add_custom_target("project-data" ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/native_data.zip")

Установка не сильно будет отличаться от обычной:

install(FILES "${CMAKE_CURRENT_BINARY_DIR}/native_data.zip" DESTINATION ${DATADIR} RENAME "data000.zip") # Install our zip (as data000.zip)
person val is still with Monica    schedule 29.10.2018

Я предполагаю, что у вас уже установлен zip-инструмент (WinZip или 7z и т. д.). Вы можете написать скрипт find_zip-tool, который будет искать WinZip, 7Z и т. д.

Фрагмент для WinZip:

FIND_PROGRAM(ZIP_EXECUTABLE wzzip PATHS "$ENV{ProgramFiles}/WinZip")
IF(ZIP_EXECUTABLE)
  SET(ZIP_COMMAND "\"${ZIP_EXECUTABLE}\" -P \"<ARCHIVE>\" @<FILELIST>")
ENDIF(ZIP_EXECUTABLE)

Фрагмент для 7-zip:

  FIND_PROGRAM(ZIP_EXECUTABLE 7z PATHS "$ENV{ProgramFiles}/7-Zip") 
  IF(ZIP_EXECUTABLE)
    SET(ZIP_COMMAND "\"${ZIP_EXECUTABLE}\" a -tzip \"<ARCHIVE>\" @<FILELIST>")
  ENDIF(ZIP_EXECUTABLE)

Взгляните на файл

<cmake-install-dir>\share\cmake-2.8\Modules\CPackZIP.cmake

он показывает, как CPack ищет Zip_Executable и подготавливает некоторые «полезные» флаги по умолчанию.

После этого я бы предложил выполнить execute_process, аналогично ответу сакры.

person André    schedule 31.08.2011

Начиная с версии 3.18, CMake теперь напрямую поддерживает создание zip или архивных файлов с помощью команды file() с ARCHIVE_CREATE:

file(ARCHIVE_CREATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/MyData.zip
    PATHS ${CMAKE_CURRENT_SOURCE_DIR}/data
    FORMAT zip
)

Обязательно укажите полный путь для OUTPUT архивного имени файла, иначе файл не будет создан. Кроме того, параметр PATHS допускает размещение файлов или каталогов в zip-файле, но на момент написания он не принимает подстановочные знаки.

Эта команда поддерживает несколько форматов архивов и вариантов сжатия. Таким образом, вы можете использовать ту же команду для создания архивов:

file(ARCHIVE_CREATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/MyData.tar.gz
    PATHS ${CMAKE_CURRENT_SOURCE_DIR}/data
    FORMAT gnutar
    COMPRESSION GZip
)
person squareskittles    schedule 15.07.2020
comment
@yig Я не понимаю, что ты имеешь в виду. Эта команда запускается на этапе configure CMake, еще до того, как будет создана какая-либо из ваших целей CMake. Если вы хотите заархивировать цели CMake после их создания, вы можете попробовать что-то вроде этого ответ используя опцию POST_BUILD. - person squareskittles; 12.10.2020
comment
Я спрашивал, можно ли использовать эту новую функциональность файла 3.18 (ARCHIVE_CREATE) в цели. Ваш ответ разъясняет, что это невозможно. Спасибо. - person yig; 13.10.2020

Поскольку это лучший результат поиска для создания zip-файлов с помощью CMake, вот решение CPack для полноты картины. Основная идея заключается в том, что вы вызываете install(), а затем сообщаете ему, как назвать получившийся zip-файл. Он будет помещен в каталог сборки, хотя это можно изменить. Затем вы можете создать zip-файл с make package или cpack.

# Version 1: Subtractive
# Include everything in the project source directory.
# Put it at the top level of the zip via `DESTINATION .`
# Subtract things we don't want.
# The trailing slash after "${PROJECT_SOURCE_DIR}/" prevents
# an extra layer of directories.
install(DIRECTORY "${PROJECT_SOURCE_DIR}/"
    DESTINATION .
    PATTERN ".git*" EXCLUDE
    PATTERN ".DS_Store" EXCLUDE
    PATTERN "examples" EXCLUDE
    PATTERN "docs" EXCLUDE
    PATTERN "README.md" EXCLUDE
)

# Version 2: Additive
# Include only the list of things we specify.
# Put it at the top level of the zip via `DESTINATION .`
# install(FILES
#     ${SRCS}
#     "Notes.txt"
#     DESTINATION .
# )

# Tell CPack to create a zip file.
set(CPACK_GENERATOR "ZIP")
# Tell CPack what to name the zip file. It will append `.zip`.
set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}")
# Tell CPack not to put everything inside an enclosing directory.
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
# Apparently this should be always on but isn't for backwards compatibility.
set(CPACK_VERBATIM_VARIABLES YES)
include(CPack)
person yig    schedule 12.10.2020

По сути, я создал пользовательскую цель

add_custom_target(STAGE_FILES)

С этой целью я копирую файлы и каталоги в CMAKE_CURRENT_BINARY_DIR

add_custom_command( 
  TARGET STAGE_FILES 
  COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/assets/video ${CMAKE_CURRENT_BINARY_DIR}/video
  COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/assets/data ${CMAKE_CURRENT_BINARY_DIR}/data
  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/assets/strings_en.csv ${CMAKE_CURRENT_BINARY_DIR}/
  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/assets/strings_rules_en.csv ${CMAKE_CURRENT_BINARY_DIR}/
  COMMAND ${CMAKE_COMMAND} -E tar "cfv" "data.zip" --format=zip  --files-from=${CMAKE_SOURCE_DIR}/assets/to_zip.txt
  COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/data
  COMMAND ${CMAKE_COMMAND} -E rename  ${CMAKE_CURRENT_BINARY_DIR}/data.zip ${CMAKE_CURRENT_BINARY_DIR}/data
)

Важная линия

COMMAND ${CMAKE_COMMAND} -E tar "cfv" "data.zip" --format=zip  --files-from=${CMAKE_SOURCE_DIR}/assets/to_zip.txt

внутри моего

to_zip.txt

Я указываю все файлы, которые хочу включить в свой zip

data/
video/
...

Теперь я могу выполнить команду

make STAGE_FILES

который скопирует и заархивирует все, что мне нужно

person Begui    schedule 11.01.2018