交叉編譯工具打包準則
32 位 – CLR – CMake – Cross – DKMS – Eclipse – Electron – Font – Free Pascal – GNOME – Go – Haskell – Java – KDE – Kernel – 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 遞歸地調用自身)。