Skip to content

archbuild 脚本解读

Avimitin edited this page May 31, 2022 · 15 revisions

archbuild 脚本解读(在 Arch Linux x86_64 环境中构建 RISC-V 架构的软件包)


我们这里使用的打包命令是 extra-riscv64-build,是 devtools 包里的命令。但是官方仓库里面的 devtools 中只有extra-x86_64-build,所以我们需要手动给 devtools 打 patch。

安装 devtools

注:现在可以从 ArchLinuxCN 源中安装 devtools-riscv64 软件包,不需要通过以往手工打造的方式来安装。

# 添加源
echo '
[archlinuxcn]
Server = https://repo.archlinuxcn.org/$arch' >> /etc/pacman.conf && \
sudo pacman -Sy && sudo pacman -S archlinuxcn-keyring

# 下载 devtools
sudo pacman -S devtools-riscv64

ArchLinuxCN 源添加说明:https://github.com/archlinuxcn/repo#usage

🔙 返回新人指南

手动打 Patch 说明
  1. 下载 devtools 的构建脚本,这里使用的是 asp 命令。同时我们需要使用 devtools 软件包里面的 extra-x86_64-build 来打我们修改好的 devtools 软件包,所以需要先使用 pacman -S devtools asp来安装正常的 devtools 和 asp 软件包。
$ asp checkout devtools
  1. 给 devtools 包打 patch,这里需要用到三个文件。文件地址,建议直接 clone archriscv-packages 这个仓库。
$ git clone git@github.com:felixonmars/archriscv-packages.git
$ cd archriscv-packages/devtools-riscv64/

  1. 编译。这里使用的是 devtools 包里的 extra-x86_64-build 命令。 我打我自己
$ extra-x86_64-build
  1. 安装,使用 pacman -U 来安装本地包
# pacman -U devtools-xxxxxx-86_64.pkg.tar.zst

至此,包含 extra-riscv64-build 的 devtools 就已经安装到你的电脑上了。

使用extra-riscv64-build来进行打包操作

这里以 iana-etc 包来做演示。

  1. 获取包的构建文件
$ asp checkout iana-etc
  1. 使用 extra-riscv64-build 来构建包
$ cd iana-etc/trunk/
$ extra-riscv64-build -- -d /tmp/pkgcache:/var/cache/pacman/pkg/

这里 -d 指定了软件包的下载目录,如果不指定的话会试图读写本机 pacman cache 中的软件包,造成打包时软件安装失败的问题。这样写的原因是因为 -d 这个参数实际上是传递给 makepkg ,在makechrootpkg的帮助文档中写到,在--之后传递给这个脚本的参数将被传递给makepkg

最后可以看到包构建完成

关于 extra-riscv64-build 的相关知识

我们使用 ls -l 查看 \*-build

$ ls /bin/extra*build -l

lrwxrwxrwx 1 root root     9  8月 16 16:41 /bin/extra-riscv64-build -> archbuild
lrwxrwxrwx 1 root root     9  8月 16 16:41 /bin/extra-x86_64-build -> archbuild

可以看到所有的 -build 都软链接到 archbulid。 archbuild 是如何知道我们编译的是哪个架构的软件,并且如何运行打包的呢

阅读 archbuild 的源码

cmd="${0##*/}"
if [[ "${cmd%%-*}" == 'multilib' ]]; then
    repo="${cmd%-build}"
    arch='x86_64'
    base_packages+=(multilib-devel)
