交叉编译工具打包准则

来自 Arch Linux 中文维基
Arch 打包准则

32 位CLRCMakeCrossDKMSEclipseElectronFontFree PascalGNOMEGoHaskellJavaKDEKernelLispMesonMinGWNode.jsNonfreeOCamlPerlPHPPythonRRubyRustVCSWebWine

本页描述了如何打包交叉编译器工具链。另一种交叉编译的方法是在多种架构上使用 distcc。参见 Distcc#使用 distcc 交叉编译

提示:打包交叉编译器还可使用 crosstool-ng,以完全自动化的方式创建自己的工具链。详情请见 crosstool-ng

重要提示[编辑 | 编辑源代码]

受以下软件包启发,本文介绍新的打包方法:

  • mingw-w64-gcc 以及 mingw-w64-* 系列的其他软件包
  • arm-none-eabi-gcc 以及 arm-none-eabi-* 系列的其他软件包
  • arm-wince-cegcc-* 系列的其他软件包

版本兼容性[编辑 | 编辑源代码]

警告: 使用不兼容版本的软件包编译工具链必然会失败。一般来说,不同版本之间都不兼容。

建议按照以下策略选择 gcc、binutils、内核和 C 库的兼容版本:

  • 总则:
    • gcc 和 binutils 的版本相关,建议使用同时发布的版本;
    • 建议使用最新的内核头文件来编译 libc,但使用 --enable-kernel(只保证适用于 glibc,其他 C 库可能约定不同)能强制在旧内核上工作;
  • 官方仓库:可能需要额外的修正,但 Arch Linux(或其特定架构的分支)使用的版本很可能可以协同工作;
  • 软件文档:所有 GNU 软件都有 READMENEWS 文件,涵盖了依赖关系的最低版本要求等内容;
  • 其他发行版:同样也进行交叉编译
  • https://trac.clfs.org 涵盖了构建交叉编译器的必要步骤以及一些依赖的最新版本。

构建交叉编译器[编辑 | 编辑源代码]

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

  1. binutils:构建为目标架构链接、处理的 cross-binutils。
  2. 头文件:安装目标架构的 C 库和内核头文件。
    1. 参考 linux-api-headers,并将 ARCH=target-architecture 参数传给 make
    2. 打包 libc 头文件 (此处描述了 Glibc 的处理方法)
  3. gcc 第 1 阶段:构建基本的(第 1 阶段)gcc 交叉编译器。这将被用来编译 C 库,但是几乎不能编译其他任何东西(因为无法链接不存在的 C 库)。
  4. libc:构建交叉编译的 C 库(使用第 1 阶段的交叉编译器)。
  5. gcc 第 2 阶段:构建完整的(第 2 阶段)C 交叉编译器。

头文件和 libc 的源代码因平台而异。

提示:根据需求的不同,具体操作步骤也不尽相同。例如,如果想创建内核和 glibc 版本与 Arch Linux 系统相同的 "克隆版",可不构建头文件直接将 --with-build-sysroot=/ 传给 configure

软件包命名[编辑 | 编辑源代码]

软件包名称应以 cross- 开头(之前建议使用前缀 cross-,但可能由于包名太长,在正式的软件包中未被采用),而应由软件包名称组成,前缀为 GNU triplet,不含厂商字段或在厂商字段中含 "unknown"。例如:arm-linux-gnueabihf-gcc。如果存在更短的命名规则(例如:mips-gcc),可以使用但并不建议。

放置文件[编辑 | 编辑源代码]

最新版本的 gcc 和 binutils 对系统根目录和库使用不冲突的路径。可执行文件应放在 /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="http://www.gnu.org/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 ${srcdir}/${_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. 首先,根据文件系统层次结构标准 (FHS),这些文件只位于 /usr 的某个位置。
  2. 其次,安装到 /opt 是退而求其次的选择。

"路径外的可执行文件 (out-of-path executables)" 是什么?[编辑 | 编辑源代码]

这看起来很奇怪,但能让交叉编译更容易。有时项目的 Makefile 不使用 CC 或其他变量,而是直接使用 gcc 。在尝试交叉编译这样的项目时,编辑 Makefile 可能会很麻烦。然而,将 $PATH 改为优先使用我们的可执行文件即可解决此问题,只需将 make 改为执行 PATH=/usr/arch/bin/:$PATH make

故障排除[编辑 | 编辑源代码]

编译失败但没有明确的提示应该如何解决?[编辑 | 编辑源代码]

如果是在运行 configure 时发生的错误,参见 $srcdir/pkgname -build/config.log。如果是在编译过程中发生的错误,请向上滚动控制台日志或搜索 "error" 一词。

[error message] 错误意味着什么?[编辑 | 编辑源代码]

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

  • 配置标志位过多或过少。尝试使用已证明有效的标志位。
  • 依赖关系被破坏。例如,binutils 文件放错位置或丢失,可能导致 gcc 配置过程中出现晦涩难懂的错误信息。
  • 未在 build() 函数中添加 export CFLAGS=""(参见 GCC Bugzilla 中的 bug 25672)。
  • 某些 --prefix--with-sysroot 参数组合可能要求目录可写。
  • 系统根目录缺少内核头文件或 libc 头文件。
  • 如果通过搜索引擎仍无法解决,建议立刻放弃当前配置,尝试更稳定、更成熟的配置。

为什么文件安装位置会不正确?[编辑 | 编辑源代码]

执行 make install 命令的各种方法会产生不同的结果。例如,有些 make 目标可能不提供 DESTDIR 支持,而是要求使用install_root。对于 tooldirprefix 和其他类似参数也是如此。有时提供参数而不是环境变量,例如

./configure CC=arm-elf-gcc

而不是

CC=arm-elf-gcc ./configure

反之亦然,可能会导致不同的结果(通常是因为 configure/make 递归地调用自身)。

另请参阅[编辑 | 编辑源代码]