跳到主要内容

简介

Duo 默认的 SDK 是基于 buildroot 构建的,用来生成 Duo 的固件,SDK 主要包含如下几个部分:

  • u-boot: 2021.10
  • linux kernel: 5.10.4
  • buildroot: 2021.05
  • opensbi: 89182b2

源码地址: github

SDK目录结构

├── build               // 编译目录,存放编译脚本以及各board差异化配置
├── build.sh // Milk-V Duo 一键编译脚本
├── buildroot-2021.05 // buildroot 开源工具
├── freertos // freertos 系统
├── fsbl // fsbl启动固件,prebuilt 形式存在
├── install // 执行一次完整编译后,临时存放各 image 路径
├── isp_tuning // 图像效果调试参数存放路径
├── linux_5.10 // 开源 linux 内核
├── middleware // 自研多媒体框架,包含 so 与 ko
├── device // 存放 Milk-V Duo 相关配置及脚本文件的目录
├── opensbi // 开源 opensbi 库
├── out // Milk-V Duo 最终生成的 SD 卡烧录镜像所在目录
├── ramdisk // 存放最小文件系统的 prebuilt 目录
└── u-boot-2021.10 // 开源 uboot 代码
提示

当前 SDK 不支持 Duo256M 和 DuoS 的 ARM 核,如果需要使用 ARM 核,可以暂时参考这个仓库:

duo-build: https://github.com/milkv-duo/duo-buildroot-sdk-v2

编译镜像

准备编译环境,使用本地的 Ubuntu 系统,官方支持的编译环境为 Ubuntu Jammy 22.04.x amd64

如果您使用的是其他的 Linux 发行版,我们强烈建议您使用 Docker 环境来编译,以降低编译出错的概率。

以下分别介绍两种环境下的编译方法。

一、使用 Ubuntu 22.04 编译

安装编译依赖的工具包

sudo apt install -y pkg-config build-essential ninja-build automake autoconf libtool wget curl git gcc libssl-dev bc slib squashfs-tools android-sdk-libsparse-utils jq python3-distutils scons parallel tree python3-dev python3-pip device-tree-compiler ssh cpio fakeroot libncurses5 flex bison libncurses5-dev genext2fs rsync unzip dosfstools mtools tcl openssh-client cmake expect python-is-python3

对于 duo-buildroot-sdk-v2,还需要安装以下工具包:

sudo pip install jinja2

获取 SDK

git clone https://github.com/milkv-duo/duo-buildroot-sdk.git --depth=1

1、一键编译

执行一键编译脚本 build.sh

cd duo-buildroot-sdk/
./build.sh

会看到编译脚本的使用方法提示:

# ./build.sh
Usage:
./build.sh - Show this menu
./build.sh lunch - Select a board to build
./build.sh [board] - Build [board] directly, supported boards asfollows:
milkv-duo-sd
milkv-duo-spinand
milkv-duo-spinor
milkv-duo256m-sd
milkv-duo256m-spinand
milkv-duo256m-spinor
milkv-duos-emmc
milkv-duos-sd

最下边列出的是当前支持的目标版本列表。

如提示中所示,有两种方法来编译目录版本。

第一种方法是执行 ./build.sh lunch 调出交互菜单,选择要编译的版本序号,回车:

# ./build.sh lunch
Select a target to build:
1. milkv-duo-sd
2. milkv-duo-spinand
3. milkv-duo-spinor
4. milkv-duo256m-sd
5. milkv-duo256m-spinand
6. milkv-duo256m-spinor
7. milkv-duos-emmc
8. milkv-duos-sd
Which would you like:

第二种方法是脚本后面带上目标版本的名字,比如要编译 milkv-duo-sd 的镜像:

# ./build.sh milkv-duo-sd

编译成功后可以在 out 目录下看到生成的SD卡烧录镜像 milkv-duo-sd-*-*.img

注: 第一次编译会自动下载所需的工具链,大小为 840M 左右,下载完会自动解压到 SDK 目录下的 host-tools 目录,下次编译时检测到已存在 host-tools 目录,就不会再次下载了

2、分步编译

如果未执行过一键编译脚本,需要先手动下载工具链 host-tools,并解压到 SDK 根目录:

