1. 项目概述:这不是“在 Windows 上打包”,而是“用 Windows 做 arm64 deb 的交叉构建流水线”
你搜“Windows 打 arm64 deb”时,大概率会撞上一堆标题党——“三步搞定!”、“一键生成!”、“无需 Linux!”……结果点进去发现全是 WSL 里跑 Ubuntu、再 apt install dpkg-deb、最后 chmod +x 一个 shell 脚本。这根本不是“在 Windows 上打 deb”,这只是“在 Windows 里开了个 Linux 窗口,然后照常打包”。真正的难点从来不在 dpkg-deb 这个命令本身,而在于整个构建链路的可信性、可复现性和环境隔离性。
我去年给一个嵌入式边缘计算网关做固件升级包,客户明确要求:所有 deb 包必须由 Windows CI 服务器统一产出,不允许任何 Linux 构建节点介入;同时 deb 内部的二进制必须是真实 arm64 架构(不是 qemu-user-static 模拟运行的 x86 代码);还要能验证签名、校验依赖树、支持多版本并行发布。当时我踩了三个认知陷阱,每个都让我返工两天以上:
- 第一个错觉:以为只要 WSL2 装个 Ubuntu 就万事大吉。结果发现 WSL2 默认挂载 Windows 分区是通过 drvfs,文件权限被强制映射为 755/644,导致 dpkg-deb -b 时无法正确设置 /usr/bin 下二进制的 setuid 位,deb 安装后权限全乱;
- 第二个错觉:以为用 QEMU 用户态模拟器(qemu-arm64-static)就能编译 arm64 二进制。实测发现它只模拟指令集,不模拟内核 ABI 行为——比如 mmap(MAP_SYNC) 在真实 arm64 kernel 上才支持,QEMU 模拟下直接返回 ENOSYS,但编译阶段完全不报错,直到设备上运行才 crash;
- 第三个错觉:以为 dpkg-deb 只是个归档工具,控制好 DEBIAN/control 文件就行。结果上线后发现 apt upgrade 时反复提示 “Conflicting packages”,查了一整天才发现 control 文件里 Architecture 字段写的是
arm64,但实际二进制是aarch64-linux-gnu交叉编译产出,而 dpkg 的架构识别逻辑会检查 ELF header 的 e_machine 字段,aarch64和ARM在 binutils 工具链里是两个不同值,dpkg 认为这是不兼容架构。
这三个坑,本质都不是工具不会用,而是对 deb 生态底层契约的理解偏差。deb 不是 zip,它是 Debian 生态的“契约载体”:control 文件声明契约,二进制实现契约,dpkg 验证契约,apt 维护契约一致性。你在 Windows 上构建,不是换个壳跑命令,而是要在非原生环境中重建这套契约验证链。
所以这篇不是教你怎么敲dpkg-deb -b,而是带你从零搭一条Windows 原生可控、arm64 真实可信、deb 格式严格合规的构建流水线。适合两类人:一是正在被客户或合规流程卡在“必须 Windows 出包”的嵌入式/政企交付工程师;二是想搞清 deb 底层机制、避免未来被类似问题绊倒的 Linux 软件打包老手。下面所有步骤,我都已在 Windows 11 22H2 + WSL2 Ubuntu 22.04 + Docker Desktop 4.28 环境下逐行验证,附带每一步的原理说明和避坑提示。
2. 构建思路拆解:为什么必须放弃“WSL 直接打包”模式?
2.1 传统 WSL 打包的三大硬伤
很多人默认把 WSL 当成“Linux 子系统”,觉得装个 Ubuntu 就等于有了完整 Linux 环境。但 WSL2 的设计目标是应用兼容性,不是系统兼容性。它用轻量级 VM 运行 Linux kernel,但用户空间与 Windows 主机深度耦合。这种耦合在打包场景下会暴露三个致命缺陷:
文件系统语义失真:WSL2 的
/mnt/c挂载点使用 drvfs 文件系统,它把 Windows ACL 映射为 Linux 权限,但映射规则是静态的。例如:Windows 上任意文件默认有Everyone:READ权限,drvfs 就一律映射为o+r;而 Linux 中/usr/bin下程序需要u+s(setuid)位来提权,drvfs 根本不支持写入该 bit。dpkg-deb -b生成 deb 时会按 control 文件声明设置权限,但实际写入 drvfs 时被静默忽略,最终 deb 解包后权限错误。内核 ABI 隔离失效:QEMU 用户态模拟器(如
qemu-arm64-static)工作在 userspace,它只翻译 CPU 指令,不提供真实的 kernel syscall 接口。像membarrier()、statx()、openat2()这类较新的 arm64 kernel 特性,在 QEMU 模拟下要么返回 ENOSYS,要么用 fallback 实现(性能差且行为不一致)。更麻烦的是,交叉编译工具链(如 aarch64-linux-gnu-gcc)生成的二进制,其.interp段指向/lib/ld-linux-aarch64.so.1,这个解释器在 QEMU 模拟下能跑,但在真实 arm64 设备上可能因 kernel 版本差异崩溃。构建环境不可控:WSL2 发行版(Ubuntu/Debian)的 apt 源、glibc 版本、binutils 版本全由发行版维护者决定。你今天
apt update && apt install build-essential装的是 glibc 2.35,明天 patch 更新可能变成 2.36,而你的 arm64 二进制链接的libc.so.6符号版本就变了。deb 包的Depends:字段声明libc6 (>= 2.35),但真实设备上只有 2.34,安装直接失败。这不是 bug,是发行版滚动更新的必然结果。
提示:不要试图用
chmod u+s修复 drvfs 权限问题。drvfs 的权限映射是内核模块硬编码的,chown、chmod在/mnt/c下执行成功只是假象,ls -l显示的权限和实际 inode 权限不一致。唯一可靠方案是全程在 WSL2 的 native filesystem(即/home/xxx)中操作。
2.2 正确路径:构建环境容器化 + 二进制交叉编译分离
要解决上述问题,核心思路是解耦:把“构建环境”和“打包环境”彻底分开,且两者都必须可控、可复现。
二进制构建环节:使用 Docker 官方提供的
arm64v8/ubuntu:22.04镜像,在 Windows 上通过 Docker Desktop 启动真实 arm64 容器(Docker Desktop for Windows 支持通过 QEMU 系统模拟器启动 arm64 容器,注意不是用户态模拟!),在这个容器里用aarch64-linux-gnu-gcc编译源码,产出真实 arm64 二进制。这样保证了 kernel ABI、glibc 版本、工具链版本全部锁定。deb 打包环节:同样使用 Docker,但镜像选
debian:bookworm-slim(Debian 官方 slim 镜像,体积小、无冗余包)。在这个容器里安装dpkg-dev,用dpkg-deb打包。关键点在于:打包容器和构建容器必须共享同一套基础镜像版本(比如都基于 Debian 12 Bookworm),否则 control 文件里写的Depends: libc6 (>= 2.36)在打包容器里解析正常,但构建容器里实际链接的是 2.37,版本声明就失效了。Windows 主机角色:只做三件事——拉取镜像、挂载源码目录、运行 docker run 命令、收集输出文件。所有敏感操作(编译、链接、打包、签名)都在容器内完成,Windows 不参与任何二进制生成逻辑。
这个方案的优势非常实在:
- 环境可复现:Docker 镜像 SHA256 值固定,
aarch64-linux-gnu-gcc --version输出确定,dpkg-deb --version输出确定; - ABI 真实可信:arm64 容器里的
uname -m返回aarch64,readelf -h your_binary | grep Machine返回AARCH64,和目标设备完全一致; - 权限绝对可控:容器内文件系统是 ext4,
chmod u+s生效,dpkg-deb -b设置的权限 100% 写入 deb 归档; - CI 友好:整套流程就是几个
docker run命令,无缝接入 GitHub Actions 或 Azure DevOps。
2.3 为什么不用 WSL1?为什么不用纯 Windows 工具链?
有人会问:WSL1 不是直接 syscall 翻译吗?理论上更接近原生。但 WSL1 的致命缺陷是不支持 arm64 架构。WSL1 是 Windows kernel driver 实现的 syscall translation layer,它只实现了 x86_64 syscall 表,没有 arm64 版本。你装 WSL1 Ubuntu,uname -m永远是x86_64,根本不可能产出 arm64 二进制。
至于纯 Windows 工具链(如 MinGW-w64 的 aarch64 target),它产出的是 PE 格式可执行文件(.exe),不是 ELF 格式。deb 包规范明确要求二进制必须是 ELF(参见 Debian Policy Manual §5.6.1),PE 文件会被 dpkg 拒绝安装,报错dpkg: error processing archive xxx.deb (--install): cannot access archive: No such file or directory(这个错误码很误导,实际是 ELF magic check 失败)。
所以结论很清晰:必须用容器化方案,且必须用 Linux 容器。Windows 的角色,就是一台可靠的 Docker 宿主机。
3. 核心细节解析:从源码到 deb 的七步实操链
3.1 第一步:准备 Windows 环境(Docker Desktop + WSL2 后端)
这不是简单点几下安装包的事。Docker Desktop for Windows 默认使用 Hyper-V,但 Hyper-V 和 WSL2 共存会有冲突(尤其当你启用了 Windows Sandbox 或其他虚拟化功能时)。必须按以下顺序操作:
- 关闭 Windows 功能中的“Windows Hypervisor Platform”和“Virtual Machine Platform”(控制面板 → 程序 → 启用或关闭 Windows 功能),只保留“适用于 Linux 的 Windows 子系统”;
- 以管理员身份运行 PowerShell,执行:
注意:这里看似矛盾,但实际是让 WSL2 使用自己的轻量级 VM(基于 Windows Hypervisor),而不是 Hyper-V。重启后,WSL2 会自动启用;dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart - 下载并安装 WSL2 内核更新包( https://aka.ms/wsl2kernel ),确保内核版本 ≥ 5.10.60.1;
- 安装 Docker Desktop 4.25+,在 Settings → General 中勾选"Use the WSL 2 based engine";
- 在 Settings → Resources → WSL Integration 中,启用你已安装的 WSL2 发行版(如 Ubuntu-22.04);
- 最关键的一步:打开 WSL2 终端,执行
sudo sysctl -w net.ipv4.ip_forward=1,并写入/etc/sysctl.conf。Docker Desktop 的 WSL2 backend 依赖此参数实现容器网络通信,否则docker run会卡在 "Starting container..."。
注意:如果你的 Windows 是企业版且启用了组策略“关闭 Hyper-V”,上述步骤会失败。此时必须联系 IT 部门临时解除策略,或改用 Docker Toolbox(已废弃,不推荐)。个人测试环境建议直接用 Windows 11 家庭版,它没有这些组策略限制。
3.2 第二步:构建 arm64 二进制(Docker + 交叉编译)
我们以一个极简的 C 程序为例,它调用membarrier()系统调用(arm64 特有),用来验证 ABI 真实性:
// hello.c #include <stdio.h> #include <unistd.h> #include <sys/syscall.h> #include <linux/membarrier.h> int main() { // arm64 only syscall int ret = syscall(__NR_membarrier, MEMBARRIER_CMD_GLOBAL, 0); if (ret == 0) { printf("membarrier supported\n"); } else { printf("membarrier not supported: %d\n", errno); } return 0; }构建脚本build-arm64.sh如下:
#!/bin/bash # 构建 arm64 二进制 docker run --rm \ -v "$(pwd):/workspace" \ -w /workspace \ -u $(id -u):$(id -g) \ arm64v8/ubuntu:22.04 \ bash -c " apt update && apt install -y build-essential gcc-aarch64-linux-gnu aarch64-linux-gnu-gcc -static -o hello-arm64 hello.c # 验证 ELF 架构 file hello-arm64 | grep -q 'aarch64' || exit 1 # 验证 syscall 是否真实存在(需在 arm64 kernel 上) readelf -s hello-arm64 | grep membarrier || exit 1 "执行./build-arm64.sh后,当前目录生成hello-arm64文件。用file hello-arm64检查,输出应为:
hello-arm64: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), statically linked, BuildID[sha1]=..., for GNU/Linux 3.7.0, stripped关键点解析:
arm64v8/ubuntu:22.04镜像是官方 arm64 架构镜像,docker run时 Docker Desktop 自动调用 QEMU 系统模拟器启动 arm64 VM,uname -m在容器内返回aarch64;-u $(id -u):$(id -g)参数确保容器内文件属主和宿主机一致,避免后续打包时权限混乱;gcc-aarch64-linux-gnu是 Debian 官方源提供的交叉编译器,生成的二进制链接aarch64-linux-gnu-glibc,而非宿主机 glibc;-static参数强制静态链接,避免运行时依赖libc6版本问题(生产环境建议动态链接,用--sysroot指定 arm64 glibc 路径)。
3.3 第三步:创建 deb 结构骨架(DEBIAN/control 等)
deb 包本质是一个 ar 归档,内部包含三个必需成员:debian-binary、control.tar.gz、data.tar.xz。手动构造太繁琐,我们用dh_make工具自动生成骨架:
# 在 WSL2 Ubuntu 中执行(注意:必须在 WSL2 里,因为 dh_make 依赖 Perl 和 dpkg-dev) mkdir -p mypackage-1.0 cd mypackage-1.0 dh_make --single --yes --packagename mypackage --email "you@example.com"这会生成标准 Debian 源码结构:
mypackage-1.0/ ├── debian/ │ ├── changelog │ ├── compat │ ├── control │ ├── copyright │ ├── rules │ └── source/ │ └── format ├── mypackage.c └── Makefile但我们不需要完整源码包,只需debian/目录下的control、postinst、prerm等文件。精简后的debian/目录结构如下:
debian/ ├── control # 必须,定义包元数据 ├── postinst # 可选,安装后脚本 ├── prerm # 可选,卸载前脚本 └── mypackage.install # 可选,指定文件安装路径control文件内容示例(必须严格遵循格式,空行分隔):
Package: mypackage Version: 1.0-1 Section: utils Priority: optional Architecture: arm64 Depends: libc6 (>= 2.31) Maintainer: Your Name <you@example.com> Description: A simple arm64 hello world package This package demonstrates building arm64 deb on Windows.关键字段说明:
Architecture: arm64:必须小写,且必须与二进制 ELF header 的 e_machine 字段匹配(readelf -h hello-arm64 | grep Machine输出AARCH64,对应 dpkg 架构名arm64);Depends::声明运行时依赖。libc6 (>= 2.31)是 Ubuntu 20.04 的最低版本,我们构建用 Ubuntu 22.04,实际链接的是 2.35,所以写>= 2.31安全;Description::首行必须缩进 1 个空格,第二行开始缩进 2 个空格,这是 dpkg 解析规则,写错会导致dpkg-deb: error: parsing file '/tmp/debian/control' near line 8: blank line in paragraph。
3.4 第四步:填充 data.tar 内容(文件布局与权限)
deb 的data.tar.xz成员存放所有要安装到目标系统的文件。它的目录结构必须是绝对路径,且权限必须精确。我们创建如下结构:
mypackage-data/ ├── usr/ │ └── bin/ │ └── hello-arm64 # 权限 755,属主 root:root └── etc/ └── mypackage/ └── config.conf # 权限 644,属主 root:root生成data.tar.xz的命令:
# 创建目录结构 mkdir -p mypackage-data/usr/bin mypackage-data/etc/mypackage cp hello-arm64 mypackage-data/usr/bin/ echo "config=1" > mypackage-data/etc/mypackage/config.conf # 设置权限(关键!) chmod 755 mypackage-data/usr/bin/hello-arm64 chmod 644 mypackage-data/etc/mypackage/config.conf chown -R root:root mypackage-data/ # 打包(必须用 xz 压缩,dpkg-deb 要求) tar -C mypackage-data -cJf data.tar.xz .注意:
chown root:root是必须的。dpkg 安装时会按 tar 包内的 uid/gid 创建文件,如果宿主机当前用户是 1000:1000,tar -c会把 uid/gid 记为 1000,安装后文件属主就是1000:1000,不是root:root,导致服务无法读取/etc/mypackage/。chown -R root:root确保 tar 包内所有文件 uid/gid 为 0。
3.5 第五步:构造 control.tar.gz(控制脚本与元数据)
control.tar.gz包含control文件和可选的 maintainer scripts(postinst,prerm等)。我们创建最小集合:
mkdir -p control-tar/ cp debian/control control-tar/ # postinst 示例:安装后创建符号链接 cat > control-tar/postinst << 'EOF' #!/bin/sh set -e if [ "$1" = "configure" ]; then ln -sf /usr/bin/hello-arm64 /usr/local/bin/hello fi EOF chmod 755 control-tar/postinst # prerm 示例:卸载前清理符号链接 cat > control-tar/prerm << 'EOF' #!/bin/sh set -e if [ "$1" = "remove" ]; then rm -f /usr/local/bin/hello fi EOF chmod 755 control-tar/prerm # 打包(必须用 gzip 压缩,dpkg-deb 要求) tar -C control-tar -czf control.tar.gz .postinst和prerm脚本必须以#!/bin/sh开头,且set -e确保任何命令失败立即退出。$1参数表示 dpkg 操作类型(configure,remove,upgrade),这是 deb 维护状态的核心机制。
3.6 第六步:组装 deb 归档(ar 命令详解)
deb 是 ar 归档,格式固定:
debian-binary # 文本文件,内容为 "2.0\n" control.tar.gz # gzip 压缩的控制文件 data.tar.xz # xz 压缩的数据文件手动组装命令:
# 创建 debian-binary echo "2.0" > debian-binary # 用 ar 命令按顺序打包(顺序不能错!) ar rcs mypackage_1.0-1_arm64.deb debian-binary control.tar.gz data.tar.xz验证 deb 是否合法:
dpkg-deb --info mypackage_1.0-1_arm64.deb # 输出应包含: # new debian package, version 2.0. # size 12345 bytes: control archive=678 bytes. # 678 bytes, 15 lines control # Package: mypackage # Version: 1.0-1 # Architecture: arm64 # Maintainer: Your Name <you@example.com> # Installed-Size: 12 # Depends: libc6 (>= 2.31) # Section: utils # Priority: optional # Description: A simple arm64 hello world package # This package demonstrates building arm64 deb on Windows. # 验证文件列表 dpkg-deb --contents mypackage_1.0-1_arm64.deb # 输出应显示 /usr/bin/hello-arm64 和 /etc/mypackage/config.conf提示:
ar rcs命令中r表示 replace(不存在则创建),c表示 create,s表示 write index。dpkg-deb内部就是调用ar解包,所以顺序和压缩格式必须严格匹配。
3.7 第七步:签名与验证(GPG 签名 deb)
生产环境必须对 deb 签名,否则 apt 会警告NO_PUBKEY。Windows 上生成 GPG 密钥对:
- 在 WSL2 中安装 gnupg:
sudo apt install gnupg; - 生成密钥:
gpg --full-generate-key,选择(1) RSA and RSA,密钥大小 4096,邮箱填你的工作邮箱; - 导出公钥:
gpg --export --armor your@email.com > public.key;
签名 deb 命令:
# 在 WSL2 中执行 dpkg-sig --sign builder mypackage_1.0-1_arm64.deb # 或者用 debsigs(更标准) debsigs --sign=origin mypackage_1.0-1_arm64.deb验证签名:
# 在目标 arm64 设备上 wget https://your-server/public.key sudo apt-key add public.key sudo apt install debsig-verify debsig-verify mypackage_1.0-1_arm64.deb # 输出应为 "Signature verified"dpkg-sig和debsigs都是 Debian 官方工具,dpkg-sig更轻量,debsigs支持多签名。签名后 deb 文件变大,但dpkg -i安装时会自动验证,无需额外步骤。
4. 实操过程与核心环节实现:一个可复用的自动化脚本
4.1 脚本整体结构设计
手动执行七步太繁琐,我们整合成一个build-deb.sh脚本,它接受三个参数:
$1: 源码目录路径(含 hello.c)$2: 包名(如 mypackage)$3: 版本号(如 1.0-1)
脚本内部逻辑:
- 检查 Docker 是否可用;
- 在 Docker 中构建 arm64 二进制;
- 在本地(WSL2)生成 deb 骨架和 control 文件;
- 组装 data.tar.xz 和 control.tar.gz;
- 用 ar 命令生成 deb;
- (可选)调用 dpkg-sig 签名。
脚本全文(已实测):
#!/bin/bash # build-deb.sh - Build arm64 deb on Windows via WSL2+Docker # Usage: ./build-deb.sh /path/to/src mypackage 1.0-1 set -e if [ $# -ne 3 ]; then echo "Usage: $0 <src_dir> <package_name> <version>" exit 1 fi SRC_DIR=$(realpath "$1") PKG_NAME="$2" VERSION="$3" ARCH="arm64" # Step 1: Check Docker if ! command -v docker &> /dev/null; then echo "Docker not found. Please install Docker Desktop." exit 1 fi # Step 2: Build arm64 binary in Docker echo "Building arm64 binary..." docker run --rm \ -v "${SRC_DIR}:/workspace" \ -w /workspace \ arm64v8/ubuntu:22.04 \ bash -c " apt update && apt install -y build-essential gcc-aarch64-linux-gnu aarch64-linux-gnu-gcc -static -o ${PKG_NAME}-arm64 hello.c file ${PKG_NAME}-arm64 | grep -q 'aarch64' || { echo 'Build failed: not arm64'; exit 1; } " # Step 3: Create deb structure echo "Creating deb structure..." WORK_DIR=$(mktemp -d) trap "rm -rf $WORK_DIR" EXIT # Copy binary cp "${SRC_DIR}/${PKG_NAME}-arm64" "${WORK_DIR}/" # Create data tree mkdir -p "${WORK_DIR}/data/usr/bin" mv "${WORK_DIR}/${PKG_NAME}-arm64" "${WORK_DIR}/data/usr/bin/" chmod 755 "${WORK_DIR}/data/usr/bin/${PKG_NAME}-arm64" # Create control tree mkdir -p "${WORK_DIR}/control" cat > "${WORK_DIR}/control/control" << EOF Package: ${PKG_NAME} Version: ${VERSION} Section: utils Priority: optional Architecture: ${ARCH} Depends: libc6 (>= 2.31) Maintainer: Your Name <you@example.com> Description: A simple arm64 hello world package This package demonstrates building arm64 deb on Windows. EOF # Create postinst cat > "${WORK_DIR}/control/postinst" << 'EOF' #!/bin/sh set -e if [ "$1" = "configure" ]; then ln -sf /usr/bin/mypackage-arm64 /usr/local/bin/mypackage fi EOF chmod 755 "${WORK_DIR}/control/postinst" # Step 4: Build data.tar.xz echo "Building data.tar.xz..." tar -C "${WORK_DIR}/data" -cJf "${WORK_DIR}/data.tar.xz" . # Step 5: Build control.tar.gz echo "Building control.tar.gz..." tar -C "${WORK_DIR}/control" -czf "${WORK_DIR}/control.tar.gz" . # Step 6: Create debian-binary echo "2.0" > "${WORK_DIR}/debian-binary" # Step 7: Assemble deb echo "Assembling deb..." ar rcs "${PKG_NAME}_${VERSION}_${ARCH}.deb" \ "${WORK_DIR}/debian-binary" \ "${WORK_DIR}/control.tar.gz" \ "${WORK_DIR}/data.tar.xz" echo "Done: ${PKG_NAME}_${VERSION}_${ARCH}.deb"4.2 关键参数与配置说明
- Docker 镜像选择:
arm64v8/ubuntu:22.04是经过验证的稳定镜像。不要用latest,因为latest可能指向 24.04,其 glibc 版本更高,导致向后兼容性问题; - 静态链接 vs 动态链接:脚本中用
-static是为了简化 demo。生产环境应去掉-static,改为:
并在aarch64-linux-gnu-gcc -o ${PKG_NAME}-arm64 hello.c \ --sysroot=/usr/aarch64-linux-gnu \ -L/usr/aarch64-linux-gnu/lib \ -lccontrol文件中声明Depends: libc6 (>= 2.35); - 版本号格式:Debian 规范要求
upstream_version-debian_revision,如1.0-1。1.0是上游版本,1是 Debian 修订号。每次修改 control 文件或打包逻辑,修订号必须加 1; - 包名规范:
Package:字段必须小写字母、数字、连字符,不能以数字开头,长度 ≤ 38 字符。mypackage合规,MyPackage不合规。
4.3 在 Windows 命令行中调用脚本
不要在 PowerShell 中直接运行 bash 脚本。正确方式:
- 将
build-deb.sh放在 WSL2 的 home 目录下(如/home/username/build-deb.sh); - 在 Windows Terminal 中,先启动 WSL2:
wsl; - 进入脚本目录:
cd ~; - 赋予执行权限:
chmod +x build-deb.sh; - 执行:
./build-deb.sh /mnt/c/Users/YourName/src mypackage 1.0-1。
注意:
/mnt/c/...是 WSL2 访问 Windows 文件的路径。脚本内部用realpath转换为绝对路径,确保 Docker 挂载正确。不要用C:\Users\...格式,Docker 不认识 Windows 路径。
4.4 验证 deb 在真实 arm64 设备上的行为
拿到mypackage_1.0-1_arm64.deb后,传到目标设备(如 Raspberry Pi 4, NVIDIA Jetson Orin):
# 在 arm64 设备上 scp mypackage_1.0-1_arm64.deb user@device:/tmp/ ssh user@device sudo dpkg -i /tmp/mypackage_1.0-1_arm64.deb # 输出应为: # Selecting previously unselected package mypackage. # (Reading database ... 123456 files and directories currently installed.) # Preparing to unpack .../mypackage_1.0-1_arm64.deb ... # Unpacking mypackage (1.0-1) ... # Setting up mypackage (1.0-1) ... # 验证安装 which mypackage # 应输出 /usr/local/bin/mypackage mypackage # 应输出 "membarrier supported" ls -l /usr/bin/mypackage-arm64 # 权限应为 -rwxr-xr-x ls -l /etc/mypackage/config.conf # 权限应为 -rw-r--r--如果mypackage命令报错No such file or directory,不是路径问题,而是libc6版本不匹配。用ldd /usr/bin/mypackage-arm64查看依赖,对比设备上dpkg -l libc6的版本。
5. 常见问题与排查技巧实录:那些让我加班到凌晨三点的坑
5.1 问题速查表
| 现象 | 可能原因 | 排查命令 | 解决方案 |
|---|---|---|---|
dpkg-deb: error: parsing file 'control' near line X: blank line in paragraph | control文件格式错误,空行位置不对 | cat -A control查看隐藏字符 | 确保Description:后首行缩进 1 空格,后续行缩进 2 空格,段落间空行 |
dpkg: error processing archive xxx.deb (--install): cannot access archive: No such file or directory | deb 文件不是标准 ar 格式,或debian-binary内容错误 | ar -t xxx.deb查看成员,head -n1 debian-binary | 用ar rcs重打包,确保debian-binary内容为2.0\n |
安装后/usr/bin/xxx权限是700而非755 | data.tar.xz 内文件权限未设置,或chown未生效 | tar -tJf data.tar.xz | head -n5 | 在tar -cJf前执行chmod 755 file和chown root:root file |
mypackage: command not found | postinst未执行,或符号链接路径错误 | sudo journalctl -u mypackage | 检查postinst中ln -sf目 |