buildroot(1) -- 编译过程记录

1. 前言

我需要交叉编译一个gnutls的开源库,该库还依赖了其他的库,可能是我下载的源码都是最新的,有些库的编译框架发生了变化,最后折腾了很久还是失败了。然后了解到Buildroot,这是一个很强大的集成环境,其中就有gnutls这个包,索性去研究一下。这并不是我第一次听说Buildroot,在Qemu(1) — Ubuntu下运行CK860 Qemu这篇文章中,我就使用过buildroot编译后的产物,但那个不是我编出来的,那就亲手编译一次吧。

2. 下载代码

Buildroot官方的库中不支持csky架构,在github上有一个c-sky/buildroot库,该库在Buildroot官方库的基础上,添加了对csky架构的支持。查看c-sky/buildrootMakefile文件,可以看到它添加支持的过程。

3. 构建docker镜像

wsl(6) – 安装docker文章中描述了docker的一些事情,使用docker进行各种环境部署是很方便的,既不用担心会把当前的系统弄得太乱,也能比较好的记录过程,方便以后的自动化。下面是我完成部署后总结的Dockerfile,其中主要是收集了一些buildroot环境需要的命令和库,方便一次性安装。buildroot目录比较大,就放在wsl目录下,启动docker时挂载上去,目前这个docker镜像800多M。

# 基于ubuntu_base镜像
FROM ubuntu_base

# 切换到root用户
USER root

# 安装buildroot构建环境所需库
# file patch wget cpio rsync bc bzip2 git是buildroot构建所需要的
# python3在buildroot构建openssl库时会用到,且需要将其链接为python
# libbrlapi-dev libvdeplug-dev libaio-dev libpixman-1-dev libbluetooth-dev libsnappy-dev是qemu运行所需要的库,其中有些库还需要创建新的软连接
# xz-utils zlib1g-dev libnuma-dev liblzo2-dev m4这些在构建libpng libnettle源码时使用
# libncurses-dev在进行make menuconfig时需要
# bridge-utils uml-utilities isc-dhcp-client创建和管理网桥时需要,通过网桥可以将qemu与外界联系起来
# telnet可用于连接qemu
# libncurses.so.5用于支持csky-gdb的运行
# wget下载时提示网站证书检验失败,需要添加--no-check-certificate参数
RUN apt-get update \
 && apt-get install -y --no-install-recommends file patch wget cpio rsync bc bzip2 git python3 \
    libbrlapi-dev libvdeplug-dev libaio-dev libpixman-1-dev libbluetooth-dev \
    libsnappy-dev xz-utils zlib1g-dev libnuma-dev liblzo2-dev m4 \
    libncurses-dev bridge-utils uml-utilities isc-dhcp-client telnet \
 && ln -s /usr/bin/python3 /usr/bin/python \
 && ln -s libbrlapi.so /lib/x86_64-linux-gnu/libbrlapi.so.0.6 \
 && ln -s libaio.so /usr/lib/x86_64-linux-gnu/libaio.so.1 \
 && ln -s libncurses.so.6 /usr/lib/x86_64-linux-gnu/libncurses.so.5 \
 && wget --no-check-certificate https://ppa.launchpadcontent.net/linuxuprising/libpng12/ubuntu/pool/main/libp/libpng/libpng_1.2.54.orig.tar.xz \
 && tar -xf libpng_1.2.54.orig.tar.xz; cd libpng-1.2.54 \
 && ./configure; make -j8; make install; cd ..; rm -rf libpng-1.2.54 libpng_1.2.54.orig.tar.xz \
 && ln -s /usr/local/lib/libpng12.so.0.54.0 /usr/lib/libpng12.so.0 \
 && wget --no-check-certificate https://ftp.gnu.org/gnu/nettle/nettle-3.2.tar.gz \
 && tar -xf nettle-3.2.tar.gz; cd nettle-3.2 \
 && ./configure; make -j8; make install; cd ..; rm -rf nettle-3.2 nettle-3.2.tar.gz \
 && ln -s /usr/local/lib64/libnettle.so.6 /lib/libnettle.so.6 \
 && apt-get clean \
 && apt-get autoclean

