龙芯Arch Linux移植技巧

参与移植工作的注意事项及FAQ

Posted by wszqkzqk on August 22, 2024
本文字数:15708

需要重新构建的软件

soname变更

多数时候,如果遇到上游软件包的soname变更,必须要重新构建链接到这些库的软件包。

当开发者使用devtools/devtools-loong64构建软件包时(例如extra-loong64-build),会自动运行checkpkg来检查soname变化,例如,我们将llvm(pkgbase)从16.0.6-2升级到18.1.8-4checkpkg会输出如下信息:

......
==> No soname differences for llvm.
usr/lib/libLLVM-16.0.6.so                                     | usr/lib/libLLVM-18.so
usr/lib/libLLVM-16.so                                         <
                                                              > usr/lib/libLLVM.so.18.1
usr/lib/libLTO.so.16                                          | usr/lib/libLTO.so.18.1
usr/lib/libRemarks.so.16                                      | usr/lib/libRemarks.so.18.1
==> Sonames differ in llvm-libs!
libLLVM-16.so=libLLVM-16.so-64                                | libLLVM.so=18.1-64
libLTO.so=16-64                                               | libLTO.so=18.1-64
libRemarks.so=16-64                                           | libRemarks.so=18.1-64
  • 关注==> Sonames differ in <package>!之后列出的内容!
  • extra-*-build默认并不会保存checkpkg的输出,可以考虑事先在命令中加入2>&1 | tee all.log来保存所有输出。

其中给出了发生soname变化的软件包名llvm-libs,以及变化的soname:libLLVM.solibLTO.solibRemarks.so

我们可以在获得了变化的soname后,通过sogrep-loong64来查找链接到这些库的软件包:

  • Bash/Zsh
for lib in libLLVM.so libLTO.so libRemarks.so
do
    sogrep-loong64 -r all $lib
done | sort | uniq
  • Fish
for lib in libLLVM.so libLTO.so libRemarks.so
    sogrep-loong64 -r all $lib
end | sort | uniq

这样我们就可以找到需要重新构建的软件包列表。

考虑到一般情况下,同一软件的多个.so文件的soname变化是同时发生的,我们有时候也可以通过对软件包查找来获取所有需要重新构建的软件包:

  • Bash/Zsh
for lib in $(find-libprovides <path-to-your-pkg> | sed 's/=.*//g')
do
    sogrep-loong64 -r all $lib
done | sort | uniq
  • Fish
for lib in $(find-libprovides <path-to-your-pkg> | sed 's/=.*//g')
    sogrep-loong64 -r all $lib
end | sort | uniq
  • find-libprovides给出的是软件包提供的所有soname,包含了没有变化的soname,可能会包含很多不必要的重构
  • 很多时候还是需要手动找出需要重构的软件包:
    • 手动找到发生soname变化的.so文件
    • 使用sogrep-loong64找到链接到这些.so文件的软件包
    • 少数情况下还有其他需要重构的软件包

构建顺序

一般情况

获得了需要重新构建的软件包列表后,我们需要按照依赖关系的顺序来构建这些软件包。目前,肥猫的genrebuild脚本可以帮助我们生成构建顺序。

genrebuild <package1> <package2> ...

KDE及Qt软件包

Arch Linux官方维护有专门用于构建KDE及Qt软件包的工具kde-build,其中记录了构建这些软件包的顺序。我们需要按照这一手动维护的顺序来构建这些软件包。

一般的Bootstrap方法

在Bootsrap的过程中,往往需要在构建环境中添加一些源中没有的软件包,这可以通过makechrootpkg-I参数来实现,而在运行extra-loong64-build或者extra-loong64-build的时候,可以通过--参数来添加传递到makechrootpkg的参数。

cd <package>
extra-loong64-build -- -I <package1> -I <package2> ...

软件包的手动上传