tar -xf host-tools.tar.gz -C /your/sdk/path/

再依次输入如下命令完成分步编译,命令中的 [board][config] 替换为需要编译的版本,当前支持的 board 和对应的 config 如下:

milkv-duo-sd             cv1800b_milkv_duo_sd
milkv-duo-spinand cv1800b_milkv_duo_spinand
milkv-duo-spinor cv1800b_milkv_duo_spinor
milkv-duo256m-sd cv1812cp_milkv_duo256m_sd
milkv-duo256m-spinand cv1812cp_milkv_duo256m_spinand
milkv-duo256m-spinor cv1812cp_milkv_duo256m_spinor
milkv-duos-emmc cv1813h_milkv_duos_emmc
milkv-duos-sd cv1813h_milkv_duos_sd
source device/[board]/boardconfig.sh

source build/milkvsetup.sh
defconfig [config]
clean_all
build_all
pack_sd_image

比如需要编译 milkv-duo-sd 的镜像,分步编译命令如下:

source device/milkv-duo-sd/boardconfig.sh

source build/milkvsetup.sh
defconfig cv1800b_milkv_duo_sd
clean_all
build_all
pack_sd_image

生成的固件位置:

Duo:      install/soc_cv1800b_milkv_duo_sd/[board].img
Duo256M: install/soc_cv1812cp_milkv_duo256m_sd/[board].img

二、使用 Docker 编译

需要在运行 Linux 系统的主机上支持 Docker。 Docker 的使用方法请参考官方文档或其他教程。

我们将 SDK 代码放在 Linux 主机系统上,调用 Milk-V 提供的 Docker 镜像环境来编译。

在 Linux 主机上拉 SDK 代码

git clone https://github.com/milkv-duo/duo-buildroot-sdk.git --depth=1

进入 SDK 代码目录

cd duo-buildroot-sdk

拉取 Docker 镜像并运行

docker run --privileged -itd --name duodocker -v $(pwd):/home/work milkvtech/milkv-duo:latest /bin/bash

命令中部分参数说明:

  • --privileged 以特权模式启动容器。
  • duodocker docker 运行时名字,可以使用自己想用的名字。
  • $(pwd) 当前目录,这里是上一步 cd 到的 duo-buildroot-sdk 目录。
  • -v $(pwd):/home/work 将当前的代码目录绑定到 Docker 镜像里的 /home/work 目录。
  • milkvtech/milkv-duo:latest Milk-V 提供的 Docker 镜像,第一次会自动从 hub.docker.com 下载。

Docker 运行成功后,可以用 docker ps -a 命令查看运行状态:

$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8edea33c2239 milkvtech/milkv-duo:latest "/bin/bash" 2 hours ago Up 2 hours duodocker
提示

如果 Docker 服务器上的镜像有更新,可以使用 docker pull milkvtech/milkv-duo:latest 命令来同步最新的镜像。

1. 使用 Docker 一键编译

docker exec -it duodocker /bin/bash -c "cd /home/work && cat /etc/issue && ./build.sh [board]"

注意命令最后的 ./build.sh [board] 和前面在 Ubuntu 22.04 中一键编译说明中的用法是一样的,直接 ./build.sh 可以查看命令的使用方法,用 ./build.sh lunch 可以调出交互选择菜单,用 ./build.sh [board] 可以直接编译目标版本,[board] 可以替换为:

milkv-duo-sd
milkv-duo-spinand
milkv-duo-spinor
milkv-duo256m-sd
milkv-duo256m-spinand
milkv-duo256m-spinor
milkv-duos-emmc
milkv-duos-sd

命令中部分参数说明:

  • duodocker 运行的 Docker 名字, 与上一步中设置的名字要保持一致
  • "*" 双引号中是要在 Docker 镜像中运行的 Shell 命令
  • cd /home/work 是切换到 /home/work 目录,由于运行时已经将该目录绑定到主机的代码目录,所以在 Docker 中 /home/work 目录就是该 SDK 的源码目录
  • cat /etc/issue 显示 Docker 使用的镜像的版本号,目前是 Ubuntu 22.04.3 LTS,调试用
  • ./build.sh [board] 执行一键编译脚本

比如需要编译 milkv-duo-sd 的镜像,编译命令如下:

