可以。你现在踩到的不是单个 `libc6` 问题,而是 **Debian/Ubuntu 发行版安装系统时自动维护了一整套隐式约定**。你自己做精简 sysroot 时,这些隐式行为都要手动还原,否则 GCC/ld/CMake 会报各种“明明有文件但找不到”的错误。 下面一次说完整。 --- # 1. 发行版真正安装包时做了什么 Ubuntu 不是简单把 `.deb` 文件解压到 `/`。正常 `apt install` / `dpkg -i` 会做这些事: | 行为 | 说明 | 你用 `dpkg-deb -x` 是否会做 | | --------------------- | --------------------------------------------------- | --------------------- | | 解包文件 | 把 deb 里的文件释放到根目录 | 会 | | 解析依赖 | 自动安装 `Depends` 包 | 不会 | | 执行 `preinst/postinst` | 包安装前后脚本 | 不会 | | 执行 trigger | 例如 `ldconfig`、icon cache、man-db | 不会 | | 维护 dpkg 数据库 | `/var/lib/dpkg/status` | 不会 | | 创建/更新 alternatives | 例如 `/usr/bin/cc` 指向 gcc | 不会 | | 保持 symlink 布局 | `/lib`、`/bin`、`libc.so.6` 等软链接 | 只解包原样;跨 Windows 打包可能丢 | | 维护动态库缓存 | `/etc/ld.so.cache` | 不会 | | 按 multiarch 放路径 | `/usr/lib/x86_64-linux-gnu`、`/lib/x86_64-linux-gnu` | 文件本身会解包,但你裁剪时可能漏 | 所以 `dpkg-deb -x` 只是: ```bash 把 deb 里的文件倒出来 ``` 不是: ```bash 完整安装一个 Ubuntu 包 ``` --- # 2. sysroot 里必须同时有“运行库”和“开发文件” 你现在做 GCC/CMake 编译 sysroot,至少要分清这几类包。 ## 2.1 `libc6` 提供 glibc 运行库,通常包含: ```text /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /lib/x86_64-linux-gnu/libm.so.6 /lib/x86_64-linux-gnu/libpthread.so.0 /lib/x86_64-linux-gnu/libdl.so.2 /lib/x86_64-linux-gnu/librt.so.1 ``` 这些是运行期 ELF 文件。 你的错误: ```text cannot find /lib/x86_64-linux-gnu/libc.so.6 inside sysroot cannot find /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 inside sysroot ``` 就是缺这类文件,或者这些文件在错误位置。 ## 2.2 `libc6-dev` 提供 glibc 编译开发文件,通常包含: ```text /usr/include/stdio.h /usr/include/features.h /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/x86_64-linux-gnu/crtn.o /usr/lib/x86_64-linux-gnu/Scrt1.o /usr/lib/x86_64-linux-gnu/rcrt1.o /usr/lib/x86_64-linux-gnu/libc.so /usr/lib/x86_64-linux-gnu/libc_nonshared.a ``` 注意: ```text /usr/lib/x86_64-linux-gnu/libc.so ``` 通常不是 ELF 动态库,而是 **ld linker script**。 里面会写类似: ```text GROUP ( /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ) ) ``` 所以即使你有: ```text /usr/lib/x86_64-linux-gnu/libc.so.6 ``` 也不够。因为 `libc.so` 脚本明确让链接器去找: ```text /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ``` ## 2.3 `linux-libc-dev` 提供 Linux UAPI headers: ```text /usr/include/linux/*.h /usr/include/asm-generic/*.h /usr/include/x86_64-linux-gnu/asm/*.h ``` 这个是编译很多 Linux 程序需要的头文件,不提供 glibc runtime。 --- # 3. `/usr/lib` 和 `/lib` 不是可以随便互换的 你截图里有: ```text sysroot/usr/lib/x86_64-linux-gnu/libc.so.6 ``` 但链接器要的是: ```text sysroot/lib/x86_64-linux-gnu/libc.so.6 ``` 这是两个路径。 在真实 Ubuntu 系统里,发行版可能通过以下方式保证它们都正常: ```text /lib 是真实目录 或者 /lib -> usr/lib 或者包里带了软链接 或者 loader/linker script 指向固定路径 ``` 但你自己裁剪 sysroot、再打包到 Windows 时,最容易丢的是: ```text /lib /lib64 软链接 绝对 symlink ``` 尤其 WinRAR 会提示“跳过可能不安全的链接”,这就会破坏 Linux sysroot。 --- # 4. `/lib64` 也可能必须存在 x86_64 glibc 的动态加载器有时通过这些路径出现: ```text /lib64/ld-linux-x86-64.so.2 /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ``` 具体看你的: ```bash cat "$sysroot/usr/lib/x86_64-linux-gnu/libc.so" ``` 只要 `libc.so` 里写了某个绝对路径,例如: ```text /lib64/ld-linux-x86-64.so.2 ``` 那么 sysroot 里就必须有: ```text $sysroot/lib64/ld-linux-x86-64.so.2 ``` 只要它写的是: ```text /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ``` 那么 sysroot 里就必须有: ```text $sysroot/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ``` **规则很简单:linker script 里的绝对路径 `/xxx`,ld 使用 `--sysroot` 后会找 `$sysroot/xxx`。** --- # 5. `/usr/lib/x86_64-linux-gnu/libc.so` 是关键 你不要只看有没有 `libc.so.6`。真正要看这个: ```bash cat "$sysroot/usr/lib/x86_64-linux-gnu/libc.so" ``` 然后把里面所有 `/lib/...`、`/usr/lib/...`、`/lib64/...` 的绝对路径都补齐。 可以用这个检查: ```bash target=x86_64-linux-gnu sysroot=/ae/sysroots/ubuntu2004 echo "[INFO] libc.so linker script:" cat "$sysroot/usr/lib/$target/libc.so" echo "[INFO] Absolute paths referenced by libc.so:" grep -oE '/(lib64|lib|usr/lib)[^ )]+' "$sysroot/usr/lib/$target/libc.so" | sort -u echo "[INFO] Check referenced files:" grep -oE '/(lib64|lib|usr/lib)[^ )]+' "$sysroot/usr/lib/$target/libc.so" | sort -u | while read -r p; do if [ -e "$sysroot$p" ]; then echo "[OK] $sysroot$p" else echo "[MISS] $sysroot$p" fi done ``` 这个比猜测更可靠。 --- # 6. 你这种精简 sysroot 必须手动还原的东西 最终 sysroot 至少应该有: ```text usr/include/stdio.h usr/include/features.h usr/include/linux usr/include/asm-generic usr/include/x86_64-linux-gnu/asm usr/lib/x86_64-linux-gnu/crt1.o usr/lib/x86_64-linux-gnu/crti.o usr/lib/x86_64-linux-gnu/crtn.o usr/lib/x86_64-linux-gnu/Scrt1.o usr/lib/x86_64-linux-gnu/rcrt1.o usr/lib/x86_64-linux-gnu/libc.so usr/lib/x86_64-linux-gnu/libc_nonshared.a lib/x86_64-linux-gnu/libc.so.6 lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 lib64/ld-linux-x86-64.so.2 # 如果 libc.so 或工具链需要 ``` 另外常见还需要: ```text lib/x86_64-linux-gnu/libm.so.6 lib/x86_64-linux-gnu/libpthread.so.0 lib/x86_64-linux-gnu/libdl.so.2 lib/x86_64-linux-gnu/librt.so.1 lib/x86_64-linux-gnu/libresolv.so.2 lib/x86_64-linux-gnu/libgcc_s.so.1 ``` 但 `libgcc_s.so.1` 最好来自你的 GCC 工具链,不要混旧系统版本,除非你明确知道搜索顺序。 --- # 7. 你之前的 rsync 白名单还要注意 symlink 你的白名单应该保留: ```bash --include='/lib/' --include="/lib/${target}/***" --include='/lib64/***' --include='/usr/' --include='/usr/include/***' --include='/usr/lib/' --include="/usr/lib/${target}/***" --include='/usr/lib/gcc/' --include="/usr/lib/gcc/${target}/***" --exclude='*' ``` 但问题是:如果 `/lib` 是 symlink,或者里面的 `libc.so.6` 是 symlink,Windows 打包时可能丢。 所以给 Windows 工具链发布用,建议最后做一次“实体化”: ```bash sudo cp -aL "$src" "$dst" ``` `-L` 的意义是:如果源文件是软链接,就复制软链接指向的真实文件。 --- # 8. `cc` 也是发行版隐式行为 你前面遇到的 `cc 9.4` 也是同一类问题。 Ubuntu 发行版通常提供: ```text /usr/bin/cc -> /etc/alternatives/cc -> /usr/bin/gcc ``` 但你自己 `make install` GCC 时,通常只生成: ```text gcc g++ c++ cpp ``` 不一定生成: ```text cc ``` 所以如果 configure 里传了: ```text CC=cc ``` 而你的工具链目录没有 `cc`,shell 就会继续往 PATH 后面找,最后找到系统 `/usr/bin/cc`。 这也是发行版帮你做了 `update-alternatives`,你自己的工具链没有。 --- # 9. `dpkg-deb -x` 方式的正确认知 你现在这种函数: ```bash install_iso_deb_to_sysroot_by_name "libc6-dev" ... ``` 本质是: ```text 从 ISO pool 找 deb -> 解包文件 -> 放入 sysroot ``` 它不会自动安装依赖。 所以如果你解 `libc6-dev`,它可能依赖: ```text libc6 linux-libc-dev ``` 但它不会帮你自动解这两个包。 而 Live ISO 的 `/pool` 里不一定有 `libc6`,因为 `libc6` 已经在: ```text casper/filesystem.squashfs ``` 里面了。 所以正确策略是: ```text libc6:优先从已解出的 rootfs 复制/修正 libc6-dev:从 ISO pool 解包 linux-libc-dev:从 ISO pool 解包 ``` --- # 10. 你应该采用的最终流程 ## 第一步:unsquashfs 提取完整 rootfs ```bash sudo unsquashfs -d /ae/sysroots/ubuntu2004 /media/wyc/Ubuntu\ 20.04.6\ LTS\ amd64/casper/filesystem.squashfs ``` 这个里面通常已经有: ```text /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ``` ## 第二步:从 ISO pool 解包开发包 ```bash libc6-dev linux-libc-dev ``` ## 第三步:生成精简 sysroot 只复制这些: ```text /usr/include /usr/lib/x86_64-linux-gnu /lib/x86_64-linux-gnu /lib64 /etc/ld.so.conf /etc/ld.so.conf.d ``` ## 第四步:修正 glibc runtime 绝对路径 检查: ```bash cat "$sysroot/usr/lib/x86_64-linux-gnu/libc.so" ``` 凡是里面写的绝对路径,必须在: ```text $sysroot + 绝对路径 ``` 存在。 ## 第五步:Windows 打包前实体化 symlink 尤其是: ```text libc.so.6 ld-linux-x86-64.so.2 libm.so.6 libpthread.so.0 libdl.so.2 librt.so.1 libresolv.so.2 ``` 不要让 WinRAR 跳过软链接。 --- # 11. 最终检查命令 在 Linux 打包前,对最终 sysroot 跑: ```bash target=x86_64-linux-gnu sysroot=/path/to/final/sysroot check() { if [ -e "$sysroot/$1" ]; then echo "[OK] $1" else echo "[MISS] $1" fi } check "usr/include/stdio.h" check "usr/include/features.h" check "usr/lib/$target/crt1.o" check "usr/lib/$target/crti.o" check "usr/lib/$target/crtn.o" check "usr/lib/$target/Scrt1.o" check "usr/lib/$target/libc.so" check "usr/lib/$target/libc_nonshared.a" check "lib/$target/libc.so.6" check "lib/$target/ld-linux-x86-64.so.2" if [ -e "$sysroot/usr/lib/$target/libc.so" ]; then echo "[INFO] Checking absolute references in libc.so:" grep -oE '/(lib64|lib|usr/lib)[^ )]+' "$sysroot/usr/lib/$target/libc.so" | sort -u | while read -r p; do if [ -e "$sysroot$p" ]; then echo "[OK] $p" else echo "[MISS] $p" fi done fi ``` 这个检查能直接解释你 CMake 那种错误。 --- # 12. 一句话总结 发行版隐式帮你维护了: ```text 依赖关系 multiarch 路径 /lib 与 /usr/lib 布局 /lib64 loader glibc linker script 引用路径 软链接 cc alternatives ldconfig/triggers ``` 你现在不是在“正常安装 Ubuntu”,而是在做一个 **可发布到 Windows 的精简 Linux sysroot**。因此必须自己保证: ```text linker script 里引用的绝对路径,在 sysroot 里真实存在 ``` 尤其是: ```text sysroot/lib/x86_64-linux-gnu/libc.so.6 sysroot/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ``` 不能只看: ```text sysroot/usr/lib/x86_64-linux-gnu/libc.so.6 ```