0%

在 Debian 中通过 MinGW-w64 编译 Windows 应用程序

在之前的博客中介绍了一个差分包工具 zstd(虽然说人家的专业是压缩软件,谁让它的差分能力那么出众呢)。

使用 Ztsd 代替 bsdiff/bspatch 差分还原文件

这货很能打,用起来也很爽。但是有个痛点就是制作差分包的时候有文件大小限制:不支持大于 2G 的文件。

但是在使用中经常遇到这种情况,为了彻底不再忍受 bsdiff 那蜗牛般的速度,遂决定通过修改 ztsd 源代码来支持对 2G 文件的支持。

由于我主要的使用场景是在 Windows 系统,所以记录的是构建 Windows 下的可执行程序。

但是我又不想在 Windows 下折腾 VSMinGW-w64,最终采用 Debian 容器安装 MinGW-w64 的方式来编译。

想要折腾 VS 或者 Windows 下的 MinGW-w64 的可以参考我的另外两篇笔记:

源码

zstd 的源码是开源的,地址在:https://github.com/facebook/zstd

因为我要修改,所以 fork 了一份:https://github.com/lx0758/zstd

克隆一份:

cd ~/projects/
git clone https://github.com/lx0758/zstd

镜像

基础环境镜像

构建镜像

docker build -t build-base - <<\EOF
FROM debian:12