docker exec -it duodocker /bin/bash -c "cd /home/work && cat /etc/issue && ./build.sh milkv-duo-sd"

编译成功后可以在 out 目录下看到生成的SD卡烧录镜像 [board]-*-*.img

2. 使用 Docker 分步编译

如果未执行过一键编译脚本,需要先手动下载工具链 host-tools,并解压到 SDK 根目录:

tar -xf host-tools.tar.gz -C /your/sdk/path/

分步编译需要登陆到 Docker 中进行操作,用命令 docker ps -a 查看并记录容器的 ID 号,比如 8edea33c2239。

登陆到 Docker 中:

docker exec -it 8edea33c2239 /bin/bash

进入 Docker 中绑定的代码目录:

root@8edea33c2239:/# cd /home/work/

再依次输入如下命令完成分步编译,命令中的 [board][config] 替换为需要编译的版本,当前支持的 board 和对应的 config 如下:

milkv-duo-sd             cv1800b_milkv_duo_sd
milkv-duo-spinand cv1800b_milkv_duo_spinand
milkv-duo-spinor cv1800b_milkv_duo_spinor
milkv-duo256m-sd cv1812cp_milkv_duo256m_sd
milkv-duo256m-spinand cv1812cp_milkv_duo256m_spinand
milkv-duo256m-spinor cv1812cp_milkv_duo256m_spinor
milkv-duos-emmc cv1813h_milkv_duos_emmc
milkv-duos-sd cv1813h_milkv_duos_sd
source device/[board]/boardconfig.sh

source build/milkvsetup.sh
defconfig [config]
clean_all
build_all
pack_sd_image

比如需要编译 milkv-duo-sd 的镜像,分步编译命令如下:

source device/milkv-duo-sd/boardconfig.sh

source build/milkvsetup.sh
defconfig cv1800b_milkv_duo_sd
clean_all
build_all
pack_sd_image

生成的固件位置:

Duo:      install/soc_cv1800b_milkv_duo_sd/[board].img
Duo256M: install/soc_cv1812cp_milkv_duo256m_sd/[board].img

编译完成后可以用 exit 命令退出 Docker 环境:

root@8edea33c2239:/home/work# exit

在主机代码目录中同样也可以看到生成的固件。

停用 Docker

编译完成后,如果不再需要以上的 Docker 运行环境,可先将其停止,再删除:

docker stop 8edea33c2239
docker rm 8edea33c2239

三、其他编译注意事项

如果您想尝试在以上两种环境之外的环境下编译本 SDK,下面是可能需要注意的事项,仅供参考。

cmake 版本号

注意:cmake 版本最低要求 3.16.5

查看系统中 cmake 的版本号

cmake --version

比如在Ubuntu 20.04中用 apt 安装的 cmake 版本号为

cmake version 3.16.3

不满足此SDK最低要求,需要手动安装目前最新的 3.27.6 版本

wget https://github.com/Kitware/CMake/releases/download/v3.27.6/cmake-3.27.6-linux-x86_64.sh
chmod +x cmake-3.27.6-linux-x86_64.sh
sudo sh cmake-3.27.6-linux-x86_64.sh --skip-license --prefix=/usr/local/

手动安装的 cmake/usr/local/bin 中,此时用 cmake --version 命令查看其版本号, 应为

cmake version 3.27.6

使用 Windows Linux 子系统 (WSL) 进行编译

如果您希望使用 WSL 执行编译,则构建镜像时会遇到一个小问题,WSL 中的 $PATH 具有 Windows 环境变量,其中路径之间包含一些空格。

要解决此问题,您需要更改 /etc/wsl.conf 文件并添加以下行:

[interop]
appendWindowsPath = false

然后需要使用 wsl.exe --reboot 重新启动 WSL。再运行 ./build.sh 脚本或分步编译命令。

要恢复 /etc/wsl.conf 文件中的此更改,请将 appendWindowsPath 设置为 true。 要重新启动 WSL,您可以使用 Windows PowerShell 命令 wsl.exe --shutdown,然后使用wsl.exe,之后 Windows 环境变量在 $PATH 中再次可用。

四、添加应用包

