diff --git a/apps/runtime/Dockerfile b/apps/runtime/Dockerfile deleted file mode 100644 index bf2876a..0000000 --- a/apps/runtime/Dockerfile +++ /dev/null @@ -1,129 +0,0 @@ -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"] diff --git a/apps/runtime/README.md b/apps/runtime/README.md deleted file mode 100644 index 15c7fac..0000000 --- a/apps/runtime/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Open-XiaoAI Runtime(OH2P v1.58.1) - -```bash -root@OH2P:~# uname -a -Linux OH2P 4.9.61 #1 SMP PREEMPT Fri Jun 27 06:11:47 2025 aarch64 GNU/Linux - -root@OH2P:~# file /lib/libc-2.25.so -app/runtime/squashfs-root/lib/libc-2.25.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, stripped -``` diff --git a/apps/runtime/build.sh b/apps/runtime/build.sh deleted file mode 100755 index e70b6ea..0000000 --- a/apps/runtime/build.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -set -e - -# 在 macOS 上,使用 host.docker.internal 访问宿主机的代理端口 -# 如果你的代理软件没有开启 "Allow LAN"(允许局域网连接),请确保它监听的是 0.0.0.0 而不仅仅是 127.0.0.1 -PROXY="http://host.docker.internal:7890" - -# 1. 构建编译环境镜像 -echo "Building Docker image with proxy..." -docker build \ - --build-arg http_proxy=$PROXY \ - --build-arg https_proxy=$PROXY \ - -t open-xiaoai-runtime . - -# 2. 运行编译出的二进制文件 (通过 QEMU 模拟) -# docker run --rm -v $(pwd)/hello:/app/hello open-xiaoai-runtime \ -# run /app/hello - -# 3. 交互模式运行 -# docker run --rm -it --privileged open-xiaoai-runtime run \ No newline at end of file diff --git a/apps/runtime/.gitignore b/packages/runtime/.gitignore similarity index 100% rename from apps/runtime/.gitignore rename to packages/runtime/.gitignore diff --git a/packages/runtime/Dockerfile b/packages/runtime/Dockerfile new file mode 100644 index 0000000..dcf28f3 --- /dev/null +++ b/packages/runtime/Dockerfile @@ -0,0 +1,88 @@ +# syntax=docker/dockerfile:1.4 +FROM ubuntu:20.04 + +# 1. 环境变量合并,减少层数 +ENV DEBIAN_FRONTEND=noninteractive \ + PATH="/opt/toolchain/bin:/root/.cargo/bin:${PATH}" \ + PKG_CONFIG_ALLOW_CROSS=1 \ + PKG_CONFIG_SYSROOT_DIR=/opt/sysroot \ + PKG_CONFIG_LIBDIR=/opt/sysroot/usr/lib/pkgconfig:/opt/sysroot/lib/pkgconfig \ + CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + CC_armv7_unknown_linux_gnueabihf="arm-linux-gnueabihf-gcc --sysroot=/opt/sysroot" + +# 2. 基础依赖与多架构源配置合并 +# 使用 --mount=type=cache 优化 apt 操作 +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + 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 && \ + sed -i 's/deb http/deb [arch=amd64] http/g' /etc/apt/sources.list && \ + 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 && \ + dpkg --add-architecture armhf && \ + apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates curl git build-essential qemu-user-static pkg-config libssl-dev xz-utils squashfs-tools \ + crossbuild-essential-armhf libasound2-dev:armhf libopus-dev:armhf libssl-dev:armhf && \ + # 删除 lists 文件以减小体积 + rm -rf /var/lib/apt/lists/* + +# 3. 安装 Linaro Toolchain & Rust +# 将下载和清理放在一层,减少体积 +RUN mkdir -p /opt/toolchain && \ + curl -fSL 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 -xJ -C /opt/toolchain --strip-components=1 && \ + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable && \ + rustup target add armv7-unknown-linux-gnueabihf + +WORKDIR /app + +# 4. 脚本与 Rootfs 处理 +# 使用 --mount=bind 减少一次 COPY 导致的镜像体积增加 +COPY run.sh runtime.sh /usr/local/bin/ +RUN chmod +x /usr/local/bin/run.sh /usr/local/bin/runtime.sh + +# 处理 root.squashfs:利用临时挂载或直接解压并删除 +RUN --mount=type=bind,source=root.squashfs,target=/app/root.squashfs \ + mkdir -p /opt/sysroot && unsquashfs -d /opt/sysroot -f /app/root.squashfs + +# 5. 构建混合 Sysroot 逻辑优化 +# 将所有文件操作合并到一个 RUN 块,减少 Metadata 冗余 +RUN set -e; \ + # 1. 自动为共享库创建 .so 软链接 + find /opt/sysroot/lib /opt/sysroot/usr/lib -name "lib*.so.*" | while read -r src; do \ + link_name=$(echo "$src" | sed 's/\.so\..*$/.so/'); \ + if [ ! -e "$link_name" ]; then \ + ln -s "$(basename "$src")" "$link_name"; \ + fi; \ + done; \ + # 2. 拷贝 crt*.o 文件 + find /opt/toolchain/arm-linux-gnueabihf/libc -name "*crt*.o" -exec cp {} /opt/sysroot/usr/lib/ \; ; \ + # 3. 拷贝 libc_nonshared.a + cp /opt/toolchain/arm-linux-gnueabihf/libc/usr/lib/libc_nonshared.a /opt/sysroot/usr/lib/; \ + if [ -f /opt/toolchain/arm-linux-gnueabihf/libc/usr/lib/libpthread_nonshared.a ]; then \ + cp /opt/toolchain/arm-linux-gnueabihf/libc/usr/lib/libpthread_nonshared.a /opt/sysroot/usr/lib/; \ + fi; \ + # 4. 生成 Linker Scripts + printf "OUTPUT_FORMAT(elf32-littlearm)\nGROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a AS_NEEDED ( /lib/ld-linux-armhf.so.3 ) )\n" > /opt/sysroot/usr/lib/libc.so; \ + if [ -f /opt/sysroot/lib/libpthread.so.0 ]; then \ + printf "OUTPUT_FORMAT(elf32-littlearm)\nGROUP ( /lib/libpthread.so.0 /usr/lib/libpthread_nonshared.a )\n" > /opt/sysroot/usr/lib/libpthread.so; \ + fi; \ + # 5. 注入头文件和 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; \ + if [ -d /usr/include/arm-linux-gnueabihf ]; then \ + cp -r /usr/include/arm-linux-gnueabihf/* /opt/sysroot/usr/include/ 2>/dev/null || true; \ + fi; \ + if [ -d /usr/lib/arm-linux-gnueabihf/pkgconfig ]; then \ + cp -r /usr/lib/arm-linux-gnueabihf/pkgconfig/* /opt/sysroot/usr/lib/pkgconfig/ 2>/dev/null || true; \ + fi + +# 6. 设置 Rust 链接参数 +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" + +CMD ["/bin/bash"] \ No newline at end of file diff --git a/packages/runtime/Makefile b/packages/runtime/Makefile new file mode 100644 index 0000000..2691614 --- /dev/null +++ b/packages/runtime/Makefile @@ -0,0 +1,37 @@ +# Makefile for open-xiaoai-runtime + +# 使用 host.docker.internal 访问宿主机的代理端口(加速构建) +# 注意:代理软件需要开启 "Allow LAN"(允许局域网连接) +PROXY := http://host.docker.internal:7890 +IMAGE_NAME := idootop/open-xiaoai-runtime:oh2p + +# 显示帮助信息 +help: + @echo "Available targets:" + @echo " make build - 构建交叉编译环境镜像" + @echo " make run-x86 - 进入交叉编译环境(Ubuntu x86_64)" + @echo " make run-armv7 - 进入小爱音箱模拟环境(OpenWrt ARMv7)" + @echo " make help - 显示此帮助信息" + @echo "" + @echo "Variables:" + @echo " PROXY=$(PROXY)" + @echo " IMAGE_NAME=$(IMAGE_NAME)" + +# 构建交叉编译环境镜像 +build: + @echo "Building Docker image: $(IMAGE_NAME)..." + docker build \ + --build-arg http_proxy=$(PROXY) \ + --build-arg https_proxy=$(PROXY) \ + -t $(IMAGE_NAME) . + +# 进入交叉编译环境(Ubuntu x86_64) +run-x86: + @echo "Entering cross-compilation environment (Ubuntu x86_64)..." + docker run --rm -it --privileged $(IMAGE_NAME) + +# 进入小爱音箱模拟环境(OpenWrt ARMv7) +run-armv7: + @echo "Entering XiaoAi speaker simulation environment (OpenWrt ARMv7)..." + docker run --rm -it --privileged $(IMAGE_NAME) run + diff --git a/packages/runtime/README.md b/packages/runtime/README.md new file mode 100644 index 0000000..ddbfc30 --- /dev/null +++ b/packages/runtime/README.md @@ -0,0 +1,83 @@ +# Open-XiaoAI Runtime + +小爱音箱 ARMv7 交叉编译 + 模拟运行环境(基于 OH2P v1.58.1 固件) + +## 概述 + +小爱音箱使用的 Linux 系统较旧,glibc 版本为 2.25,需要使用 `gcc-linaro-7.5.0-2019.12` 工具链才能编译出兼容的程序。 + +```bash +root@OH2P:~# uname -a +Linux OH2P 4.9.61 #1 SMP PREEMPT Fri Jun 27 06:11:47 2025 aarch64 GNU/Linux + +root@OH2P:~# file /lib/libc-2.25.so +ELF 32-bit LSB shared object, ARM, EABI5 version 1 (GNU/Linux), +dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, stripped +``` + +## Rust 交叉编译示例 + +编译产物可直接在小爱音箱上运行。 + +```bash +cd /path/to/your-rust-project + +# 使用预先构建好的 Docker 环境进行交叉编译 +docker run --rm idootop/open-xiaoai-runtime:oh2p \ + -v $(shell pwd):/app \ + cargo build --target armv7-unknown-linux-gnueabihf --release +``` + +## 环境说明 + +**交叉编译环境**(Ubuntu 20.04 x86_64) + +- Linaro GCC 7.5.0 (arm-linux-gnueabihf) +- Rust 稳定版 + armv7-unknown-linux-gnueabihf target +- 包含 ALSA、Opus、OpenSSL 等系统库(ARMv7 版本) +- 从小爱音箱固件提取的完整 Sysroot + +**模拟运行环境**(QEMU 用户态) + +- ARMv7 架构(32-bit ARM) +- OpenWrt 定制系统 + glibc 2.25 +- 使用小爱音箱真实 rootfs +- 不支持音频录制/播放等操作,需在小爱音箱真机运行 + +## 自定义配置 + +### 更换固件 + +默认使用 OH2P v1.58.1 固件。如需使用其他型号和版本: + +```bash +# 克隆代码 +git clone https://github.com/idootop/open-xiaoai.git + +# 进入当前项目根目录 +cd packages/runtime + +# 【重要】将新的 `root.squashfs` 放到当前目录 + +# 构建镜像 +make build +``` + +PS:你可以修改 `Makefile` 中的代理地址加速镜像构建(代理软件需开启局域网访问)。 + +```makefile +PROXY := http://host.docker.internal:7890 # 对应 0.0.0.0:7890 +``` + +### 其他 Makefile 命令 + +```bash +# 构建镜像 +make build + +# 进入交叉编译环境(Ubuntu x86_64) +make run-x86 + +# 进入小爱音箱模拟环境(OpenWrt ARMv7) +make run-armv7 +``` diff --git a/apps/runtime/run.sh b/packages/runtime/run.sh similarity index 100% rename from apps/runtime/run.sh rename to packages/runtime/run.sh diff --git a/apps/runtime/runtime.sh b/packages/runtime/runtime.sh similarity index 100% rename from apps/runtime/runtime.sh rename to packages/runtime/runtime.sh