RUN <<EOT
    sed -e 's|deb.debian.org|mirrors.tuna.tsinghua.edu.cn|g' -i.bak /etc/apt/sources.list.d/debian.sources
    apt update
    apt install -y sudo bash-completion command-not-found
    apt update
    apt clean && rm -rf /var/lib/apt/lists/*
EOT

COPY <<EOT /etc/profile.d/aliases.sh
alias ll='ls -lh -F --color=auto --time-style=long-iso'
alias la='ls -lhA -F --color=auto --time-style=long-iso'
alias lt='ls -lht -F --color=auto --time-style=long-iso'
alias lat='ls -lhAt -F --color=auto --time-style=long-iso'
EOT

ENV TZ=Asia/Shanghai
RUN <<EOT
    useradd --create-home --uid 1000 --groups users,sudo --shell /bin/bash user
    echo "user:1111" | chpasswd
    ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime
    echo "${TZ}" > /etc/timezone
EOT

USER user
WORKDIR /home/user/
EOF
  1. 使用管道输入 Dockerfile 内容,自定义镜像标签为 build-base
    https://docs.docker.com/build/building/context/#how-to-build-without-a-context
  2. 使用 Here-Documents 运行 RUNCOPY 指令,注意如果是在 Dockerfile 中使用需要保证文件换行符是 LF
    https://docs.docker.com/reference/dockerfile/#here-documents

使用镜像

docker run -ti --rm build-base bash -l
  1. 默认为 non-loginshell,需要使用 ‘-l’ 参数登录以生效 /etc/profile 配置。
    https://github.com/gliderlabs/docker-alpine/issues/443

编译环境镜像

构建镜像

docker build -t build-windows - <<\EOF
FROM build-base
USER root

RUN <<EOT
    apt update
    apt install -y make mingw-w64
    apt clean &&  rm -rf /var/lib/apt/lists/*
EOT

USER user
EOF
  1. 软件包 mingw-w64 提供了在 Linux 编译 Windowsx86x64 架构的程序的工具链.

使用镜像

docker run -ti --rm --privileged -v ~/projects/:/projects/ build-windows bash -l

构建

声明工具链

zstdMakefile 中默认没有设置工具链的配置,所以需要改造一下 Makefile

diff --git a/Makefile b/Makefile
index 5598cdd0..554a82f0 100644
--- a/Makefile
+++ b/Makefile
@@ -206,7 +206,7 @@ clangbuild-darwin-fat: clean
 	mv programs/zstd programs/zstd_x64
 	lipo -create programs/zstd_x64 programs/zstd_arm64 -output programs/zstd

-.PHONY: gcc5build gcc6build gcc7build clangbuild m32build armbuild aarch64build ppcbuild ppc64build
+.PHONY: gcc5build gcc6build gcc7build clangbuild m32build armbuild aarch64build ppcbuild ppc64build mingw64build
 gcc5build: clean
 	gcc-5 -v
 	CC=gcc-5 $(MAKE) all MOREFLAGS="-Werror $(MOREFLAGS)"
@@ -239,6 +239,10 @@ ppcbuild: clean
 ppc64build: clean
 	CC=powerpc-linux-gnu-gcc CFLAGS="-m64 -Werror" $(MAKE) -j allzstd

+mingw64build: clean
+	x86_64-w64-mingw32-gcc -v
+	CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-ar $(MAKE) all MOREFLAGS="$(MOREFLAGS)"
+
 .PHONY: armfuzz aarch64fuzz ppcfuzz ppc64fuzz
 armfuzz: clean
 	CC=arm-linux-gnueabi-gcc QEMU_SYS=qemu-arm-static MOREFLAGS="-static $(MOREFLAGS)" FUZZER_FLAGS="--no-big-tests $(FUZZER_FLAGS)" $(MAKE) -C $(TESTDIR) fuzztest
  1. x86_64-w64-mingw32-MingW-w64 编译 x64 软件的工具链前缀。
  2. i686-w64-mingw32-MingW-w64 编译 x86 软件的工具链前缀,我这没有用到。

修改源码

这个改动最终就比较大了,详情见提交:
https://github.com/lx0758/zstd/tree/64g

改了源码只验证了我需要的功能,没有补全单元测试用例。凑合用吧~

编译

cd /projects/

make TARGET_SYSTEM=Windows mingw64build

实践证明这个源码用这种方式编译不能开多线程,否则编译失败。

产物

相关的编译产物已经归档至 Github,方便有需要的朋友直接取用:
https://github.com/lx0758/zstd/releases

使用

# 创建差分补丁
$ ls -lh
总用量 14G
-rw-r--r-- 1 Liux 197121 6.5G 2024-10-19 23:23 zh-cn_windows_10_business_editions_version_22h2_updated_july_2024_x64_dvd_53d015e8.iso
-rw-r--r-- 1 Liux 197121 6.6G 2024-10-19 23:22 zh-cn_windows_11_business_editions_version_23h2_updated_july_2024_x64_dvd_8c3fbaa8.iso
$ sha1sum zh-cn_windows_11_business_editions_version_23h2_updated_july_2024_x64_dvd_8c3fbaa8.iso
4c80a05919a1eb838d5b5174bd4985e7374fca64 *zh-cn_windows_11_business_editions_version_23h2_updated_july_2024_x64_dvd_8c3fbaa8.iso
$ ./zstd.exe --patch-from=zh-cn_windows_10_business_editions_version_22h2_updated_july_2024_x64_dvd_53d015e8.iso  zh-cn
_windows_11_business_editions_version_23h2_updated_july_2024_x64_dvd_8c3fbaa8.iso -o windows.diff
long mode automatically triggered
zh-cn_windows_11_business_editions_version_23h2_updated_july_2024_x64_dvd_8c3fbaa8.iso : 87.73%   (  6.59 GiB =>   5.79 GiB, windows.diff)

# 差分还原
$ ../zstd.exe -d --patch-from=zh-cn_windows_10_business_editions_version_22h2_updated_july_2024_x64_dvd_53d015e8.iso windows.diff -o zh-cn_windows_11_business_editions_version_23h2_updated_july_2024_x64_dvd_8c3fbaa8.iso
windows.diff        : 7080916992 bytes
$ sha1sum zh-cn_windows_11_business_editions_version_23h2_updated_july_2024_x64_dvd_8c3fbaa8.iso
4c80a05919a1eb838d5b5174bd4985e7374fca64 *zh-cn_windows_11_business_editions_version_23h2_updated_july_2024_x64_dvd_8c3fbaa8.iso
  1. 这里使用两个基本不相关的 Windows 安装镜像做了测试,差分功能正常。
  2. 对于测试的这个 6.5G 超大文件差分操作,大约需要占用 7.5G 内存。内存不足会报 zstd: windows.diff: Permission denied 错误。
  • 本文作者: 6x
  • 本文链接: https://6xyun.cn/article/219
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-ND 许可协议。转载请注明出处!