Buildroot 是一个轻量级的嵌入式 Linux 系统构建框架,其生成的系统没有像 Ubuntu 系统一样的 apt 包管理工具来下载和使用应用包。Duo 默认的 SDK 已经添加了一些常用的工具或命令,如果您需要添加自己的应用,需要对 SDK 做一些修改后重新编译生成所需的系统固件。

以下介绍在 Buildroot 中添加应用包常用的几种方法。

开启 Busybox 中的命令

在使用 Buildroot 构建的系统中,部分基础命令由 busybox 提供,您可以查看 busybox 的配置文件中是否有您需要的命令,将其打开后重新编译即可,busybox 的配置文件位置在:

buildroot-2021.05/package/busybox/busybox.config

比如 timeout 命令,打开的方法:

diff --git a/buildroot-2021.05/package/busybox/busybox.config b/buildroot-2021.05/package/busybox/busybox.config
index d7d58f064..b268cd6f8 100644
--- a/buildroot-2021.05/package/busybox/busybox.config
+++ b/buildroot-2021.05/package/busybox/busybox.config
@@ -304,7 +304,7 @@ CONFIG_TEST=y
CONFIG_TEST1=y
CONFIG_TEST2=y
CONFIG_FEATURE_TEST_64=y
-# CONFIG_TIMEOUT is not set
+CONFIG_TIMEOUT=y
CONFIG_TOUCH=y
# CONFIG_FEATURE_TOUCH_NODEREF is not set
CONFIG_FEATURE_TOUCH_SUSV3=y

参考该次提交: busybox: add timeout command

配置 Buildroot 中预置的应用包

另外,Buildroot 中预置了大量的应用包,通过下载源码编译的方式来生成所需的程序,Buildroot 预置的应用包可以在 buildroot-2021.05/package 目录中查看。

配置使用或者禁用某个应用包,是在目标板的配置文件中实现的,以 milkv-duo-sd 目标为例,其 buildroot 配置文件是:

buildroot-2021.05/configs/milkv-duo-sd_musl_riscv64_defconfig

我们可以在宿主机(比如 Ubuntu)上整体编译过一次 SDK 后,到 Buildroot 编译目录中通过命令行菜单交互的方式来配置相关的应用包。

  1. 进入 Buildroot 编译目录

    cd buildroot-2021.05/output/milkv-duo-sd_musl_riscv64

    可以使用 make show-targets 命令来查看当前已经使用的应用包:

    $ make show-targets
    busybox coreutils dhcpcd dnsmasq dropbear duo-pinmux e2fsprogs evtest expat fio freetype gdb host-acl host-attr host-autoconf host-automake host-e2fsprogs host-fakeroot host-genimage host-libtool host-libzlib host-m4 host-makedevs host-mkpasswd host-patchelf host-pkgconf host-skeleton host-util-linux host-xz host-zlib htop ifupdown-scripts initscripts iperf3 json-c kmod libevent libffi libnl libopenssl libxml2 libxslt libzlib musl-compat-headers ncurses ntp openssl python-cffi python-evdev python-freetype python-lxml python-modbus-tk python-pillow python-pinpong python-pip python-psutil python-pycparser python-serial python-setuptools python-smbus-cffi python-spidev python3 skeleton skeleton-init-common skeleton-init-sysv spidev_test strace stress-ng tar toolchain toolchain-external toolchain-external-custom urandom-scripts util-linux wpa_supplicant zlib rootfs-ext2 rootfs-tar
  2. 配置 Buildroot

    执行 make menuconfig 命令,调出交互菜单:

    Document Pictures

    Target packages 中根据分类找到所需的应用包,如果不清楚应用包具体的位置,可以按 / 键搜索包名,比如我们要安装 tar 命令,由于搜索 tar 会出来太多其他无关内容,可以搜索 package_tar,可以看到,当前 =n 是禁用的状态,其位置为 Target packagesSystem tools 分类中,可以双击 ESC 键退回到主界面再进入到相应的位置,也可以按前面提示的数字直接进入到其所在的位置:

    Document Pictures

    按空格键选中:

    Document Pictures

    连续双击 ESC 键退出主界面,提示是否保存时,默认是 YES, 直接回车保存退出:

    Document Pictures

    执行 make savedefconfig 命令,将修改的配置保存到原始配置文件中,用 git status 命令确认一下,可以看到,原始配置文件已经被修改:

    Document Pictures

    此时回到 SDK 根目录重新编译即可。

    提示

    这里也可以比较一下编译目录中的旧配置文件和新配置文件的差异,把需要更改的部分直接手动修改到原始配置文件 milkv-duo-sd_musl_riscv64_defconfig 中:

    diff -u .config.old .config

    使用新编译的镜像启动后,在 Duo 设备上测试新加的命令,如果出现 not found 错误,可能是该包的 .mk 配置文件需要补充一下 gcc 的参数,主要是 TARGET_CFLAGSTARGET_LDFLAGS 两个参数要加上,可以参考如下几个提交:

    1. buildroot: enable fio
    2. buildroot: enable spidev_test
    3. buildroot: fix build parameter for coremark package