else
    tag="${cmd%-build}"
    repo=${tag%-*}
    arch=${tag##*-}
fi

我们可以看到,当我们调用 extra-riscv64-build 的时候,archbuild 先读取参数 0 也就是 extra-riscv64-build 命令名本身并把它赋值给 cmd。然后再对 cmd 中的内容进行拆分,得到 tag=extra-riscv64, repo=extra, arch=riscv64。

if ${clean_first} || [[ ! -d "${chroots}/${repo}-${arch}" ]]; then

    # 省略部分代码

    rm -rf --one-file-system "${chroots}/${repo}-${arch}"
    (umask 0022; mkdir -p "${chroots}/${repo}-${arch}")
    setarch "${set_arch}" mkarchroot \
        -C "${pacman_config}" \
        -M "${makepkg_config}" \
        "${chroots}/${repo}-${arch}/root" \
        "${base_packages[@]}" || abort
else
    lock 9 "${chroots}/${repo}-${arch}/root.lock" "Locking clean chroot"
    arch-nspawn \
        -C "${pacman_config}" \
        -M "${makepkg_config}" \
        "${chroots}/${repo}-${arch}/root" \
        pacman -Syuu --noconfirm || abort
fi

msg "Building in chroot for [%s] (%s)..." "${repo}" "${arch}"
exec makechrootpkg -r "${chroots}/${repo}-${arch}" "${makechrootpkg_args[@]}"

archbuild 的主要代码是上面这一部分,它先判断是否需要清理或者是否存在 chroot,如果需要清理或者不存在 chroot,我们就需要通过 mkarchroot 构建一个干净的 chroot。如果存在 chroot,那么我们直接运行arch-nspawn来将 chroot 中软件包还原为仓库中的版本。最后我们运行 makechrootpkg来在干净环境内进行软件包的构建。

参数解释

${chroots}/${repo}-${arch}/root

chroots='/var/lib/archbuild'

${chroots}/${repo}-${arch}/root 是干净环境的路径。即在这里面就是 /var/lib/archbuild/extra-riscv64/root

base_packages[@]

base_packages=(base-devel)

base_packages[@]表示将base-devel作为 mkarchroot 的参数。这边这样写的原因是:如果我们编译的是 multilib 架构的包,那么我们需要传递的是 base-develmultilib-devel

set_arch

setarch 读取了set_arch的值。

fi
if [[ -f "@pkgdatadir@/setarch-aliases.d/${arch}" ]]; then
    read -r set_arch < "@pkgdatadir@/setarch-aliases.d/${arch}"
else
    set_arch="${arch}"
fi

可以看到他判断了是否存在@pkgdatadir@/setarch-aliases.d/${arch}这个文件,如存在的话就将这个文件中的值赋值给set_arch,不存在的话就将变量arch的值赋值给set_arch。我们研究发现现在 setarch 没有 riscv64 的支持,同时在 x86_64 上也不会编译这个部分。于是我们采用了在@pkgdatadir@/setarch-aliases.d/${arch}这个文件中写入x86_64的方式来跳过 setarch 设置架构。

@pkgdatadir@/setarch-aliases.d/${arch}文件的具体路径为/usr/share/devtools/setarch-aliases.d/riscv64

$ cat /usr/share/devtools/setarch-aliases.d/riscv64
x86_64

pacman_configmakepkg_config

这里还有pacman_configmakepkg_config ,它们的赋值如下

pacman_config="@pkgdatadir@/pacman-${repo}.conf"
if [[ -f @pkgdatadir@/pacman-${repo}-${arch}.conf ]]; then
    pacman_config="@pkgdatadir@/pacman-${repo}-${arch}.conf"
fi
makepkg_config="@pkgdatadir@/makepkg-${arch}.conf"
if [[ -f @pkgdatadir@/makepkg-${repo}-${arch}.conf ]]; then
    makepkg_config="@pkgdatadir@/makepkg-${repo}-${arch}.conf"
fi

他们对应的是如果存在对对应架构的 pacman.conf 和 makepkg.conf 文件,就将对于的文件赋值给 pacman_config 和 makepkg_config。如果不存在的话,就采用默认的配置文件。

由于系统中原本不存在pacman-extra-riscv64.confmakepkg-extra-riscv64.conf。所以我们需要根据pacman-extra.confmakepkg-extra.conf来进行修改。

对于pacman-extra-riscv64.conf,我们需要修改它的架构和软件包仓库。

- Architecture = auto
+ Architecture = riscv64

 #[testing]
-#Include = /etc/pacman.d/mirrorlist
+#Server = https://mirrors.wsyu.edu.cn/archriscv/repo/$repo

 [core]
-Include = /etc/pacman.d/mirrorlist
+Server = https://mirrors.wsyu.edu.cn/archriscv/repo/$repo

 [extra]
-Include = /etc/pacman.d/mirrorlist
+Server = https://mirrors.wsyu.edu.cn/archriscv/repo/$repo

 #[community-testing]
-#Include = /etc/pacman.d/mirrorlist
+#Server = https://mirrors.wsyu.edu.cn/archriscv/repo/$repo

 [community]
-Include = /etc/pacman.d/mirrorlist
+Server = https://mirrors.wsyu.edu.cn/archriscv/repo/$repo

对于makepkg-extra-riscv64.conf,我们需要修改架构和编译工具以及编译参数。

- CARCH="x86_64"
- CHOST="x86_64-pc-linux-gnu"
+ CARCH="riscv64"
+ CHOST="riscv64-unknown-linux-gnu"

-CFLAGS="-march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fexceptions \
+CFLAGS="-march=rv64gc -mabi=lp64d -O2 -pipe -fno-plt -fexceptions \
         -Wp,-D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security \
-        -fstack-clash-protection -fcf-protection"
+        -fstack-clash-protection"

-march 指明大型的 64 位电脑,架构

-fcf-protection 会调用宏 CET(Control-flow Enforcement Technology) 控制流执行技术,目前只有 x86 gun /linux 中提供一个基于 intel 的 CET 实现

-mabi 指定生成的代码符合整数和浮点 ABI,与架构对应

注意: 在实际使用中,我们对makepkg-extra-riscv64.confpacman-extra-riscv64.conf的有更多的修改,详情请看肥猫大佬的 archriscv-packages 仓库中的devtools

补充内容

我们常常在编译软件包的时候并不是一次只编译一个软件包,可能会同时编译多个软件包。

但是我们阅读脚本,会发现他会在编译的时候对要使用的 chroot 进行锁定,这样一次就只能编译一个软件包。

我们查阅 makechrootpkg的帮助,发现里面有个参数 -l,可以通过-l指定 chroot 工作副本的路径,默认值是:当前使用脚本的用户名。我们如果想要同时编译多个软件包,只用在后几个编译命令上用 -l指定不一样的名称即可。

例如

$ cd devtools/trunk
$ extra-riscv64-build -- -d /tmp/pkgcache:/var/cache/pacman/pkg/

$ cd iana-etc/trunk
$ extra-riscv64-build -- -d /tmp/pkgcache:/var/cache/pacman/pkg/ -l dongdong1

使用上述写法这两个是软件包是可以同时进行编译。

Clone this wiki locally