柚子/在 Windows WSL 中的 Trimui 应用编译环境构建指北

Created Sun, 15 Dec 2024 06:56:08 +0000 Modified Sat, 28 Dec 2024 11:52:18 +0000
By 柚子 1966 Words 9 min Edit

一、准备工作

首先,在 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-essentialgitwget 等:

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 设备上,具体步骤如下:

  1. 在 WSL 编译环境中运行脚本提取依赖库:
./export_libs.sh ./my_program ./lib

脚本会扫描 my_program 的依赖并将所有 .so 文件复制到 ./lib 目录。

  1. 将二进制文件和依赖库打包上传到设备:

  2. 在设备上运行程序时设置动态链接库路径:

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