使用 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
选项接受 files 或 directories 放置在 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 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)
【讨论】:
【参考方案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 压缩文件?的主要内容,如果未能解决你的问题,请参考以下文章