添加自己的应用包

编译测试自己的应用,不推荐集成到 Buildroot 工程中的方法。建议使用 duo-examples 的方式。

如果确实需要将自己的应用以 Buildroot package 方式编译,可以参考 Buildroot 中预置包的配置进行添加,以下是几个参考链接:

  1. buildroot: add python-evdev required by the pinpong library
  2. buildroot: add python-freetype required by the pinpong library

主要参考 buildroot-2021.05/package 中添加的内容。

五、删除不需要的应用包

如果你在自行编译固件的过程中,需要删除一些不需要的应用包来加快编译速度,或者禁用一些不需要的包,可以采用上述打开 Buildroot 应用包的 make menuconfig 方式,禁用相关的包。

也可以在 Buildroot 的配置文件中将对应的包名删除,以 milkv-duo-sd 目标为例,比如不需要编译 Python 相关的库,可以做如下修改后,重新编译生成固件即可。

buildroot-2021.05/configs/milkv-duo-sd_musl_riscv64_defconfig
diff --git a/buildroot-2021.05/configs/milkv-duo-sd_musl_riscv64_defconfig b/buildroot-2021.05/configs/milkv-duo-sd_musl_riscv64_defconfig
index 2bc8cd5e3..e78901afb 100644
--- a/buildroot-2021.05/configs/milkv-duo-sd_musl_riscv64_defconfig
+++ b/buildroot-2021.05/configs/milkv-duo-sd_musl_riscv64_defconfig
@@ -330,25 +330,6 @@ BR2_PACKAGE_EVTEST=y
# BR2_PACKAGE_FCONFIG is not set
BR2_PACKAGE_FLASHROM_ARCH_SUPPORTS=y

-BR2_PACKAGE_PYTHON3=y
-BR2_PACKAGE_PYTHON3_PY_PYC=y
-BR2_PACKAGE_PYTHON_LXML=y
-BR2_PACKAGE_PYTHON_PIP=y
-BR2_PACKAGE_PYTHON_SETUPTOOLS=y
-BR2_PACKAGE_PYTHON3_SSL=y
-
-BR2_PACKAGE_PYTHON_SERIAL=y
-BR2_PACKAGE_PYTHON_PILLOW=y
-BR2_PACKAGE_PYTHON_SMBUS_CFFI=y
-BR2_PACKAGE_PYTHON_SPIDEV=y
-BR2_PACKAGE_PYTHON_MODBUS_TK=y
-BR2_PACKAGE_PYTHON_EVDEV=y
-BR2_PACKAGE_PYTHON_FREETYPE=y
-
-BR2_PACKAGE_PYTHON_PINPONG=y
-
-BR2_PACKAGE_PYTHON_PSUTIL=y
-
#
# Compression and decompression
#

六、常见问题

Buildroot 编译出错排查方法

SDK 中 Buildroot 默认开启了顶层并行编译以加快编译速度,但是编译出错时,不方便分析出错的日志,所以我们可以先在 config 文件中将其删除,待排解决了问题之后,再将其重新打开。

milkv-duo-sd 目标为例,在其配置文件中将该配置删除后,再删除 buildroot-2021.05/output 目录,重新编译:

buildroot-2021.05/configs/milkv-duo-sd_musl_riscv64_defconfig
BR2_PER_PACKAGE_DIRECTORIES=y

编译出错时除了查看编译终端的出错信息,还可以查看 build/br.log 中的完整日志进行排查。

  • carbonfix
  • logan-milkv