130 lines
6.2 KiB
Docker
130 lines
6.2 KiB
Docker
FROM --platform=linux/amd64 ubuntu:20.04
|
||
|
||
ENV DEBIAN_FRONTEND=noninteractive
|
||
|
||
# 换成阿里云源
|
||
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \
|
||
sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
|
||
|
||
# 安装必要的依赖
|
||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||
apt-get update && apt-get install -y \
|
||
curl \
|
||
git \
|
||
build-essential \
|
||
qemu-user-static \
|
||
pkg-config \
|
||
libssl-dev \
|
||
xz-utils \
|
||
squashfs-tools
|
||
|
||
# 配置交叉编译工具链(Linaro GCC 7.5.0)
|
||
ENV PATH="/opt/toolchain/bin:${PATH}"
|
||
RUN mkdir -p /opt/toolchain && \
|
||
curl -fSL -o toolchain.tar.xz https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz && \
|
||
tar -xJf toolchain.tar.xz -C /opt/toolchain --strip-components=1 && \
|
||
rm toolchain.tar.xz
|
||
|
||
# 安装 Rust
|
||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||
ENV PATH="/root/.cargo/bin:${PATH}"
|
||
RUN rustup target add armv7-unknown-linux-gnueabihf
|
||
|
||
WORKDIR /app
|
||
|
||
COPY run.sh /usr/local/bin/run
|
||
COPY runtime.sh /usr/local/bin/runtime
|
||
RUN chmod +x /usr/local/bin/run /usr/local/bin/runtime
|
||
|
||
# 解压 root.squashfs
|
||
COPY root.squashfs /app/root.squashfs
|
||
RUN mkdir -p /opt/sysroot \
|
||
&& unsquashfs -d /opt/sysroot -f /app/root.squashfs \
|
||
&& rm -rf /app/root.squashfs
|
||
|
||
# 创建专门针对 armhf 的源文件
|
||
# 注意:ubuntu:20.04 默认源里没有 armhf,必须添加 ubuntu-ports 源
|
||
RUN echo "deb [arch=armhf] http://mirrors.aliyun.com/ubuntu-ports/ focal main restricted universe multiverse" > /etc/apt/sources.list.d/armhf.list && \
|
||
echo "deb [arch=armhf] http://mirrors.aliyun.com/ubuntu-ports/ focal-updates main restricted universe multiverse" >> /etc/apt/sources.list.d/armhf.list && \
|
||
# 限制原有的源只针对 amd64,防止冲突
|
||
sed -i 's/deb http/deb [arch=amd64] http/g' /etc/apt/sources.list
|
||
|
||
# 安装 armhf 架构的开发库
|
||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||
dpkg --add-architecture armhf && \
|
||
apt-get update && apt-get install -y \
|
||
crossbuild-essential-armhf \
|
||
libasound2-dev:armhf \
|
||
libopus-dev:armhf \
|
||
libssl-dev:armhf
|
||
|
||
# --------------------------------------------------------------------------------
|
||
# 构建混合 Sysroot
|
||
# 目标:结合 OpenWrt 的运行时库 (root.squashfs) 和 Toolchain/Ubuntu 的开发文件
|
||
# --------------------------------------------------------------------------------
|
||
|
||
# 修复 OpenWrt sysroot:自动为所有共享库创建 .so 符号链接
|
||
# OpenWrt 只有 libfoo.so.1,编译链接需要 libfoo.so
|
||
RUN find /opt/sysroot/lib /opt/sysroot/usr/lib -name "lib*.so.*" | while read src; do \
|
||
# 获取库名 (例如 libopus.so.0.8.0 -> libopus.so)
|
||
link_name=$(echo "$src" | sed 's/\.so\..*$/.so/'); \
|
||
if [ ! -e "$link_name" ]; then \
|
||
ln -s "$(basename "$src")" "$link_name"; \
|
||
fi \
|
||
done
|
||
|
||
# 注入 Toolchain 的 C 运行时启动文件 (Scrt1.o, crti.o 等)
|
||
RUN cp -r /opt/toolchain/arm-linux-gnueabihf/libc/usr/lib/*crt*.o /opt/sysroot/usr/lib/ 2>/dev/null || \
|
||
cp -r /opt/toolchain/arm-linux-gnueabihf/libc/lib/*crt*.o /opt/sysroot/usr/lib/ 2>/dev/null || true
|
||
|
||
# 特殊处理 glibc 的 linker script
|
||
# OpenWrt rootfs 中没有开发用的 libc.so (linker script) 和 libc_nonshared.a
|
||
# 我们需要从 toolchain 中复制 libc_nonshared.a,并手动创建 libc.so 脚本
|
||
# 这样 linker 才能正确处理 libc.so.6 和 ld-linux-armhf.so.3 的依赖关系 (解决 __tls_get_addr 错误)
|
||
RUN cp /opt/toolchain/arm-linux-gnueabihf/libc/usr/lib/libc_nonshared.a /opt/sysroot/usr/lib/ && \
|
||
# 删除之前步骤可能自动生成的软链接
|
||
rm -f /opt/sysroot/usr/lib/libc.so && \
|
||
# 创建 linker script
|
||
echo 'OUTPUT_FORMAT(elf32-littlearm)' > /opt/sysroot/usr/lib/libc.so && \
|
||
echo 'GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a AS_NEEDED ( /lib/ld-linux-armhf.so.3 ) )' >> /opt/sysroot/usr/lib/libc.so && \
|
||
# 同理处理 libpthread.so (如果存在 libpthread.so.0)
|
||
if [ -f /opt/sysroot/lib/libpthread.so.0 ]; then \
|
||
cp /opt/toolchain/arm-linux-gnueabihf/libc/usr/lib/libpthread_nonshared.a /opt/sysroot/usr/lib/ 2>/dev/null || true; \
|
||
rm -f /opt/sysroot/usr/lib/libpthread.so; \
|
||
echo 'OUTPUT_FORMAT(elf32-littlearm)' > /opt/sysroot/usr/lib/libpthread.so; \
|
||
echo 'GROUP ( /lib/libpthread.so.0 /usr/lib/libpthread_nonshared.a )' >> /opt/sysroot/usr/lib/libpthread.so; \
|
||
fi
|
||
|
||
# 注入 Ubuntu 的开发头文件和 pkg-config 定义 (用于 alsa, opus 等)
|
||
# 我们只取头文件和 .pc 文件,不取库文件,确保链接的是 OpenWrt 的库
|
||
RUN mkdir -p /opt/sysroot/usr/include /opt/sysroot/usr/lib/pkgconfig && \
|
||
cp -r /usr/include/alsa /opt/sysroot/usr/include/ 2>/dev/null || true && \
|
||
cp -r /usr/include/opus /opt/sysroot/usr/include/ 2>/dev/null || true && \
|
||
cp -r /usr/include/arm-linux-gnueabihf/* /opt/sysroot/usr/include/ 2>/dev/null || true && \
|
||
cp -r /usr/lib/arm-linux-gnueabihf/pkgconfig/* /opt/sysroot/usr/lib/pkgconfig/ 2>/dev/null || true
|
||
|
||
# 优化 Rust 链接参数
|
||
# 1. 优先使用 -L 指定 sysroot 路径
|
||
# 2. 使用 -rpath-link 解决库的间接依赖问题
|
||
# 3. 确保 dynamic-linker 路径正确 (OpenWrt glibc 常用路径)
|
||
ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
|
||
ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUSTFLAGS="\
|
||
-C link-arg=--sysroot=/opt/sysroot \
|
||
-C link-arg=-Wl,-dynamic-linker,/lib/ld-linux-armhf.so.3 \
|
||
-C link-arg=-L/opt/sysroot/usr/lib \
|
||
-C link-arg=-L/opt/sysroot/lib \
|
||
-C link-arg=-Wl,-rpath-link,/opt/sysroot/usr/lib \
|
||
-C link-arg=-Wl,-rpath-link,/opt/sysroot/lib"
|
||
|
||
# 强制 pkg-config 只在 sysroot 中寻找,忽略宿主机容器路径
|
||
ENV PKG_CONFIG_ALLOW_CROSS=1
|
||
ENV PKG_CONFIG_SYSROOT_DIR=/opt/sysroot
|
||
ENV PKG_CONFIG_LIBDIR=/opt/sysroot/usr/lib/pkgconfig:/opt/sysroot/lib/pkgconfig
|
||
|
||
# 设置编译器,强制指定 sysroot
|
||
ENV CC_armv7_unknown_linux_gnueabihf="arm-linux-gnueabihf-gcc --sysroot=/opt/sysroot"
|
||
|
||
CMD ["/bin/bash"]
|