# 切换为xflm
USER xflm

Dockerfile中提到的ubuntu_base基础镜像,可参考在wsl(6) – 安装docker文章。使用docker命令依据Dockerfile构建一个新的镜像buildroot

$ docker build -t buildroot .

4. 在docker中编译

启动ubuntu_buildroot,并挂载buildroot目录。

# 将csky的buildroot目录挂载到容器/buildroot上
$ docker run -it -v /home/xflm/workspace/buildroot:/buildroot --name=buildroot buildroot
# 此处即进入容器中,在容器中进入/buildroot目录
xflm@b1b77bb58c37:~$ cd /buildroot
# 启动buildroot的编译,期间会出现几次错误,需要逐一排解
xflm@b1b77bb58c37:~$ make CONF=thead_860_compat_5.10_glibc_br_defconfig

5. 问题记录

编译完成后,当前目录结构如下,之后的问题记录中路径都是以工作目录为相对路径。

# 工作目录,也即csky的buildroot目录
$ ls
LICENSE   README.md  buildroot-9d1d4818c39d97ad7a1cdf6e075b9acae6dfff71  configs_enhanced  fs       patches
Makefile  board      configs                                             dl                package  thead_860_compat_5.10_glibc_br_defconfig
# 官方的buildroot目录
$ ls buildroot-9d1d4818c39d97ad7a1cdf6e075b9acae6dfff71
CHANGES  Config.in         DEVELOPERS  Makefile.legacy  arch   boot            configs  docs  linux    support  toolchain
COPYING  Config.in.legacy  Makefile    README           board  callchain_test  dl       fs    package  system   utils
# 编译输出目录
$ ls thead_860_compat_5.10_glibc_br_defconfig/
Makefile  build  host  images  staging  target
# 查看下各目录的大小,有些目录我做过修改,数值不是最开始编译后的大小,但相差不大
$ du -sh *
12K     LICENSE
4.0K    Makefile
8.0K    README.md
140K    board
74M     buildroot-9d1d4818c39d97ad7a1cdf6e075b9acae6dfff71
124K    configs
148K    configs_enhanced
864M    dl
12K     fs
5.2M    package
84K     patches
8.2G    thead_860_compat_5.10_glibc_br_defconfig

5.1 关于出错

我编译的时候遇到了fakerootm4两个包编译出错,可以根据基于WSL和玄铁官方仓库c-sky/buildroot构建玄铁CPU系统镜像文章中的方法进行修改,也可以去buildroot仓库下载更新的package,替换掉buildroot-9d1d4818c39d97ad7a1cdf6e075b9acae6dfff71/package/下面的包。

  1. 比如m4包,其目前最新的发布版本为2025.02-rc1,按照下面(很有规律)的网址即可找到该包的内容。
    https://gitlab.com/buildroot.org/buildroot/-/tree/2025.02-rc1/package/m4?ref_type=tags
  2. 点击【Code】》【Download this directory】》【tar.gz】即可下载该目录的内容为:buildroot-2025.02-rc1-package-m4.tar.gz
    https://gitlab.com/buildroot.org/buildroot/-/archive/2025.02-rc1/buildroot-2025.02-rc1.tar.gz?path=package/m4
  3. 删除buildroot-9d1d4818c39d97ad7a1cdf6e075b9acae6dfff71/package/m4文件夹。
  4. 解压buildroot-2025.02-rc1-package-m4.tar.gz,将解压后的目录移动为buildroot-9d1d4818c39d97ad7a1cdf6e075b9acae6dfff71/package/m4
  5. 执行make CONF=thead_860_compat_5.10_glibc_br_defconfig,buildroot会下载新的m4软件源码,然后进行编译,编译的过程中提示了autoconf的版本较低,所以我又按照同样的方式替换了autoconf的包。

在编译内核时遇到了usr/bin/ld: scripts/dtc/dtc-parser.tab.o:(.bss+0x50): multiple definition of 'yylloc‘这个错误,根据编译Linux内核出现:usr/bin/ld: scripts/dtc/dtc-parser.tab.o:(.bss+0x50): multiple definition of yylloc‘;解决了。修改thead_860_compat_5.10_glibc_br_defconfig/build/linux-5.10.4/scripts/dtc/dtc-lexer.lex.c629行将YYLTYPE yylloc;修改为extern YYLTYPE yylloc;

