使用 CMake 压缩文件?

Posted

技术标签:

【中文标题】使用 CMake 压缩文件?【英文标题】:zip files using CMake? 【发布时间】:2011-08-13 14:22:57 【问题描述】:

tl;dr 版本:

是否可以使用 CMake (>= 2.8) 从某些文件生成 zip 文件并将打包的 zip 文件放在特定位置?

更长的版本:

我有一个 CMakeLists.txt,它将我的项目构建成一个 .exe 文件,这个 exe 文件将从一个 zip 文件中读取数据。要打包到 zip 文件中的内容在我的 git 存储库中,因此也可以对其进行编辑。但是,该程序需要 zip 文件中的这些数据。因此,如果 CMake 脚本可以获取数据,将其放入 zip 文件中,并将其放在 exe 旁边,那就太好了。我已经听说过 CPack,但我没有找到任何简单的示例,并且不确定这是否适合我的任务。

这可能吗?如果是,怎么做?

【问题讨论】:

【参考方案1】:

自 3.2 版以来,CMake 具有生成内置 zip 文件的功能。 CMake command-line mode 子命令 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 版本的解决方法,您可以使用标准 Java JRE 安装中的jar 命令。

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
)

压缩文件将在当前 CMake 二进制目录 (CMAKE_CURRENT_BINARY_DIR) 中生成。

【讨论】:

此方法似乎创建了一个空的 zip 文件。但是,似乎我可以通过指定“files-from=files.txt”选项来创建填充档案。目录中的目录和文件似乎失败 啊,刚刚想通了..我将在下面解释我做了什么来让它工作【参考方案2】:

显示真正的答案永远不会迟到:

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)

【讨论】:

【参考方案3】:

我假设您已经安装了 zip 工具(WinZip 或 7z 等)。您可以编写一个 find_zip-tool 脚本来搜索 WinZip 或 7Z 等...

WinZip 的片段:

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

7-zip 的片段:

  FIND_PROGRAM(ZIP_EXECUTABLE 7z PATHS "$ENVProgramFiles/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,类似于sakra的回答

【讨论】:

【参考方案4】:

从 3.18 版开始,CMake 现在直接支持使用 file() 命令和 ARCHIVE_CREATE 创建 zip 或存档文件:

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

请务必为OUTPUT 压缩文件名指定完整路径,否则可能无法生成文件。此外,PATHS 选项接受 filesdirectories 放置在 zip 文件中,但它确实接受通配符写作。

此命令支持多种存档格式和压缩风格。因此,您也可以使用相同的命令来创建 tarball:

file(ARCHIVE_CREATE OUTPUT $CMAKE_CURRENT_BINARY_DIR/MyData.tar.gz
    PATHS $CMAKE_CURRENT_SOURCE_DIR/data
    FORMAT gnutar
    COMPRESSION GZip
)

【讨论】:

@yig 我不确定你的意思。此命令在 CMake configure 阶段运行,甚至在构建任何 CMake 目标之前。如果您想在构建 CMake 目标之后对其进行压缩,您可以使用 POST_BUILD 选项尝试类似 response 的操作。 我在问这个新的 3.18 文件(ARCHIVE_CREATE)功能是否可以在目标中使用。您的回答表明它不能。谢谢。【参考方案5】:

由于这是使用 CMake 创建 zip 文件的热门搜索结果,因此这里有一个 CPack 解决方案以确保完整性。基本思想是调用install(),然后告诉它为生成的zip 文件命名。它将被放置在构建目录中,尽管可能有一种方法可以改变它。然后您可以使用make packagecpack 创建压缩文件。

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

【讨论】:

【参考方案6】:

基本上我所做的是创建自定义目标

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

它将复制和压缩我需要的所有内容

【讨论】:

以上是关于使用 CMake 压缩文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何安装Cmake3.11.3-win32-x86

文件压缩

如何简单地将opencv包含在CMake的项目中

使用opensll加解密压缩文件

如何在Mac中压缩文件

文件的压缩和解压缩