Cvitek buildroot 打包 rootfs 流程介绍
基于 https://github.com/sophgo/cvi_mmf_sdk/tree/v4.1.0 的实现。
概述 在 cvi_mmf_sdk 中,支持两种生成 rootfs 的方式:
基于 ramdisk 目录下的文件系统。
基于 buildroot 打包生成文件系统。
前者仅保留了常用的一些工具,因此生成的文件系统较小,不过新增工具比较麻烦。后者方便用户自己控制需要打包哪些工具。
默认使用第一种方式来生成文件系统 ,可通过在板子的配置文件中加上 CONFIG_BUILDROOT_FS=y
(如 cv1812cp_sophpi_duo_sd_defconfig#L30 中的例子),以启用 buildroot
来生成文件系统。
rootfs 打包流程说明 在 source cvisetup.sh
之后,就可以使用 pack_rootfs
命令来打包文件系统了。它本质上是定义在 common_functions.sh 中的一个 shell 函数,在设置必要的环境变量后,通过 make rootfs
完成打包的相关处理。主要有3个步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 rootfs-prepare: rootfs-pack:rootfs-prepare rootfs-pack: rootfs:rootfs-pack rootfs: ifneq ($(STORAGE_TYPE) , sd) $(call raw2cimg ,rootfs.$(STORAGE_TYPE) ) endif
上面是基于 ramdisk
目录制作文件系统的流程,基于 buildroot
的流程也是类似的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 br-rootfs-prepare: br-rootfs-pack: ifeq ($(CONFIG_BUILDROOT_FS) ,y)rootfs:br-rootfs-prepare rootfs:br-rootfs-pack else rootfs:rootfs-pack rootfs: $(call print_target) ifneq ($(STORAGE_TYPE) , sd) $(call raw2cimg ,rootfs.$(STORAGE_TYPE) ) endif endif
有了基本流程的概念后,下面展开分析基于 buildroot
制作文件系统的流程。
br-rootfs-prepare br-rootfs-prepare
的主要工作是将需要打包到文件系统中的文件复制到指定的目录下,以便 buildroot 在制作文件系统时,能将这些文件一同打包。一般这些文件包括:
build_kernel
得到的 .ko
文件;
build_middleware
得到的动态库文件;
存放在 middlleware
中以 ko
或 so
形式发布的一些模块,如:middleware/v2/cv180x/ko 。
在 cvisetup.sh
中将需要的路径导出为环境变量,主要有:
1 2 3 4 5 6 7 8 9 10 11 12 13 export BR_DIR="$TOP_DIR " /buildroot-2021.05export BR_OVERLAY_DIR=${BR_DIR} /board/cvitek/${CHIP_ARCH} /overlayexport BR_BOARD=cvitek_${CHIP_ARCH} _${SDK_VER} export BR_DEFCONFIG=${BR_BOARD} _defconfigexport BR_ROOTFS_DIR="$OUTPUT_DIR " /tmp-rootfs
上述环境变量定义了文件复制的目标位置,在 br-rootfs-prepare
只进行复制即可!
1 2 3 4 5 6 7 8 br-rootfs-prepare: ${Q}mkdir -p $(BR_OVERLAY_DIR) /mnt/system ${Q}cp -arf ${SYSTEM_OUT_DIR}/* $(BR_OVERLAY_DIR) /mnt/system/ ${Q}find $(BR_OVERLAY_DIR) -name "*.ko" -type f -printf 'striping %p\n' -exec $(CROSS_COMPILE_KERNEL) strip --strip-unneeded {} \; ${Q}find $(BR_OVERLAY_DIR) -name "*.so*" -type f -printf 'striping %p\n' -exec $(CROSS_COMPILE_KERNEL) strip --strip-all {} \; ${Q}find $(BR_OVERLAY_DIR) -executable -type f ! -name "*.sh" ! -path "*etc*" ! -path "*.ko" -printf 'striping %p\n' -exec $(CROSS_COMPILE_SDK) strip --strip-all {} 2>/dev/null \;
br-rootfs-pack br-rootfs-pack
的主要工作是指定 buildroot 的配置文件,完成 buildroot 的编译工作,以得到需要的文件系统。
1 2 3 4 5 6 7 8 9 10 11 br-rootfs-pack:export TARGET_OUTPUT_DIR=$(BR_DIR) /output/$(BR_BOARD) br-rootfs-pack: ${Q}$(MAKE) -C $(BR_DIR) $(BR_DEFCONFIG) BR2_TOOLCHAIN_EXTERNAL_PATH=$(CROSS_COMPILE_PATH) ${Q}$(MAKE) -j${NPROC} -C $(BR_DIR) ${Q}cp $(TARGET_OUTPUT_DIR) /images/rootfs.ext4 $(OUTPUT_DIR) /rawimages/rootfs_ext4.$(STORAGE_TYPE) $(call raw2cimg ,rootfs_ext4.$(STORAGE_TYPE) )
至此,就得到了 buildroot 编译的文件系统,不过需要注意的是:该文件系统中仅包含了 ko
和 动态库,ramdisk 中的一些开机自动运行的脚本并未包含进文件系统中,因此没有自动加载 ko 等流程
buildroot 配置文件说明 目前 buildroot/configs
目录下提供了 cv180x, cv181x
的基础配置文件,用户可在该配置文件的基础上进行修改,部分参数与上面介绍的编译流程或编译工具链有关,不可随意更改。
1 2 3 4 5 6 7 BR2_TOOLCHAIN_* BR2_TOOLCHAIN_EXTERNAL_PREFIX="riscv64-unknown-linux-musl" BR2_TARGET_LDFLAGS="-mcpu=c906fdv -march=rv64imafdcv0p7xthead -mcmodel=medany -mabi=lp64d" BR2_ROOTFS_OVERLAY="board/cvitek/CV181X/overlay"
网络问题 1 2 3 4 5 6 BR2_BACKUP_SITE="http://sources.buildroot.net" BR2_KERNEL_MIRROR="https://mirrors.aliyun.com/linux-kernel" BR2_GNU_MIRROR="https://mirrors.aliyun.com/gnu" BR2_LUAROCKS_MIRROR="https://luarocks.cn" BR2_CPAN_MIRROR="https://mirrors.aliyun.com/CPAN"
有些仓库设置上面的代理也没用😑,就需要手动下载后,放到 buildroot-2021.05/dl
对应模块的文件夹下 。
打包 public 工具问题 在使用 ramdisk 方式打包文件系统时,有从好几个地方复制文件。一般来说,既然选择用 buildroot 了,一些三方工具都直接用 buildroot 编译的就好,不需要拷贝。不过像 S11defer_init 这个文件,又必须从 ramdisk 拷贝。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 define TARGET_PACKAGE_INSTALL_CMD @echo 'TARGET PACKAGE OUTPUT DIR=$(OUTPUT_DIR) /rootfs';\ $(foreach t,$(TARGET_PACKAGES) ,\ ${Q}cd $(TOP_DIR) /ramdisk/rootfs/public/$(t) /$(packages_arch) / && \ ${Q}find . \( ! -type d ! -name "*.a" ! -path "*include*" ! -name ".gitkeep" \) \ -printf 'Copy Package file $(TOP_DIR) /ramdisk/rootfs/public/$(t) /$(packages_arch) /%p\n' \ -exec cp -a --remove-destination --parents '{}' $(OUTPUT_DIR) /rootfs/ \; ; ) endef rootfs-prepare:$(OUTPUT_DIR) /rootfs ifeq ($(CONFIG_FASTBOOT) ,y) ${Q}cp -a --remove-destination $(RAMDISK_PATH) /rootfs/$(ROOTFS_BASE) _shrink/* $(OUTPUT_DIR) /rootfs else ${Q}cp -a --remove-destination $(RAMDISK_PATH) /rootfs/$(ROOTFS_BASE) /* $(OUTPUT_DIR) /rootfs endif ifneq ("$(wildcard $(SDK_VER_FOLDER_PATH) )" , "" ) ${Q}cp -r $(SDK_VER_FOLDER_PATH) /* $(OUTPUT_DIR) /rootfs endif ifneq ("$(wildcard $(CHIP_FOLDER_PATH) )" , "" ) ${Q}cp -r $(CHIP_FOLDER_PATH) /* $(OUTPUT_DIR) /rootfs endif ifneq ("$(wildcard $(CUST_FOLDER_PATH) )" , "" ) ${Q}cp -r $(CUST_FOLDER_PATH) /* $(OUTPUT_DIR) /rootfs endif $(call TARGET_PACKAGE_INSTALL_CMD) ${Q}${BUILD_PATH}/boards/default/rootfs_script/prepare_rootfs.sh $(OUTPUT_DIR) /rootfs ${Q}python3 $(COMMON_TOOLS_PATH) /image_tool/create_automount.py $(FLASH_PARTITION_XML) $(OUTPUT_DIR) /rootfs/etc/init.d/ ${Q}python3 $(COMMON_TOOLS_PATH) /image_tool/mkcvipart.py $(FLASH_PARTITION_XML) $(OUTPUT_DIR) /rootfs/etc/ --fw_env ifneq ($(CONFIG_FASTBOOT) ,y) if [ -f $(ROOTFS_DIR) /etc/init.d/fastboot ]; then ${Q}rm -rf $(ROOTFS_DIR) /etc/init.d/fastboot ; fi ; if [ -f $(ROOTFS_DIR) /etc/init.d/S11defer_init ]; then ${Q}rm -rf $(ROOTFS_DIR) /etc/init.d/S11defer_init; fi ; endif
上面从几个路径拷了文件,在使用 buildroot 时,可以选择只从 Project 路径拷贝。
1 2 3 4 CUST_FOLDER_NAME = cv1813ha_wevb_0007a_emmc CHIP_FOLDER_PATH = /data/song.yu/youdao2/v4.2.0-intl/ramdisk/rootfs/overlay/cv1813ha SDK_VER_FOLDER_PATH = /data/song.yu/youdao2/v4.2.0-intl/ramdisk/rootfs/overlay/cv181x_32bit CUST_FOLDER_PATH = /data/song.yu/youdao2/v4.2.0-intl/ramdisk/rootfs/overlay/cv1813ha_wevb_0007a_emmc
将必需的文件放在 ramdisk/rootfs/overlay/cv1813ha_wevb_0007a_emmc
目录下就行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 br-rootfs-prepare: $(call print_target) ifneq ("$(wildcard $(CUST_FOLDER_PATH) )" , "" ) ${Q}cp -r $(CUST_FOLDER_PATH) /* $(BR_OVERLAY_DIR) endif ${Q}python3 $(COMMON_TOOLS_PATH) /image_tool/create_automount.py $(FLASH_PARTITION_XML) $(BR_OVERLAY_DIR) /etc/init.d/ ${Q}python3 $(COMMON_TOOLS_PATH) /image_tool/mkcvipart.py $(FLASH_PARTITION_XML) $(BR_OVERLAY_DIR) /etc/ --fw_env ifneq ($(CONFIG_FASTBOOT) ,y) if [ -f $(ROOTFS_DIR) /etc/init.d/fastboot ]; then ${Q}rm -rf $(ROOTFS_DIR) /etc/init.d/fastboot ; fi ; if [ -f $(ROOTFS_DIR) /etc/init.d/S11defer_init ]; then ${Q}rm -rf $(ROOTFS_DIR) /etc/init.d/S11defer_init; fi ; endif ${Q}mkdir -p $(BR_OVERLAY_DIR) /mnt/system ${Q}cp -arf ${SYSTEM_OUT_DIR}/* $(BR_OVERLAY_DIR) /mnt/system/ ${Q}find $(BR_OVERLAY_DIR) -name "*.ko" -type f -printf 'striping %p\n' -exec $(CROSS_COMPILE_KERNEL) strip --strip-unneeded {} \; ${Q}find $(BR_OVERLAY_DIR) -name "*.so*" -type f -printf 'striping %p\n' -exec $(CROSS_COMPILE_KERNEL) strip --strip-all {} \; ${Q}find $(BR_OVERLAY_DIR) -executable -type f ! -name "*.sh" ! -path "*etc*" ! -path "*.ko" -printf 'striping %p\n' -exec $(CROSS_COMPILE_SDK) strip --strip-all {} 2>/dev/null \;
如果非要 rootfs/public 下的工具,也在加上这个,不建议!还是直接修改 buildroot 配置更好。
1 2 3 4 5 6 7 8 define TARGET_PACKAGE_INSTALL_CMD_BR @echo 'TARGET PACKAGE OUTPUT DIR=$(BR_OVERLAY_DIR) ';\ $(foreach t,$(TARGET_PACKAGES) ,\ ${Q}cd $(TOP_DIR) /ramdisk/rootfs/public/$(t) /$(packages_arch) / && \ ${Q}find . \( ! -type d ! -name "*.a" ! -path "*include*" ! -name ".gitkeep" \) \ -printf 'Copy Package file $(TOP_DIR) /ramdisk/rootfs/public/$(t) /$(packages_arch) /%p\n' \ -exec cp -a --remove-destination --parents '{}' $(BR_OVERLAY_DIR) / \; ; ) endef
其他
❗❗注意:buildroot 目录下的 output/xxx 中的文件,并不会自动删除。也就是说,overlay中第一次添加了某个文件,后面不需要这个文件了,仅从overlay目录删除还不够,必须从 output/xxx/target 中删除,而且有时候奇奇怪怪的编译报错,直接清空 output/xxx 文件夹也能解决。
❗也不能简单地直接 只 删除output/xxx/target 中的文件,有一些文件、文件夹是在 buildroot 某个模块的编译过程中放进去的,只删除目标文件,而不清楚编译中间文件 output/xxx/build,那些文件也不会重新生成。
如果在流程中自动清空 output/xxx 文件夹,会导致编译时间变得很长。
如何去掉开机必须输入用户名、密码?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 修改 getty 服务 如果你使用的是 getty 来管理终端登录,可以在 /etc/inittab 文件中设置自动登录。 编辑 /etc/inittab: 打开 /etc/inittab 文件(如果存在),找到类似于以下的行: 1:2345:respawn:/sbin/getty 38400 tty1 修改为: 1:2345:respawn:/sbin/getty --noclear tty1 创建自动登录的脚本: 在 /etc/init.d/ 下创建一个脚本,命名为 autologin,内容如下: #!/bin/sh exec /bin/login -f your_username 替换 your_username 为你的实际用户名。 使脚本可执行: chmod +x /etc/init.d/autologin
不显示当前所在路径,增加 /etc/profile
文件。\u: user \h: host
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 export LD_LIBRARY_PATH="/lib:/lib/3rd:/usr/lib:/mnt/system/lib:/mnt/system/usr/lib:/mnt/system/usr/lib/3rd:/mnt/data/lib" export PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/mnt/system/usr/bin:/mnt/system/usr/sbin:/mnt/data/bin:/mnt/data/sbin" if [ "$PS1 " ]; then if [ "`id -u`" -eq 0 ]; then export PS1='# ' else export PS1='$ ' fi fi export PAGER='/bin/more ' export EDITOR='/bin/vi' for i in /etc/profile.d/*.sh ; do if [ -r "$i " ]; then . $i fi unset i done export HOSTNAME="$(hostname) " export OLDPWD=/rootif [ '$USER' == 'root' ]; then export PS1='[\u@\h]\w\# ' else export PS1='[\u@\h]\w\$ ' fi alias ll='ls -alF' alias la='ls -A' alias l='ls -CF'
修改之后,就显示 [root@cvitek]~#
使用 erofs 只读文件系统后,/var/run 中也只读,导致一些动态生成的文件(如 PID 文件、socket 文件等)无法写入。增加 `/etc/fstab 文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 ramdisk/rootfs/common_arm/etc$ cat fstab # <file system> <mount pt> <type> <options> <dump> <pass> /dev/root / ext2 rw,noauto 0 1 proc /proc proc defaults 0 0 devpts /dev/pts devpts defaults,gid=5,mode=620,ptmxmode=0666 0 0 tmpfs /dev/shm tmpfs mode=0777 0 0 tmpfs /tmp tmpfs mode=1777 0 0 tmpfs /run tmpfs mode=0755,nosuid,nodev 0 0 tmpfs /var/run tmpfs mode=0755,nosuid,nodev 0 0 tmpfs /var/lock tmpfs mode=0755,nosuid,nodev 0 0 tmpfs /var/empty tmpfs mode=0755,nosuid,nodev 0 0 sysfs /sys sysfs defaults 0 0 nodev /sys/kernel/debug debugfs defaults 0 0