交叉编译工具包指南

来自 ArchWiki
Arch 软件包指南

32 位CLRCMake交叉DKMSEclipseElectron字体Free PascalGNOMEGoHaskellJavaKDE内核模块LispMesonMinGWNode.js非自由软件OCamlPerlPHPPythonRRubyRust - 安全ShellVCSWebWine

本页面描述了如何为交叉编译器工具链创建软件包。另一种交叉编译方法是在混合架构上使用 distcc。请参阅Distcc#使用 distcc 进行交叉编译

提示: 作为创建交叉编译器软件包的替代方案,您可以使用 crosstool-ng 并以完全自动化的方式创建您自己的工具链。crosstool-ng 可以在 crosstool-ng 上找到。

重要提示

本页面描述了新的做事方式,灵感来自以下软件包

  • mingw-w64-gccmingw-w64-* 系列的其他软件包
  • arm-none-eabi-gccarm-none-eabi-* 系列的其他软件包
  • arm-wince-cegcc-* 系列的其他软件包

版本兼容性

警告: 使用不兼容版本的软件包进行工具链编译将导致不可避免的失败。默认情况下,认为所有版本都不兼容。

以下策略允许您选择兼容版本的 gcc、binutils、内核和 C 库

  • 通用规则
    • gcc 和 binutils 版本之间存在关联,请同时使用发布的版本;
    • 最好使用最新的内核头文件来编译 libc,但使用 --enable-kernel 开关(glibc 特有,其他 C 库可能使用不同的约定)来强制在旧内核上工作;
  • 官方仓库:您可能需要应用额外的修复和 hack,但 Arch Linux(或其特定于架构的分支)使用的版本最有可能可以协同工作;
  • 软件文档:所有 GNU 软件都有 READMENEWS 文件,记录了诸如依赖项的最低要求版本之类的内容;
  • 其他发行版:它们也进行交叉编译
  • https://trac.clfs.org 涵盖了构建交叉编译器所需的步骤,并提到了依赖项的最新版本。

构建交叉编译器

