交叉编译工具打包准则
32 位 – CLR – CMake – Cross – DKMS – Eclipse – Electron – Font – Free Pascal – GNOME – Go – Haskell – Java – KDE – 内核模块 – Lisp – Meson – MinGW – Node.js – Nonfree – OCaml – Perl – PHP – Python – R – Ruby – Rust – VCS – Web – Wine
本页描述了如何打包交叉编译器工具链。另一种交叉编译的方法是在多种架构上使用 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:构建为目标架构链接、处理的 cross-binutils。
- 头文件:安装目标架构的 C 库和内核头文件。
- 参考 linux-api-headers包,并将
ARCH=target-architecture
参数传给 make - 打包 libc 头文件 (此处描述了 Glibc 的处理方法)
- 参考 linux-api-headers包,并将
- gcc 第 1 阶段:构建基本的(第 1 阶段)gcc 交叉编译器。这将被用来编译 C 库,但是几乎不能编译其他任何东西(因为无法链接不存在的 C 库)。
- libc:构建交叉编译的 C 库(使用第 1 阶段的交叉编译器)。
- gcc 第 2 阶段:构建完整的(第 2 阶段)C 交叉编译器。
头文件和 libc 的源代码因平台而异。
--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} }
疑难解答[编辑 | 编辑源代码]
为什么不安装到 /opt?[编辑 | 编辑源代码]
有以下两个原因:
- 首先,根据文件系统层次结构标准 (FHS),这些文件只位于
/usr
的某个位置。 - 其次,安装到
/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 递归地调用自身)。