交叉編譯工具打包準則

出自 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 遞歸地調用自身)。

另請參閱[編輯 | 編輯原始碼]