5.2 关于下载慢

dl/中存放着已下载并校验通过的源码包,在编译前该目录是空的,编译的过程中会根据需要自动下载,buildroot中每个包都有多个下载地址,下载时会在日志中打印出来,当地址不通时,buildroot等待会超时,然后切换到其他地址。
若有些地址能下载,但是下载的很慢,则可以CTRL+C终止buildroot,将下载地址拷贝到迅雷中进行下载,下载完毕,手动拷贝到dl/对应的目录中,然后再重新执行make CONF=thead_860_compat_5.10_glibc_br_defconfig,buildroot会跳过之前的下载步骤,直接进入解压编译环节。

5.3 关于工具链

thead_860_compat_5.10_glibc_br_defconfig/host/bin/目录下有许多可执行程序,这些程序是运行在宿主机上的,其中包括csky-abiv2-linux-gcc工具链,使用该工具链时,无需再添加-mcpu=ck860

# 查看工具链默认的sysroot
$ ./thead_860_compat_5.10_glibc_br_defconfig/host/bin/csky-abiv2-linux-gcc --print-sysroot
/buildroot/thead_860_compat_5.10_glibc_br_defconf/host/csky-buildroot-linux-gnuabiv2/sysroot/ck860/./
# 该工具链其实是一个软连接
$ ll ./thead_860_compat_5.10_glibc_br_defconfig/host/bin/csky-abiv2-linux-gcc
lrwxrwxrwx  ./thead_860_compat_5.10_glibc_br_defconfig/host/bin/csky-abiv2-linux-gcc -> toolchain-wrapper*
# 查看toolchain-wrapper中的字符串,推测是由该程序设置了csky-abiv2-linux-gcc的sysroot值
$ strings ./thead_860_compat_5.10_glibc_br_defconfig/host/bin/toolchain-wrapper
...
-mcpu=ck860
--sysroot
# 真正的工具链在这里
$ ./thead_860_compat_5.10_glibc_br_defconfig/host/opt/ext-toolchain/bin/csky-abiv2-linux-gcc --print-sysroot
/buildroot/thead_860_compat_5.10_glibc_br_defconfig/host/opt/ext-toolchain/bin/../csky-linux-gnuabiv2/libc/

6. 添加新的软件包

# 执行下面的命令,进入图形界面,勾选需要的软件包
$ make -C thead_860_compat_5.10_glibc_br_defconfig menuconfig
# 勾选后保存改动,启动编译
$ make -C thead_860_compat_5.10_glibc_br_defconfig

7. 向根文件系统镜像中添加文件

此处添加一个package/user-copy来实现文件的拷贝。

  1. 创建buildroot-9d1d4818c39d97ad7a1cdf6e075b9acae6dfff71/package/user-copy/并进入该目录。
$ mkdir buildroot-9d1d4818c39d97ad7a1cdf6e075b9acae6dfff71/package/user-copy/
$ cd buildroot-9d1d4818c39d97ad7a1cdf6e075b9acae6dfff71/package/user-copy/
  1. 创建Config.in,用于将我们自定义的package添加到menuconfig中。
config BR2_PACKAGE_USER_COPY
	bool "user copy files to rootfs"
	help
	  A package to copy user files to rootfs.
  1. 编辑../Config.in,在末尾添加。
menu "User operation"
	source "package/user-copy/Config.in"
endmenu
  1. 创建user_copy.mk,这里用到了install命令,它和cp命令相似,此处目的是在thead_860_compat_5.10_glibc_br_defconfig/target下创建root/share目录,添加etc/profile.d/profile_user.sh文件。
USER_COPY_VERSION = 1.0
USER_COPY_SITE = $(TOPDIR)/package/user-copy
USER_COPY_SITE_METHOD = local

define USER_COPY_INSTALL_TARGET_CMDS
	$(INSTALL) -d $(TARGET_DIR)/root/share
	$(INSTALL) -D -m 0644 $(USER_COPY_SITE)/profile_user.sh $(TARGET_DIR)/etc/profile.d/profile_user.sh