构建交叉编译器的一般方法是

  1. binutils:构建交叉 binutils,它为目标架构链接和处理
  2. headers:为目标架构安装一组 C 库和内核头文件
    1. 使用 linux-api-headers 作为参考,并将 ARCH=目标架构 传递给 make
    2. 创建 libc 头文件软件包(Glibc 的处理过程在此处描述链接
  3. gcc-stage-1:构建基本的(stage 1)gcc 交叉编译器。这将用于编译 C 库。它几乎无法构建任何其他东西(因为它无法链接到它没有的 C 库)。
  4. libc:构建交叉编译的 C 库(使用 stage 1 交叉编译器)。
  5. gcc-stage-2:构建完整的(stage 2)C 交叉编译器

头文件和 libc 的来源将因平台而异。

提示: 确切的步骤差异很大,具体取决于您的需求。例如,如果您想创建与 Arch Linux 系统“克隆”版本相同的内核和 glibc,您可以跳过构建头文件并将 --with-build-sysroot=/ 传递给 configure

软件包命名

软件包名称不应cross- 一词作为前缀(之前曾提出过,但在官方软件包中未被采用,可能是由于名称长度增加),并且应由软件包名称组成,前缀为GNU 三元组,不带供应商字段或供应商字段中带有“unknown”;例如:arm-linux-gnueabihf-gcc。如果存在较短的命名约定(例如 mips-gcc),则可以使用,但不建议这样做。

文件放置

最新版本的 gcc 和 binutils 对 sysroot 和库使用非冲突路径。可执行文件应放置在 /usr/bin/ 中,为防止此处发生冲突,请为所有可执行文件添加架构名称前缀。

通常,./configure 至少应具有以下参数

_target=your_target
_sysroot=/usr/lib/${_target}
...
./configure \
    --prefix=${_sysroot} \
    --sysroot=${_sysroot} \
    --bindir=/usr/bin

其中 your_target 可以是,例如,“i686-pc-mingw32”。

示例

这是 MinGW 的 binutils 的 PKGBUILD。值得注意的是

  • 指定交叉环境的根目录
  • 使用 ${_pkgname} ${_target} ${_sysroot} 变量使代码更具可读性
  • 删除重复/冲突的文件
# Maintainer: Allan McRae <allan@archlinux.org>

# cross toolchain build order: binutils, headers, gcc (pass 1), w32api, mingwrt, gcc (pass 2)

_target=i686-pc-mingw32
_sysroot=/usr/lib/${_target}

pkgname=${_target}-binutils
_pkgname=binutils
pkgver=2.19.1
pkgrel=1
pkgdesc="MinGW Windows binutils"
arch=('i686' 'x86_64')
url="https://gnu.ac.cn/software/binutils/"
license=('GPL')
depends=('glibc>=2.10.1' 'zlib')
options=('!libtool' '!distcc' '!ccache')
source=(http://ftp.gnu.org/gnu/${_pkgname}/${_pkgname}-${pkgver}.tar.bz2)
md5sums=('09a8c5821a2dfdbb20665bc0bd680791')

build() {
  cd ${_pkgname}-${pkgver}
  mkdir binutils-build && cd binutils-build

  ../configure --prefix=${_sysroot} --bindir=/usr/bin \
    --with-sysroot=${_sysroot} \
    --build=$CHOST --host=$CHOST --target=${_target} \
    --with-gcc --with-gnu-as --with-gnu-ld \
    --enable-shared --without-included-gettext \
    --disable-nls --disable-debug --disable-win32-registry
  make
  make DESTDIR=${pkgdir}/ install
  
  # clean-up cross compiler root
  rm -r ${pkgdir}/${_sysroot}/{info,man}
}
注意: 在构建交叉工具链期间,始终从专用目录(所谓的树外编译)执行 configuremake 命令,并在 PKGBUILD 中进行任何细微更改后删除整个 src 目录。

方法和原因

为什么不安装到 /opt 中

两个原因

  1. 首先,根据文件系统层次结构标准,这些文件就应该属于 /usr 下的某个位置。句号。
  2. 其次,安装到 /opt 是在没有其他选择时的最后措施。

什么是“路径外可执行文件”?

这种奇怪的方法可以更轻松地进行交叉编译。有时,项目 Makefile 不使用 CC 和 co. 变量,而是直接使用 gcc。如果您只想尝试交叉编译这样的项目,则编辑 Makefile 可能是一项非常耗时的操作。但是,更改 $PATH 以首先使用“我们”的可执行文件是一个非常快速的解决方案。然后,您将运行 PATH=/usr/arch/bin/:$PATH make 而不是 make

故障排除

如果编译失败且没有明确的消息怎么办?

对于在运行 configure 期间发生的错误,请阅读 $srcdir/pkgname-build/config.log。对于在编译期间发生的错误,请向上滚动控制台日志或搜索单词“error”。

这个错误 [错误消息] 是什么意思?

很可能您犯了一些不明显的错误

  • 配置标志过多或过少。尝试使用已经验证过的标志集。
  • 依赖项已损坏。例如,错放或丢失的 binutils 文件可能会导致 gcc 配置期间出现神秘错误。
  • 您没有将 export CFLAGS="" 添加到您的 build() 函数中(请参阅 GCC Bugzilla 中的 bug 25672)。
  • 某些 --prefix/--with-sysroot 组合可能需要目录可写(从 clfs 指南中不明显)。
  • sysroot 尚不具有内核/libc 头文件。
  • 如果谷歌搜索没有帮助,请立即放弃当前配置并尝试更稳定/经过验证的配置。

为什么文件会被安装在错误的位置?

运行通用 make install 行的各种方法会导致不同的结果。例如,某些 make 目标可能不提供 DESTDIR 支持,而是需要使用 install_roottooldirprefix 和其他类似参数也是如此。有时,将参数作为参数而不是环境变量提供,例如

./configure CC=arm-elf-gcc

代替

CC=arm-elf-gcc ./configure

反之亦然可能会导致不同的结果(通常是由 configure/make 的递归自调用引起的)。

参见