376 lines
8.4 KiB
Markdown
376 lines
8.4 KiB
Markdown
# Musl 工具链编译说明
|
||
|
||
**更新时间**: 2025-12-04
|
||
**问题**: 开发板使用 musl libc,但最初用 glibc 工具链编译导致无法运行
|
||
**解决**: 切换到 musl 工具链重新编译
|
||
|
||
---
|
||
|
||
## 📋 问题诊断过程
|
||
|
||
### 在开发板上的错误
|
||
|
||
```bash
|
||
root@(none):/# ldd /tmp/avaota_client
|
||
/bin/sh: /tmp/avaota_client: not found
|
||
|
||
root@(none):/# /lib/ld-musl-riscv32.so.1 /tmp/avaota_client
|
||
Error loading shared library ld-linux-riscv32-ilp32d.so.1: No such file or directory
|
||
Error relocating /tmp/avaota_client: __register_atfork: symbol not found
|
||
```
|
||
|
||
### 开发板环境确认
|
||
|
||
```bash
|
||
root@(none):/# /lib32/ilp32d/libc.so
|
||
musl libc (riscv32)
|
||
Version 1.2.4
|
||
Dynamic Program Loader
|
||
```
|
||
|
||
**结论**: 开发板运行 **musl libc 1.2.4**,但程序用 **glibc** 编译,导致:
|
||
1. 动态链接器路径不匹配(`ld-linux-riscv32-ilp32d.so.1` vs `ld-musl-riscv32.so.1`)
|
||
2. glibc 特有符号 `__register_atfork` 在 musl 中不存在
|
||
|
||
---
|
||
|
||
## ✅ 解决方案
|
||
|
||
### 已修改的文件
|
||
|
||
修改了 `src/Makefile`,添加 musl 工具链支持:
|
||
|
||
```makefile
|
||
# 切换工具链:设置 USE_MUSL=1 使用 musl 工具链(推荐)
|
||
USE_MUSL := 1
|
||
|
||
ifeq ($(USE_MUSL),1)
|
||
# musl 工具链(与开发板兼容)
|
||
TOOLCHAIN_DIR := $(SDK_ROOT)/out/toolchain/nds32le-linux-musl-v5d/bin
|
||
CROSS_COMPILE := riscv32-linux-musl-
|
||
$(info [INFO] Using musl toolchain for board compatibility)
|
||
else
|
||
# glibc 工具链(仅用于对比测试,开发板不支持)
|
||
TOOLCHAIN_DIR := $(SDK_ROOT)/out/toolchain/nds32le-linux-glibc-v5d/bin
|
||
CROSS_COMPILE := riscv32-unknown-linux-
|
||
$(warning [WARNING] Using glibc toolchain - will NOT run on board!)
|
||
endif
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 编译步骤(在 Ubuntu 服务器上)
|
||
|
||
### 前提条件
|
||
|
||
确保 musl 工具链存在:
|
||
|
||
```bash
|
||
cd ~/ProgramFiles/AvaotaF1/avaota_sdk/tina-v821-release
|
||
|
||
# 检查 musl 工具链
|
||
ls -la out/toolchain/nds32le-linux-musl-v5d/bin/
|
||
|
||
# 应该看到类似这些文件:
|
||
# riscv32-linux-musl-gcc
|
||
# riscv32-linux-musl-g++
|
||
# riscv32-linux-musl-ar
|
||
# ...
|
||
```
|
||
|
||
**如果不存在**,可能需要:
|
||
1. 解压工具链压缩包(如果在 `out/toolchain/` 下有 `.tar.xz` 或 `.tar.gz` 文件)
|
||
2. 或在 `prebuilt/rootfsbuilt/riscv/` 下查找
|
||
3. 或重新编译 SDK(会自动生成)
|
||
|
||
---
|
||
|
||
### 步骤 1: 上传修改后的代码
|
||
|
||
将修改后的 `avaota_app_demo` 文件夹上传到 Ubuntu 服务器:
|
||
|
||
```bash
|
||
# 在 Windows 上(使用 SCP 或 WinSCP)
|
||
# 目标路径:/home/rongye/ProgramFiles/AvaotaF1/avaota_app_demo
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 2: SSH 连接到服务器
|
||
|
||
```bash
|
||
ssh rongye@<服务器IP>
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 3: 验证工具链路径
|
||
|
||
```bash
|
||
cd ~/ProgramFiles/AvaotaF1/avaota_app_demo/src
|
||
|
||
# 检查 Makefile 变量
|
||
grep "TOOLCHAIN_DIR" Makefile
|
||
grep "CROSS_COMPILE" Makefile
|
||
grep "USE_MUSL" Makefile
|
||
|
||
# 测试编译器
|
||
SDK_ROOT=~/ProgramFiles/AvaotaF1/avaota_sdk/tina-v821-release
|
||
$SDK_ROOT/out/toolchain/nds32le-linux-musl-v5d/bin/riscv32-linux-musl-gcc --version
|
||
```
|
||
|
||
**预期输出**:
|
||
```
|
||
riscv32-linux-musl-gcc (GCC) 10.x.x
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 4: 清理旧编译文件
|
||
|
||
```bash
|
||
cd ~/ProgramFiles/AvaotaF1/avaota_app_demo/src
|
||
make clean
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 5: 重新编译
|
||
|
||
```bash
|
||
cd ~/ProgramFiles/AvaotaF1/avaota_app_demo
|
||
|
||
# 方法 1: 使用构建脚本
|
||
./build_main.sh
|
||
|
||
# 方法 2: 直接 make
|
||
cd src
|
||
make all -j4
|
||
```
|
||
|
||
编译时应该看到:
|
||
```
|
||
[INFO] Using musl toolchain for board compatibility
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 6: 验证编译结果
|
||
|
||
```bash
|
||
cd ~/ProgramFiles/AvaotaF1/avaota_app_demo
|
||
|
||
# 查看文件信息
|
||
ls -lh build/bin/avaota_client
|
||
file build/bin/avaota_client
|
||
|
||
# 【关键】检查动态链接器
|
||
strings build/bin/avaota_client | grep "/lib/ld-"
|
||
```
|
||
|
||
**正确结果应该是**:
|
||
```
|
||
/lib/ld-musl-riscv32.so.1
|
||
```
|
||
|
||
**如果看到这个就是错的**(说明还在用 glibc):
|
||
```
|
||
/lib/ld-linux-riscv32-ilp32d.so.1
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 7: 上传到开发板
|
||
|
||
```bash
|
||
# 从服务器上传到开发板
|
||
cd ~/ProgramFiles/AvaotaF1/avaota_app_demo
|
||
scp build/bin/avaota_client root@<开发板IP>:/tmp/avaota_client_musl
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 8: 在开发板上测试
|
||
|
||
SSH 到开发板:
|
||
|
||
```bash
|
||
ssh root@<开发板IP>
|
||
|
||
# 添加执行权限
|
||
chmod +x /tmp/avaota_client_musl
|
||
|
||
# 验证依赖(现在应该正常显示)
|
||
ldd /tmp/avaota_client_musl
|
||
|
||
# 运行程序
|
||
/tmp/avaota_client_musl
|
||
```
|
||
|
||
**成功标志**:
|
||
- ✅ `ldd` 不再报 "not found" 错误
|
||
- ✅ 能看到需要的动态库列表
|
||
- ✅ 程序启动,打印初始化日志
|
||
- ✅ 各模块开始工作
|
||
|
||
---
|
||
|
||
## 🔧 故障排查
|
||
|
||
### 问题 1: 找不到 musl 工具链
|
||
|
||
**错误**:
|
||
```bash
|
||
make: /home/rongye/.../nds32le-linux-musl-v5d/bin/riscv32-linux-musl-gcc: No such file or directory
|
||
```
|
||
|
||
**解决方案 A**: 查找并解压
|
||
|
||
```bash
|
||
cd ~/ProgramFiles/AvaotaF1/avaota_sdk/tina-v821-release
|
||
|
||
# 查找压缩包
|
||
find . -name "*musl*.tar*" 2>/dev/null
|
||
|
||
# 如果找到,解压到 out/toolchain/
|
||
cd out/tool chain
|
||
tar -xJf nds32le-linux-musl-v5d.tar.xz # 或 .tar.gz
|
||
```
|
||
|
||
**解决方案 B**: 使用其他位置的工具链
|
||
|
||
如果工具链在 `prebuilt/` 目录,修改 Makefile:
|
||
|
||
```makefile
|
||
TOOLCHAIN_DIR := $(SDK_ROOT)/prebuilt/rootfsbuilt/riscv/nds32le-linux-musl-v5d/bin
|
||
```
|
||
|
||
**解决方案 C**: 临时切换回 glibc
|
||
|
||
如果实在找不到 musl 工具链,可以暂时用 glibc 重新编译(虽然不推荐):
|
||
|
||
```makefile
|
||
USE_MUSL := 0
|
||
```
|
||
|
||
但这样编译的程序**无法在开发板上运行**。
|
||
|
||
---
|
||
|
||
### 问题 2: 编译器前缀不对
|
||
|
||
**错误**:
|
||
```
|
||
make: riscv32-linux-musl-gcc: command not found
|
||
```
|
||
|
||
**解决方案**:
|
||
|
||
检查实际的编译器名称:
|
||
|
||
```bash
|
||
ls ~/ProgramFiles/AvaotaF1/avaota_sdk/tina-v821-release/out/toolchain/nds32le-linux-musl-v5d/bin/riscv32-*gcc
|
||
```
|
||
|
||
可能的前缀:
|
||
- `riscv32-linux-musl-`
|
||
- `riscv32-unknown-linux-musl-`
|
||
|
||
修改 Makefile 中的 `CROSS_COMPILE` 变量。
|
||
|
||
---
|
||
|
||
### 问题 3: 编译时缺少头文件
|
||
|
||
**错误**:
|
||
```
|
||
fatal error: xxx.h: No such file or directory
|
||
```
|
||
|
||
**原因**: musl 的系统头文件路径可能与 glibc 不同
|
||
|
||
**解决方案**:
|
||
|
||
在 Makefile 中添加 musl 头文件路径:
|
||
|
||
```makefile
|
||
ifeq ($(USE_MUSL),1)
|
||
CXXFLAGS += -I$(TOOLCHAIN_DIR)/../include
|
||
CXXFLAGS += -I$(TOOLCHAIN_DIR)/../riscv32-linux-musl/include
|
||
endif
|
||
```
|
||
|
||
---
|
||
|
||
### 问题 4: 链接时找不到库
|
||
|
||
**错误**:
|
||
```
|
||
cannot find -lxxx
|
||
```
|
||
|
||
**解决方案**:
|
||
|
||
检查库是否存在于 musl 环境:
|
||
|
||
```bash
|
||
find ~/ProgramFiles/AvaotaF1/avaota_sdk/tina-v821-release/out/v821/avaota_f1/openwrt/staging_dir/target/usr/lib -name "libxxx.a"
|
||
```
|
||
|
||
如果不存在,可能需要:
|
||
1. 重新编译 SDK 以包含 musl 版本的库
|
||
2. 或移除对该库的依赖
|
||
|
||
---
|
||
|
||
## 📊 工具链对比
|
||
|
||
| 项目 | glibc 工具链 | musl 工具链 |
|
||
|------|-------------|-------------|
|
||
| 路径 | `nds32le-linux-glibc-v5d` | `nds32le-linux-musl-v5d` |
|
||
| 编译器前缀 | `riscv32-unknown-linux-` | `riscv32-linux-musl-` |
|
||
| C 库 | glibc (GNU C Library) | musl libc 1.2.4 |
|
||
| 动态链接器 | `/lib/ld-linux-riscv32-ilp32d.so.1` | `/lib/ld-musl-riscv32.so.1` |
|
||
| 二进制大小 | 较大 | 较小 |
|
||
| 兼容性 | ❌ 不兼容 Avaota F1 | ✅ 完美兼容 |
|
||
| 用途 | 仅用于实验 | **生产环境必须使用** |
|
||
|
||
---
|
||
|
||
## ✅ 编译验证清单
|
||
|
||
重新编译完成后,验证以下内容:
|
||
|
||
- [ ] musl 工具链路径存在
|
||
- [ ] Makefile 中 `USE_MUSL := 1`
|
||
- [ ] `make clean` 清理旧文件
|
||
- [ ] 编译时看到 "Using musl toolchain" 提示
|
||
- [ ] 编译成功,生成 `build/bin/avaota_client`
|
||
- [ ] `strings` 检查链接器为 `ld-musl-riscv32.so.1`
|
||
- [ ] 上传到开发板
|
||
- [ ] `ldd` 正常显示依赖
|
||
- [ ] 程序成功运行
|
||
|
||
---
|
||
|
||
## 📝 后续优化
|
||
|
||
如果后续需要调整(比如完全静态链接),可以修改:
|
||
|
||
```makefile
|
||
# 完全静态链接(不依赖任何动态库)
|
||
LDFLAGS := -static -static-libgcc -static-libstdc++
|
||
|
||
# 移除 -Wl,-Bdynamic 部分
|
||
# LDFLAGS += -Wl,-Bdynamic -lasound -lglog ...
|
||
|
||
# 全部静态链接
|
||
LDFLAGS += -lasound -lglog -llog -lpthread -lm -lstdc++ -lrt -ldl -lz
|
||
```
|
||
|
||
这样可以避免任何运行时库依赖问题,但会显著增加程序大小(可能从 3.9MB 增加到 6-8MB)。
|
||
|
||
---
|
||
|
||
**下一步**: 按照上述步骤在服务器上重新编译,然后在开发板上测试!🚀
|