在打包完成后,如果具有上传权限,开发者可以将软件包上传。没有处理好依赖或者没有重新构建完所有需要重新构建的软件包时不应当上传软件包,或只能上传到extra-staging或者core-staging。(一般来说没有构建完所有需要构建的包时最好什么源都不要上传,只有在问题十分复杂,需要多个开发者协作解决时才上传staging,否则请参见本文介绍的Bootstrap方法或者本地仓库的使用,先在本地解决好,再一次性上传,当软件包没有依赖和重构建问题时,可以上传到extra-testing或者core-testing。如果软件包很简单稳定,完全不需要测试,才可以上传到extra或者core。由于我们目前只跟进Arch Linux官方的extracore仓库,因此一般也不上传testing仓库。

需要注意的是,如果软件包存在需要一并上传的依赖或者需要重新构建的软件包,应当一并上传,不要遗漏

上传可以使用一些脚本来简化,例如:

#!/bin/bash

if [[ $# -lt 2 ]]; then
    echo "Usage: ${0##*/} <repo-name> <pkg-file> [option]"
    echo "Option:"
    echo "  --sign Sign the database file."
    exit 1
fi

# Set the server information "username@hostname"
TIER0SERVER=""
# Set the port of the server
PORT=""
_remote_path=/srv/http/loongarch/archlinux/

REPO=$1
PKG_PATH=$2
PKG=$(basename $2)
shift
shift

# get pkgname and version infor from $PKG
TEMP=${PKG%-*}
REL=${TEMP##*-}
TEMP2=${TEMP%-*}
VER=${TEMP2##*-}
NAME=${TEMP2%-*}

while [[ $# -gt 0 ]]; do
    case "$1" in
        --sign)
            SIGN=-s
            shift
            ;;
        *)
            shift
            ;;
    esac
done

gpg --detach-sign --use-agent $PKG_PATH
if [[ ! -e $PKG_PATH.sig ]]; then
    echo "$PKG_PATH.sig not found! Exiting..."
    exit 1
fi

rsync -e "ssh -p ${PORT}" -p '--chmod=ug=rw,o=r' -c -h -L --progress --partial -y $PKG_PATH{,.sig} $TIER0SERVER:$_remote_path/$REPO/os/loong64/
ssh -tt $TIER0SERVER -p $PORT "cd $_remote_path/$REPO/os/loong64/; flock /tmp/loong-repo-$REPO.lck repo-add $SIGN -R $REPO.db.tar.gz $PKG; curl -X POST http://127.0.0.1/op/uploong/$NAME --data-urlencode 'ver=$VER-$REL'"

然后对脚本进行修改,填入服务器信息,就可以使用这个脚本来上传软件包了:

  • Bash/Zsh
for pkg in <pkg1> <pkg2> ...
do
    loong-repo-add <repo> $pkg
done
  • Fish
for pkg in <pkg1> <pkg2> ...
    loong-repo-add <repo> $pkg
end

使用QEMU System测试

QEMU User模式下的容器没有自己的内核,显然无法用于内核测试。因此,我们需要在龙芯实体机或者QEMU System模式下进行内核测试。在实体机下的测试相对比较好理解,这里主要介绍QEMU System模式下的内核测试。

在获取或者自己构建了Loong Arch Linux的qcow2镜像后,我们可以使用qemu-system-loongarch64来启动虚拟机,例如:

qemu-system-loongarch64 \
    -m 6G \
    -cpu la464-loongarch-cpu \
    -machine virt \
    -smp 16 \
    -bios ./QEMU_EFI_9.0.fd \
    -serial stdio \
    -device virtio-gpu-pci \
    -net nic -net user \
    -device nec-usb-xhci,id=xhci,addr=0x1b \
    -device usb-tablet,id=tablet,bus=xhci.0,port=1 \
    -device usb-kbd,id=keyboard,bus=xhci.0,port=2 \
    -hda <path-to-your-image> \
    -virtfs local,path=<path-to-your-sharing-directory>,mount_tag=host0,security_model=passthrough,id=host0

其中:

  • -m 6G:分配6 GB内存
  • -smp 16:使用16个CPU核心
  • -bios ./QEMU_EFI_9.0.fd:指定QEMU使用的EFI固件
  • -hda <path-to-your-image>:指定虚拟机使用的qcow2镜像
  • -virtfs local,path=<path-to-your-sharing-directory>,mount_tag=host0,security_model=passthrough,id=host0:将宿主机的目录目录共享给虚拟机

对于需要传递给虚拟机的软件包,可以复制或者bind mount到共享目录下,供虚拟机使用。

在虚拟机中,可以使用以下命令挂载共享目录:

sudo mount -t 9p host0 <mount-point>

然后即可访问共享目录中的内容,可以使用pacman -U来安装软件包。

修复无法启动的QEMU System虚拟机

如果内核存在问题,可能会使得QEMU System虚拟机无法启动,这时候可以通过以下方法来修复:

  • 在宿主机中挂载qcow2镜像:
    • 加载nbd模块,挂载qcow2镜像:
        sudo modprobe nbd max_part=8
        sudo qemu-nbd --connect=/dev/nbd0 <path-to-your-image>
      
    • 挂载分区:
        sudo mount /dev/nbd0p2 <mount-point>
      
  • 然后可以在挂载的目录下进行修复,例如:
      sudo systemd-nspawn -aD <mount-point> --bind <path-to-your-sharing-directory>:<mount-point>
    

修复完成后,卸载分区和nbd设备:

sudo umount <mount-point>
sudo qemu-nbd --disconnect /dev/nbd0
sudo rmmod nbd

然后即可重新启动QEMU System虚拟机进行测试。

  • 需要注意的是,如果虚拟机的/etc/mkinitcpio.conf中的HOOKS中包含autodetect,则默认镜像如果在与虚拟机硬件环境不同的宿主机下生成,可能会导致缺少必要的模块而无法启动。这时候可以先使用linux-*fallback镜像启动虚拟机,然后在虚拟机中重新生成镜像。

对于需要更新config.guessconfig.sub的软件包

在构建软件包时,有时候会遇到config.guessconfig.sub过旧的问题,这时候可以给上游反馈,要求上游更新。当然,对于这样的软件包,可能是因为上游已经不再维护,或者上游不愿意更新,这时候我们需要更新config.guessconfig.sub

如果软件包的修复补丁仅包含config.guessconfig.sub的更新,不要Patch仓库中单独维护其补丁,而是在仓库的update_conifg文件中添加对应的软件包名。

Patch维护技巧:避免冲突

PKGBUILD大段删除的处理

有时候,由于某个功能整体不支持loong64,需要删除PKGBUILD中的大段代码;然而,如果这些被删除的代码在Arch Linux官方的维护中存在频繁更改,那么在以后应用loong.patch时就很可能会出现冲突。

为了避免这样的情况,我们可以将直接删除改为写成多行注释,例如,如果我们想要删除掉opencv的PKGBUILD中有关cuda的构建,我们可以在其前面插入: <<COMMENT_SEPARATOR,在其后面插入COMMENT_SEPARATOR,这样就可以在一定程度上避免上游对这个函数部分的修改导致的冲突。

  # Use a "multi-line comment" to keep patch from rotting
  : <<COMMENT_SEPARATOR
  CFLAGS="${CFLAGS} -fno-lto" CXXFLAGS="${CXXFLAGS} -fno-lto" LDFLAGS="${LDFLAGS} -fno-lto" \
  cmake -B build-cuda -S $pkgname $_opts \
      -DBUILD_WITH_DEBUG_INFO=OFF \
      -DCUDA_ARCH_BIN='52-real;53-real;60-real;61-real;62-real;70-real;72-real;75-real;80-real;86-real;87-real;89-real;90-real;90-virtual' \
      -DCUDA_ARCH_PTX='90-virtual'
  cmake --build build-cuda
COMMENT_SEPARATOR

内容插入的原则(source、哈希数组等)

此外,由于“主要矛盾”不同,语句插入的原则也发生了变化。比如,一般按照字母顺序来插入新的依赖或者新的选项,但是在这种情况下,我们可以将新的依赖或者新的选项插入到上下文最不容易被上游修改的地方,这样可以减少冲突的发生。

由于PKGBUILD本质上是一个bash文件,对于新加入的source和哈希值等数组的内容,如果要最大程度地避免上游修改带来的冲突,我们可以使用+=来添加新的元素,而不是直接修改数组的内容。

source+=(...)
sha256sums+=(...)

应用了额外Patch的包含pkgver()函数的软件包

pkgver()函数一般通过git等工具来获取软件包的版本号,然而由于环境不同,可能会导致pkgver()函数获取到的版本号(尤其是hash的位数)不同。(此时可能会存在导出的loong.patch中包含对pkgver变量的修改,这是不允许的)

为了避免这种情况,我们应当删除或者注释掉pkgver()函数,保证软件包使用的是上游的版本号。

Patch的获取

不一定所有需要Patch的软件包都需要自己手动编写Patch,有时候可以从其他地方获取Patch,例如:

此外,其他Arch Linux移植项目的Patch也可以参考,例如:

  • Modified Arch Linux packages for archriscv
    • 其中不针对于RISC-V架构的Patch可能可以直接参考使用,例如:
      • 禁用了仅适用于x86的功能
      • 禁用了仅x86下存在的依赖
      • 禁用了仅x86下存在的编译选项
    • 对于RISC-V架构的Patch,可以参考其Patch的内容,参照维护自己的Patch

某些时候,某个软件所需要的Patch可能已经出现在了某个大型软件包的子模块中,反之亦然。此时,我们也可以尝试去复用这些Patch或者作为参考。

与上游交流的注意事项

这部分内容可以参考archriscv社区的建议

首先在给社区做贡献之前,一定要优先看上游的 Code of conduct/How to contribute 等指引,尽可能的按照上游的习惯去合作。 其次和社区沟通时,尽量减少提 “某某错误是在给 loongarch-packages 做修复时出现的”,也不要用 loongarch-packages 这边的习惯做法去和上游对峙。在和上游沟通时,只需要提软件错误相关的必要信息即可。更不要不知所谓的丢个 loongarch-package 的修复链接给上游,敷衍了事的报个 bug,这样会损害整个项目的社区声誉

此外,笔者还有若干补充:

  • 某些问题并不一定与架构相关,比如上游的config.guessconfig.sub或者Cargo.lock等文件过旧,这时候提出“可能影响loong64架构的构建时“,也最好一并附上安全性考虑等理由,因为一般而言维护者更可能更关注通用的安全、性能、修复等问题,而不是一个自己不太了解的架构上的构建情况
  • 向本不支持loong64的软件的构建/配置文件中简单添加loong64支持时,考虑到上游可能根本不知道这个架构,可以附上相关介绍

PR参考示例:GitHub Google/libultrahdr PR#303

开发分支的管理要求

为了避免给loongarch-packages引入冲突,我们一般需要遵循以下原则:

  • 使用自己的fork来进行开发
  • 主分支(master)只用于同步上游的loongarch-packagesmaster分支
    • 仅用于同步,不用于开发
  • 为要修复的包单独建立以包名命名的分支
    • 派生自master分支(派生前先同步master分支)
    • 命令示例:git checkout -b <package-name>
    • 开发分支仅用于对应包的补丁提交,不用于同步

有关LoongArch64的编译器预定义宏

以下指导原则来自xen0n

关注gpr宽度是否为64,用__loongarch_grlen == 64, 关注调用约定是否为LP64系,用__loongarch_lp64

FAQ

relocation R_LARCH_B26 out of range/relocation R_LARCH_B26 overflow错误

这个错误信息一般来自链接器,它表示在处理文件时,发生了R_LARCH_B26重定位溢出错误。R_LARCH_B26是LoongArch架构的一种重定位类型,通常用于跳转指令。它要求目标地址必须在跳转指令可达的范围内(128 MB),即它只允许一定范围内的偏移量。

这个错误通常发生在编译Chromium、Firefox等大型软件包时,链接器无法找到合适的位置来放置跳转指令。

解决这个问题的方法一般为在编译参数中加入-mcmodel=medium来扩大地址空间,使得链接器可以找到合适的位置来放置跳转指令。1 2

例如,可以在PKGBUILD中的prepare()或者build()函数中加入以下内容:

prapre() {
    ......

    # Add ` -mcmodel=medium` to CFLAGS etc.
    # to avoid `relocation R_LARCH_B26 overflow`
    export CFLAGS="${CFLAGS} -mcmodel=medium"
    export CXXFLAGS="${CXXFLAGS} -mcmodel=medium"
    export RUSTFLAGS="${RUSTFLAGS} -C code-model=medium"

    ......
}

-mcmodel=medium会使得编译器使用medium模型,这样可以扩大地址空间,允许更大的跳转范围(2 GiB)。

LTO出错:换链接器还是禁用LTO?

因链接器Bug导致的LTO失败

目前的binutils版本(2.43+r4+g7999dae6961-1)存在一些Bug,可能会在链接时出现段错误等情况,尤其是在LTO时,这时候我们一般有两种选择:

  • 改用mold链接器
    • PKGBUILDprepare()函数中加入以下内容:
      export LDFLAGS="${LDFLAGS} -fuse-ld=mold"
      
    • PKGBUILDmakedepends数组中加入mold
      • 为了避免补丁应用时的冲突风险,不建议直接在原来的makedepends数组中直接添加mold
      • 建议在PKGBUILD末尾添加makedepends+=('mold')
  • 禁用LTO
    • PKGBUILD中加入options=(!lto)

一般来说,这两种方法都可以解决这一问题,但是目前推荐优先尝试不禁用LTO,仅改用mold链接器的方法:

  • 目前据笔者的观察,mold在LoongArch下稳定性更好
  • mold的性能显著更好,且对binutilsbfd的兼容性出色
  • 保留LTO可以提高软件包的性能

总结选择如下:

  1. 如果上游设置直接可行,不要作更改,直接使用上游设置
  2. 如果上游设置不可行,优先尝试mold链接器
  3. 如果mold链接器也无法解决问题,可以尝试禁用LTO

其他原因导致的LTO失败

注意,以上指引是针对链接器自身Bug的情况,如果不是这个原因,例如,存在无法访问的其他架构的内联汇编导致LTO失败,那么应当直接禁用LTO:

error: impossible constraint in ‘asm’
# Or
Error: no match insn: xxx xxx xxx

这个时候换用其他链接器是无法解决问题的。

binutils的Bug:设置-mcmodel=medium后仍然链接失败

  • 与上一小节类似,目前建议直接改用mold链接器export LDFLAGS="${LDFLAGS} -fuse-ld=mold"
  • 如果mold链接器会引入新的问题,必须使用bfd时,可以尝试以下方法

目前的binutils版本(2.43+r4+g7999dae6961-1)存在问题,relax时对指令进行了错误的优化,导致即使设置了-mcmodel=medium也会出现relocation R_LARCH_B26 out of range问题。这一问题即将修复,但是尚未发布。

如果不改用其他链接器,可以通过在LDFLAGS中加入-Wl,--no-relax来避免这一问题。

prapre() {
    ......

    # Add ` -mcmodel=medium` to CFLAGS etc.
    # to avoid `relocation R_LARCH_B26 overflow`
    export CFLAGS="${CFLAGS} -mcmodel=medium"
    export CXXFLAGS="${CXXFLAGS} -mcmodel=medium"
    export RUSTFLAGS="${RUSTFLAGS} -C code-model=medium"
    export LDFLAGS="${LDFLAGS} -Wl,--no-relax"

    ......
}

binutils修复后,应当将这一修改去除。

QEMU User特异性问题

  • 省流:在QEMU USER模式如果遇到奇怪/难以解释的问题,请尝试在QEMU System模式或者实体机上进行测试

由于QEMU User的实现问题,使用QEMU User模式构建软件包时可能会遇到一些特异性问题,目前已知的问题有:

  • 运行过于缓慢导致某些check超时报错
  • 调用pythonmultiprocessing模块的程序大概率卡死
    • 也有可能发生内存泄漏
  • go语言程序编译有一定概率卡死
  • gn在部分场景下有概率卡死并报错
    -- GN Done. Made ... targets from ... files in ...ms
    
    ......
    
    -- GN FAILED
    
    Process terminated due to timeout
    
    • 不太能总结出触发条件
    • 不过需要注意的是,如果修改gn配置的patch有误也可能会导致这个问题

(待补充)

QEMU User典型失败内容列举

  • opus构建
    • check严重超时(>50倍)
  • gimp-help构建(似乎用到了python的multiprocessing模块)
    • 内存泄漏
  • pyside6构建
    ImportError: /build/pyside6/src/build/sources/shiboken6/Shiboken.cpython-312-loongarch64-linux-gnu.so: file too short
    
  • 部分测试仅在QEMU User下失败
    • wayland
      sanity-test: ../wayland-1.23.0/tests/sanity-test.c:92: sanity_fd_leak: Assertion `fd_leak_check_enabled' failed.
      qemu: uncaught target signal 6 (Aborted) - core dumped
      Client 'sanity_fd_leak' was killed by signal 6
      Client 'sanity_fd_leak' failed
      1 child(ren) failed
      qemu: uncaught target signal 6 (Aborted) - core dumped
      test "tc_client_fd_leaks":	signal 6, pass.
      
    • vim
    • gdk-pixbuf2
    • glib2GSubprocess的测试
    • mold
      211 - loongarch64-section-order (Failed)
      
  • 部分包在QEMU下的测试构建一切正常,但仍不能用QEMU打包
    • rust在QEMU下可以正常打包并运行,但是打包出来的文件在真机下会因为页大小错误无法运行

(待补充)

pkgctl从官方clone软件包时要求输入用户名和密码

如果使用pkgctl从官方克隆软件包时要求输入用户名和密码:

==> Cloning <package-name> ...
Cloning into '<package-name>'...
Username for 'https://gitlab.archlinux.org': 

这个时候说明Arch Linux官方并不存在这一软件包仓库,一般有以下几种情况:

  • 这个软件是仅相关于Loong Arch Linux的软件包,没有由Arch Linux维护
    • 例如archlinux-lcpu-keyringdevtools-loong64
  • 未以pkgbase来克隆软件包仓库
    • 注意上游的软件包仓库名是pkgbase,而不一定pkgname
    • 同一pkgbase可能会包括多个pkgname的软件包
      • 例如rust提供了rustrust-muslrust-srcrust-wasm等软件包,这些软件包都在rust这一仓库中
  • 单纯把软件包名敲错了

我想保存/查看某一次的构建环境怎么办?

保存

默认情况下,每次运行针对相同仓库的构建命令时,devtools会自动清理上一次的构建环境。如果需要保存某一次的构建环境,可以对上一次构建环境的子卷进行快照,例如:

sudo btrfs subvolume snapshot /var/lib/archbuild/extra-loong64-build/<user-name> <path-to-your-snapshot>

如果不再需要这个快照,可以通过以下命令删除:

sudo btrfs subvolume delete <path-to-your-snapshot>

进入环境查看

可以使用systemd-nspawn进入构建环境,例如:

sudo systemd-nspawn -aD /var/lib/archbuild/extra-loong64-build/<user-name>
  • 注意:切勿进入/var/lib/archbuild/<repo-name>-loong64-build/root环境中,这是保留的干净环境,不要在这个环境中进行任何操作。如果对这个环境进行了修改,下次运行<repo-name>-loong64-build时请添加-c参数以清理环境。

这样进入环境以后的用户是root,一般我们需要切换到构建用户。Arch Linux构建环境中的构建用户统一都是builduser,可以用以下命令切换:

sudo -u builduser bash

builduser的家目录是/build,这同时也是构建环境的工作目录。其中的<pkgbase>目录就是软件包的构建目录。一般编译的中间文件都在/build/<pkgbase>/src的子目录中。

在构建环境中进行makepkg操作(不推荐)

/build/<pkgbase>/目录下并不存在PKGBUILD文件,而且原PKGBUILD中直接指定的source在这里也只有不可直接访问的软链接。因此,我们并不能够直接在这里进行makepkg的相关操作。

如果必须要在这里进行操作,可以将PKGBUILD文件复制到这里。因为一般在这个环境中进行的makepkg操作可能已经完成了编译(例如:因为直接构建时check没有通过,修改了check的逻辑,但是又不想重新构建,所以尝试在构建环境中先测试修改后的check能否通过),一般需要执行的只有check或者package部分。如果要跑check函数,可以执行:

makepkg --check

如果要打包,可以执行:

makepkg -R

这样打包生成的文件会存放在构建环境容器/srcpkgdest目录下。

然而,笔者并不推荐这种做法,笔者仍然建议按照官方的流程来运行构建命令。此外,校内具有上传权限的开发者请注意,由这样的方式得到的软件包一律禁止上传,只能用于本地的Bootstrap用途。

网络环境不稳定导致下载失败

有时候我们的网络环境不稳定,导致构建所需的源代码下载失败,而如果反复运行构建命令,又存在重新创建环境等资源开销,较为缓慢。

此时,我们可以安装pacman-contrib包,使用updpkgsums来下载源代码:

  • Bash/Zsh
    while ! updpkgsums
    done
    
  • Fish
    while not updpkgsums
    end
    

在下载完成之后,再手动检查一下PKGBUILD中的哈希是否变动,如果没有变动,再运行构建命令即可。

我为什么经常遇到(invalid or corrupted package (checksum))错误?

对于这样的错误:

:: File /var/cache/pacman/pkg/<package> is corrupted (invalid or corrupted package (checksum)).                                                                                                                              
Do you want to delete it? [Y/n]

这表示的是软件包的校验和不匹配,一般来说重新运行命令,尝试重新下载软件包即可解决。

对于架构为any的包, 用户自行在x86下载的更新包与龙芯的包可能同名但是构建环境与签名者不同,很可能会出现这个错误。

如果不愿意被重试困扰,可以在运行的构建命令中向makechrootpkg传递-d参数,为构建环境指定不同的缓存目录,例如:

mkdir ~/loong64-cache
extra-loong64-build -- -d ~/loong64-cache:/var/cache/pacman/pkg/ -- -A
  • 这一方法可以避免在构建子环境中可能遇到的冲突问题,却不能避免干净chroot模板环境在构建前的升级过程中可能遇到的冲突问题
    • 因为-d参数只会传递给从模板环境(root子卷)新建的构建子环境,而不会传递给模板环境本身
  • 不过干净chroot模板环境中仅存在base-devel及其依赖包,其中的包升级不那么频繁,因此这一问题的发生概率较低

如何指定sogrep-loong64的镜像站

devtools-loong641.2.1.patch9-1版本开始,archbuild默认使用/etc/pacman.d/mirrorlist-loong64这一镜像列表。在loong64上,由发行版的默认镜像列表软件包pacman-mirrorlist-loong64提供,在其他架构上,由devtools-loong64本身提供。

然而,sogrep-loong64工具本身不会读取mirrorlist-loong64文件,而是读取环境变量SOLINKS_MIRROR来获取镜像站。如果需要指定镜像站,可以在运行命令时指定环境变量,例如:

SOLINKS_MIRROR=https://loongarchlinux.lcpu.dev/loongarch/archlinux sogrep-loong64 <repo> <lib>

如何指定构建环境的镜像站

构建环境会自动读取宿主的镜像站配置并写入到构建环境的/etc/pacman.d/mirrorlist中。然而,我们真正使用的mirrorlist/etc/pacman.d/mirrorlist-loong64,这一文件不会从宿主环境中读取。如果我们想要修改,可以在模板环境中修改/etc/pacman.d/mirrorlist-loong64。(但是注意不应该对模板环境进行任何污染,确保模板环境是干净的)

有时候,如果嫌镜像站同步过慢影响开发,可以将其设置为CacheServer

CacheServer = https://mirrors.pku.edu.cn/loongarch-lcpu/archlinux/$repo/os/$arch
Server = https://loongarchlinux.lcpu.dev/loongarch/archlinux/$repo/os/$arch
Server = https://mirrors.pku.edu.cn/loongarch-lcpu/archlinux/$repo/os/$arch

这样会优先从第一个Server条目,也就是原始的Tier0镜像站获取仓库元数据,并优先从CacheServer获取软件包,保证了下载速度和软件包的新鲜度。

LTO提示磁盘空间不足:lto: fatal error: write: No space left on device

  • 该方法已失效!

参考自archriscv wiki

很有可能不是真的吃满了,是因为 devtools 使用了 systemd-nspawn,而后者默认用参数 size=10%挂载在 /tmp 目录上。

可以尝试调整 SYSTEMD_NSPAWN_TMPFS_TMP 这个变量的值来拒绝挂载 tmpfs

sudo SYSTEMD_NSPAWN_TMPFS_TMP=0 extra-loong64-build -- -- -A

记得需要加上 sudo 用 root 跑,不然 devtools 自己 sudo 了之后,这个环境变量就没了。

如何从GitHub的PR/Commit中获取Patch

GitHub的PR/Commit页面提供了diffpatch的下载功能,在对应的PR/Commit页面下,只需要在PR或者Commit号后面加上.patch或者.diff即可跳转到对应的Patch页面,该Patch可以直接放到PKGBUILDsource中,但是建议用::分隔来指定Patch的名字。(要求Patch文件名需要有实际意义)

上游已合并但未发布的Commit/未合并的PR导出的Patch在source中优先写链接还是写本地Patch文件

很多时候我们使用的Patch可能是已经合并但未发布的Commit,或者是未合并的PR导出的Patch。这些Patch已经可以从上游的链接中获取。为了简化我们的补丁集内容,并且增加Patch的可查验性,便于追踪上游及PR提出者的更新,我们一般按照以下原则来指定Patch的来源:

  1. 如果上游已经存在相关Commit,且软件本身使用git仓库进行构建,优先使用git cherry-pick -n <commit-hash>应用补丁
    • 如果一个PR多个Commit且上游合并的时候没有squash,可以直接应用merge commit,但是需要加上-m 1参数
  2. 上游尚未存在相关Commit,或者本身使用tarball构建,并非git仓库,优先在source中添加指向上游Patch的链接
  3. 相关PR变动过于频繁,以上两种情况均不可行时,才考虑将Patch文件拉到本地并放入source

更多阅读材料