endef

$(eval $(generic-package))
  1. 创建profile_user.sh,用于进行共享文件夹的挂载以及网络配置。
#!/bin/bash

mount | grep /root/share > /dev/null || mount -t 9p -o trans=virtio,version=9p2000.L hostshare /root/share
ifconfig | grep eth0 > /dev/null || ifconfig eth0 192.168.101.201
test -f ~/.bashrc && . ~/.bashrc
  1. 执行配置,然后编译。
# 执行下面的命令,进入图形界面,选中【User operation】》【user copy files to rootfs】
$ make -C thead_860_compat_5.10_glibc_br_defconfig menuconfig
# 勾选后保存改动,启动编译
$ make -C thead_860_compat_5.10_glibc_br_defconfig
# 若user-copy发生了改变,make可能并不会触发动作,此时可以针对user-copy进行rebuild,然后再执行make
$ make -C thead_860_compat_5.10_glibc_br_defconfig user-copy-rebuild
$ make -C thead_860_compat_5.10_glibc_br_defconfig

6. 使用qemu运行

参考Qemu(1) — Ubuntu下运行CK860 Qemu,在当前目录新建一个qemu/share的目录。

  1. 新建qemu/qemu.sh文件。
#!/bin/bash

# 获取qemu.sh的绝对路径,qemu启动参数中涉及的文件路径需要使用绝对路径
QEMU_DIR=$(dirname $(readlink -f "$0"))
CONF=thead_860_compat_5.10_glibc_br_defconfig

echo ">>>>>> 同时按下CTRL+a,松开后按下x强制关机,关机前请执行sync命令,执行reboot也能关机 <<<<<<"

OUTPUT_DIR=$QEMU_DIR/../$CONF

# qemu的启动参数,此处还配置了qemu的共享目录和网络
sudo $OUTPUT_DIR/host/csky-qemu/bin/qemu-system-cskyv2 \
-M virt \
-cpu c860 \
-smp 4 \
-m 1G \
-kernel $OUTPUT_DIR/images/Image \
-nographic \
-append "console=ttyS0,115200 rdinit=/sbin/init rootwait root=/dev/vda ro" \
-drive file=$OUTPUT_DIR/images/rootfs.ext2,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-fsdev local,security_model=passthrough,id=fsdev0,path=$QEMU_DIR/share \
-device virtio-9p-device,id=fs0,fsdev=fsdev0,mount_tag=hostshare \
-netdev tap,script=no,downscript=no,id=net0 \
-device virtio-net-device,netdev=net0
  1. 使用sudo运行qemu,即可启动并进入控制台。
$ sudo ./qemu/qemu.sh
...
Welcome to Buildroot
buildroot login: root # 此处输入root用户,回车后即可进入,因为是root用户命令提示符为"#"
# pwd
/root
# ls
share
  1. 新开一个wsl的窗口。
# 新开一个buildroot容器的窗口
$ docker exec -it buildroot bash
# 设置tap网络地址
$ sudo ifconfig tap0 192.168.101.200
# 通过telnet连接qemu
$ telnet 192.168.101.201
...
buildroot login: root # 此处输入root用户,回车后即可进入,因为是root用户命令提示符为"#"
# pwd
/root
  1. qemu中对文件系统的修改都会保存在rootfs.ext2文件中,下次启动时仍然有效,buildroot重新编译后会生成新的rootfs.ext2文件进行覆盖。

7. 配置网桥

wsl上配置网桥一直未成功,在VMware虚拟机上是可行的,这可能与wsl有关系,暂时先不弄了。

参考

基于WSL和玄铁官方仓库c-sky/buildroot构建玄铁CPU系统镜像
编译Linux内核出现:usr/bin/ld: scripts/dtc/dtc-parser.tab.o:(.bss+0x50): multiple definition of `yylloc‘;
Ubuntu 安装libpng12的方法
buildroot 增加自己的应用程序
Buildroot 添加自定义模块-内置文件到文件系统
如何配置 QEMU 虚拟机网络
install 命令用法详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值