一、准备工作
首先,在 WSL 2 的 Ubuntu 系统中安装必要的依赖包:
sudo apt install build-essential binfmt-support daemonize libarchive-tools qemu-system qemu-user qemu-user-static gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
下载适用于 ARM 64 的 Ubuntu 根文件系统:
wget https://cloud-images.ubuntu.com/releases/server/20.04/release-20221213/ubuntu-20.04-server-cloudimg-arm64-wsl.rootfs.tar.gz
将下载的文件放置在 Ubuntu 用户目录下,并创建一个新文件夹用于解压根文件系统。例如:
mkdir arm64_rootfs
二、解压并配置 ARM 64 根文件系统
解压根文件系统到新创建的文件夹中:
sudo bsdtar -xpf ubuntu-20.04-server-cloudimg-arm64-wsl.rootfs.tar.gz -C arm64_rootfs
将 QEMU ARM 64 模拟器复制到解压目录:
sudo cp /usr/bin/qemu-aarch64-static arm64_rootfs/usr/bin
运行 systemd 守护进程:
sudo daemonize /usr/bin/unshare -fp --mount-proc /lib/systemd/systemd --system-unit=basic.target
三、挂载系统目录并进入 ARM 64 环境
挂载必要的目录:
sudo mount -o bind /proc arm64_rootfs/proc
sudo mount -o bind /dev arm64_rootfs/dev
使用 chroot 进入 ARM 64 环境:
sudo chroot arm64_rootfs qemu-aarch64-static /bin/bash
四、创建自动化脚本
为了方便以后的操作,可以创建一个名为 chroot.sh
的脚本,内容如下:
#!/bin/bash
sudo daemonize /usr/bin/unshare -fp --mount-proc /lib/systemd/systemd --system-unit=basic.target
sudo mount -o bind /proc arm64_rootfs/proc
sudo mount -o bind /dev arm64_rootfs/dev
sudo mount -o bind /tmp/.X11-unix arm64_rootfs/tmp/.X11-unix
xhost + local:
sudo chroot arm64_rootfs qemu-aarch64-static /bin/bash
赋予脚本执行权限:
chmod +x chroot.sh
运行脚本进入 ARM 64 环境:
./chroot.sh
五、配置网络与更新系统
进入 ARM 64 环境后,执行以下命令设置 DNS 解析:
rm /etc/resolv.conf
echo "nameserver 8.8.8.8" > /etc/resolv.conf
更新系统并安装必要的软件包:
apt-get update && apt-get upgrade
apt-get install --no-install-recommends build-essential git wget libdrm-dev python3 python3-pip python3-setuptools python3-wheel ninja-build libopenal-dev premake4 autoconf libevdev-dev ffmpeg libboost-tools-dev magics++ libboost-thread-dev libboost-all-dev pkg-config zlib1g-dev libsdl-mixer1.2-dev libsdl1.2-dev libsdl-gfx1.2-dev libsdl2-mixer-dev clang cmake cmake-data libarchive13 libcurl4 libfreetype6-dev librhash0 libuv1 mercurial mercurial-common libgbm-dev libsdl-image1.2-dev
六、安装 ARM 64 构建工具链
1. 更新系统包
在开始安装任何软件之前,建议首先更新系统的包列表,并升级已安装的软件包:
apt-get update && apt-get upgrade -y
2. 安装基本构建工具
安装构建所需的基本工具包,如 build-essential
、git
、wget
等:
apt-get install --no-install-recommends build-essential git wget
3. 安装常见开发库
安装一些开发过程中可能需要的常见库和工具:
apt-get install --no-install-recommends libdrm-dev python3 python3-pip python3-setuptools python3-wheel ninja-build \
libopenal-dev premake4 autoconf libevdev-dev ffmpeg libboost-tools-dev magics++ libboost-thread-dev libboost-all-dev \
pkg-config zlib1g-dev libsdl-mixer1.2-dev libsdl1.2-dev libsdl-gfx1.2-dev libsdl2-mixer-dev clang cmake cmake-data \
libarchive13 libcurl4 libfreetype6-dev librhash0 libuv1 mercurial mercurial-common libgbm-dev libsdl-image1.2-dev
七、安装 SDL 2
在配置好工具链后,可以继续编译和安装 SDL2。
1. 清理系统自带的 SDL2(如有)
在 ARM64 环境中,清理可能存在的 SDL2 旧版本,以避免冲突:
rm /usr/lib/aarch64-linux-gnu/libSDL2.*
rm -rf /usr/lib/aarch64-linux-gnu/libSDL2-2.0.so*
2. 下载 SDL2 源码
下载 Trimui 官方提供的 SDL 2 源码包:
Trimui 官方 SDL2 源码下载链接
选择 SDL2-2.26.1.GE8300.tgz
并下载。
将源码包解压到 ARM 64 环境中,例如:
tar -xzf SDL2-2.26.1.GE8300.tgz
cd SDL2-2.26.1
3. 编译和安装 SDL2
使用工具链编译 SDL2,确保指定 aarch64-linux-gnu 编译器:
./configure --host=aarch64-linux-gnu --prefix=/usr
make -j8 CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++
make install
/sbin/ldconfig
4. 验证安装
安装完成后,检查 SDL2 库是否已正确安装到系统中:
ls /usr/lib/aarch64-linux-gnu/ | grep SDL2
输出应包括 libSDL2.so 等相关文件。
八、安装 FFmpeg 4.2.4
在完成 SDL 2 的安装后,我们继续在 ARM 64 环境中编译和安装 FFmpeg 4.2.4,这是许多多媒体应用的核心依赖。以下是具体步骤:
1. 下载 FFmpeg 4.2.4 源码
首先,在 ARM 64 环境中下载 FFmpeg 4.2.4 的源码:
wget https://ffmpeg.org/releases/ffmpeg-4.2.4.tar.bz2
解压源码包:
tar -xjf ffmpeg-4.2.4.tar.bz2
cd ffmpeg-4.2.4
2. 配置编译环境
运行以下命令配置 FFmpeg 的编译选项。你可以根据需求调整选项,但以下配置通常适用于大多数应用场景:
./configure --prefix=/usr \
--enable-shared \
--enable-gpl \
--enable-nonfree \
--enable-libfreetype \
--enable-libopenjpeg \
--enable-libmp3lame \
--enable-libvorbis \
--enable-libvpx \
--enable-libx264 \
--enable-libx265 \
--enable-postproc \
--enable-small \
--enable-openssl \
--enable-pthreads \
--enable-zlib
3. 编译 FFmpeg
使用多线程编译以加快速度(根据系统性能调整线程数):
make -j8
4. 安装 FFmpeg
编译完成后,安装 FFmpeg 到系统目录:
make install
更新库缓存:
ldconfig
5. 验证安装
运行以下命令以确认 FFmpeg 已成功安装并显示版本信息:
ffmpeg -version
输出结果中应包含 4.2.4
字样,例如:
ffmpeg version 4.2.4 Copyright (c) 2000-2020 the FFmpeg developers
built with gcc (Ubuntu ...)
九、测试编译环境
至此,ARM 64 的编译环境已经准备完毕,可以正常编译需要的包。
尝试运行一个测试项目以确保一切工作正常。
十、补全 so 运行库
Trimui 设备使用的是全志(Allwinner)的 Tina Linux 操作系统,这是基于 OpenWrt 修改而来的轻量级嵌入式 Linux 发行版。它针对嵌入式设备的资源限制进行了优化,因此通常只包含最小化的运行库和工具链。这种设计虽然节省了存储和内存资源,但也带来了缺少常见的运行时库的问题。
因此,在为 Trimui 这样的嵌入式设备部署程序时,需要从开发环境中提取所有依赖的动态库,并选择性一同打包到设备的运行环境中,确保程序能够正常运行。
自动化脚本
为了解决上述问题,我写了一个自动化脚本,可以针对指定的二进制文件(如编译后的程序),自动分析其运行时依赖的 .so 文件,并将这些库文件提取到一个独立的 lib 目录中。
脚本内容
#!/bin/bash
# 检查是否传入二进制文件
if [ $# -lt 2 ]; then
echo "Usage: $0 <binary-file> <output-lib-dir>"
exit 1
fi
BINARY_FILE=$1
OUTPUT_LIB_DIR=$2
# 检查二进制文件是否存在
if [ ! -f "$BINARY_FILE" ]; then
echo "Error: Binary file '$BINARY_FILE' does not exist."
exit 1
fi
# 检查输出目录是否存在,如果不存在则创建
if [ ! -d "$OUTPUT_LIB_DIR" ]; then
mkdir -p "$OUTPUT_LIB_DIR"
fi
echo "Scanning dependencies for $BINARY_FILE..."
# 使用 ldd 获取依赖库
ldd "$BINARY_FILE" | grep "=>" | awk '{print $3}' | while read -r LIB_PATH; do
# 确保依赖库路径存在
if [ -f "$LIB_PATH" ]; then
echo "Copying $LIB_PATH to $OUTPUT_LIB_DIR"
cp -u "$LIB_PATH" "$OUTPUT_LIB_DIR"
else
echo "Warning: Dependency $LIB_PATH not found."
fi
done
echo "Dependency export completed. Libraries saved to $OUTPUT_LIB_DIR."
脚本使用示例
假设我们已经完成了一个程序 my_program 的编译,并希望将其部署到 Trimui 设备上,具体步骤如下:
- 在 WSL 编译环境中运行脚本提取依赖库:
./export_libs.sh ./my_program ./lib
脚本会扫描 my_program 的依赖并将所有 .so 文件复制到 ./lib 目录。
-
将二进制文件和依赖库打包上传到设备:
-
在设备上运行程序时设置动态链接库路径:
export LD_LIBRARY_PATH=/path/to/deploy:$LD_LIBRARY_PATH
./my_program
十一、编写运行脚本
Trimui 设备识别应用程序是依靠 config.json
,在其中定义了应用的名称,启动脚本等,例如:
config.json:
{
"label":"WiliWili",
"icon":"icon.png",
"launch":"launch.sh",
"description":"WiliWili"
}
launch.sh:
#!/bin/sh
BIN_PATH=$(dirname "$0")
cd "$BIN_PATH"
BIN_NAME="wiliwili"
chmod +x "$BIN_NAME"
export LD_LIBRARY_PATH=$BIN_PATH/lib:$LD_LIBRARY_PATH
export PATH=$BIN_PATH:$PATH
./$BIN_NAME
需要按照上面的示例编写好 config. json 和 launch.sh 以后,需要将以下文件放到一个目录内,并将该目录上传到 Trimui 设备 TF 卡的 Apps 目录下。
• 程序文件(例如 my_program 或 wiliwili)
• 提取的依赖库目录(如 lib/)
• 配置文件 config.json
• 启动脚本 launch.sh
例如,最终的目录结构如下:
deploy/
├── lib/
│ ├── libc.so.6
│ ├── libm.so.6
│ └── ...
├── my_program
├── config.json
└── launch.sh