交叉编译工具打包准则 - Arch Linux 中文维基

跳转到内容

# 交叉编译工具打包准则

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

32 位 – 安全 – CLR – CMake – DKMS – Eclipse – Electron – Free Pascal – GNOME – Go – Haskell – Java – 交叉编译工具 – KDE – Lisp – Meson – MinGW – 内核模块 – Node.js – Nonfree – OCaml – Perl – PHP – Python – R – Ruby – Rust – Shell – VCS – Web – Wine – 字体

翻译状态：

- 本文（或部分内容）译自 Cross-compiling tools package guidelines，最近一次同步于 2023-05-28，若英文版本有所更改，则您可以帮助同步与翻译更改的内容。
- 您可以在 ArchWiki 的对应页面找到本文翻译的原始修订历史。
- 本文可能与英文原文存在出入。

本页描述了如何打包交叉编译器工具链。另一种交叉编译的方法是在多种架构上使用 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 软件都有 `README` 和 `NEWS` 文件，涵盖了依赖关系的最低版本要求等内容；
- 其他发行版：同样也进行交叉编译
- 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}
    }

注意：在交叉编译工具链构建过程中，每次都从独立的目录中执行 `configure` 和 make 命令（所谓的树外编译），并在 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`。对于 `tooldir`、`prefix` 和其他类似参数也是如此。有时提供参数而不是环境变量，例如

    ./configure CC=arm-elf-gcc

而不是

    CC=arm-elf-gcc ./configure

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

## 另请参阅

- https://wiki.osdev.org/GCC_Cross-Compiler (English)

分类：​

- Arch 打包准则

交叉编译工具打包准则
添加话题