交叉编译工具包指南
本页面描述了如何为交叉编译器工具链创建软件包。另一种交叉编译的方法是使用 distcc 在混合架构上进行。请参阅 Distcc#使用 distcc 进行交叉编译。
重要提示
本页面描述了新的方法,其灵感来源于以下软件包
- 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 涵盖了构建交叉编译器所需的步骤,并提到了相对最新的依赖项版本。
构建交叉编译器
构建交叉编译器的通用方法是
- binutils:构建一个交叉 binutils,用于链接和处理目标架构
- 头文件:安装一套目标架构的 C 库和内核头文件
- 使用 linux-api-headers 作为参考,并将
ARCH=target-architecture传递给 make - 创建 libc 头文件包(Glibc 的过程在此 处描述)
- 使用 linux-api-headers 作为参考,并将
- gcc-stage-1:构建一个基础(stage 1)的 gcc 交叉编译器。它将用于编译 C 库。由于它无法链接到它没有的 C 库,因此它几乎无法构建任何其他东西。
- libc:构建交叉编译的 C 库(使用 stage 1 交叉编译器)。
- gcc-stage-2:构建一个完整的(stage 2)C 交叉编译器
头文件和 libc 的来源因平台而异。
--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}
}
方法与原因
为什么不安装到 /opt
两个原因
- 首先,根据《文件系统标准》,这些文件就属于
/usr。就这样。 - 其次,安装到
/opt是在没有其他选择时的最后手段。
“不在路径中的可执行文件”是什么意思?
这个奇怪的技巧可以简化交叉编译。有时,项目的 Makefiles 不使用 CC 等变量,而是直接使用 gcc。如果您只想尝试交叉编译这样的项目,编辑 Makefile 可能会非常耗时。然而,更改 $PATH 以优先使用“我们的”可执行文件是一个非常快速的解决方案。然后您将运行 PATH=/usr/arch/bin/:$PATH make 而不是 make。
故障排除
编译失败但没有明确信息怎么办?
对于运行 configure 时发生的错误,请阅读 $srcdir/pkgname-build/config.log。对于编译时发生的错误,请向上滚动控制台日志或搜索“error”。
这个错误 [error message] 意味着什么?
很可能您犯了一些非明显的错误
- 配置标志过多或过少。尝试使用已证明有效的标志集。
- 依赖项已损坏。例如,错放或丢失的 binutils 文件可能导致 gcc 配置期间出现模糊的错误。
- 您未在
build()函数中添加export CFLAGS=""(参见 GCC Bugzilla 中的 bug 25672)。 - 某些
--prefix/--with-sysroot组合可能需要目录是可写的(clfs 指南中未明确说明)。 - sysroot 尚未包含内核/libc 头文件。
- 如果谷歌搜索无果,请立即放弃当前配置,尝试更稳定/经过验证的配置。
为什么文件会被安装到错误的位置?
各种运行通用 make install 行的方法会导致不同的结果。例如,某些 make 目标可能不支持 DESTDIR,而需要使用 install_root。tooldir、prefix 和其他类似参数也一样。有时以参数形式提供参数而不是环境变量,例如
./configure CC=arm-elf-gcc
而不是
CC=arm-elf-gcc ./configure
反之亦然,可能会导致不同的结果(通常由 configure/make 的递归自我调用引起)。