Files
2026-07-07 15:23:39 +08:00

540 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
可以。你现在踩到的不是单个 `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` 是 symlinkWindows 打包时可能丢。
所以给 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
```