-
Notifications
You must be signed in to change notification settings - Fork 80
archbuild 脚本解读
我们这里使用的打包命令是 extra-riscv64-build
,是 devtools 包里的命令。但是官方仓库里面的 devtools 中只有extra-x86_64-build
,所以我们需要手动给 devtools 打 patch。
注:现在可以从 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 说明
- 下载 devtools 的构建脚本,这里使用的是 asp 命令。同时我们需要使用 devtools 软件包里面的
extra-x86_64-build
来打我们修改好的 devtools 软件包,所以需要先使用pacman -S devtools asp
来安装正常的 devtools 和 asp 软件包。
$ asp checkout devtools
- 给 devtools 包打 patch,这里需要用到三个文件。文件地址,建议直接 clone archriscv-packages 这个仓库。
$ git clone [email protected]:felixonmars/archriscv-packages.git
$ cd archriscv-packages/devtools-riscv64/
- 编译。这里使用的是 devtools 包里的
extra-x86_64-build
命令。我打我自己
$ extra-x86_64-build
- 安装,使用 pacman -U 来安装本地包
# pacman -U devtools-xxxxxx-86_64.pkg.tar.zst
至此,包含 extra-riscv64-build
的 devtools 就已经安装到你的电脑上了。
这里以 iana-etc 包来做演示。
- 获取包的构建文件
$ asp checkout iana-etc
- 使用
extra-riscv64-build
来构建包
$ cd iana-etc/trunk/
$ extra-riscv64-build -- -d /tmp/pkgcache:/var/cache/pacman/pkg/
这里 -d
指定了软件包的下载目录,如果不指定的话会试图读写本机 pacman cache 中的软件包,造成打包时软件安装失败的问题。这样写的原因是因为 -d
这个参数实际上是传递给 makepkg
,在makechrootpkg
的帮助文档中写到,在--
之后传递给这个脚本的参数将被传递给makepkg
。
最后可以看到包构建完成
我们使用 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='/var/lib/archbuild'
${chroots}/${repo}-${arch}/root
是干净环境的路径。即在这里面就是 /var/lib/archbuild/extra-riscv64/root
。
base_packages=(base-devel)
base_packages[@]
表示将base-devel
作为 mkarchroot 的参数。这边这样写的原因是:如果我们编译的是 multilib 架构的包,那么我们需要传递的是 base-devel
和multilib-devel
。
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_config
和makepkg_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.conf
和makepkg-extra-riscv64.conf
。所以我们需要根据pacman-extra.conf
和makepkg-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.conf
和pacman-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
使用上述写法这两个是软件包是可以同时进行编译。