crosstool-NG
Toolchain, 就像他的名字一樣, 就是一堆 tools 將彼此的 input 和 output 串起來, 最終產生該平台的 binary
說起來簡單, 但實際上到底有哪些東西呢?
詳細內容可以參考 crosstool-NG 文章, 這邊僅簡單敘述
下面的每個工具的 output, 都會是下一個工具的 input
換句話說, 較後面的工具會 depends 前一個工具, 最終變成一大串肉粽
也就是 toolchain 所需要的 cross compiler
從 2-pass compiler 開始就是 platform-dependent 了
總而言之, 為了達成 cross compile 的目的
我們需要釐清這串肉粽的依賴鏈, 才能知道不同平台需要哪些工具, 而這些工具又 depends 哪些工具 (好繞口...)
詳細如何 build 出 cross compiler 請見 此文章
好在這些事情已經有人幫我們處理了, 就是今天 demo 會使用的 crosstool-NG!
crosstool-NG
提供了很多平台的 config 檔 (下面會介紹)
讓我們根據這些 config 檔 build 出不同平台的 cross toolchain
下面會用 x86_64-ubuntu16.04-linux-gnu
作為範例
從安裝 crosstool-NG
開始到最後 build 出 toolchain 完整操作一遍!
crosstool-NG
詳細安裝步驟請見 官方文件
crosstool-ng
, 這邊我們下載 txz 版本wget http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.25.0.tar.xz
tar xf crosstool-ng-1.25.0.tar.xz
gperf
, bison
, help2man
, libtool-bin
, libtool-doc
, flex
, texinfo
才能正常設定apt-get install -y \
libtool-bin \
libtool-doc \
help2man \
gperf \
bison \
flex \
texinfo \
gawk
cd crosstool-ng-1.25.0
./configure --prefix=/usr/local
make && sudo make install
ct-ng
來設定 toolchain package 啦!!!ct-ng --version
我們可以設定
有兩種方法: GUI (Linux-kernel style) 和 CLI
可以用 ct-ng menuconfig
來叫出 gui 來設定, 清楚明瞭
這種方法適合想要客製化 toolchain config 的人
不過因為我們是用 Colab 環境, 比較不方便用 GUI, 這邊就略過不介紹了
所以我們會用第二種方法: 從 CLI 設定
crosstool-ng
提供了很~多 toolchain 的 config samples 在 samples/
底下, 我們可以用 CLI 看
$ ct-ng list-samples
...
[G..X] tic6x-uclinux
[G...] x86_64-centos6-linux-gnu
[G...] x86_64-centos7-linux-gnu
[G...] x86_64-multilib-linux-gnu
[G..X] x86_64-multilib-linux-musl
[G...] x86_64-multilib-linux-uclibc
[G..X] x86_64-w64-mingw32,x86_64-pc-linux-gnu
[G...] x86_64-ubuntu14.04-linux-gnu
[G...] x86_64-ubuntu16.04-linux-gnu
[G...] x86_64-unknown-linux-gnu
[G...] x86_64-unknown-linux-uclibc
[G..X] x86_64-w64-mingw32
[G..X] xtensa-fsf-elf
[G...] xtensa-fsf-linux-uclibc
L (Local) : sample was found in current directory
G (Global) : sample was installed with crosstool-NG
X (EXPERIMENTAL): sample may use EXPERIMENTAL features
B (BROKEN) : sample is currently broken
O (OBSOLETE) : sample needs to be upgraded
在各個 toolchain folder 底下都會有 crosstool.config
config 檔
我們將想要 cross compile 的目標 config 複製為 .config
並存到當前的路徑底下
這邊以 x86_64-ubuntu16.04-linux-gnu
為例 (x86_64-ubuntu16.04-linux-gnu
稱為 target tripe, 長相如下<arch>[<endian>][-<vender>]-<kernel>[-<os>]
)
cp samples/x86_64-ubuntu16.04-linux-gnu/crosstool.config .config
再用 yes "" | ct-ng oldconfig
進行設定 (這裡我們用 yes
直接套用所有默認的設定)
設定完成後, 我們可以用 ct-ng show-config
確認剛剛環境是否設定成功
如果成功的話, 應該要看到我們剛剛選擇的環境設定
$ ct-ng show-config
[l...] x86_64-ubuntu16.04-linux-gnu
Languages : C,C++
OS : linux-4.4.302
Binutils : binutils-2.38
Compiler : gcc-11.2.0
C library : glibc-2.23
Debug tools :
Companion libs : gettext-0.21 gmp-6.2.1 isl-0.24 libiconv-1.16 mpc-1.2.1 mpfr-4.1.0 ncurses-6.2 zlib-1.2.12
Companion tools : autoconf-2.71 automake-1.16.1
這樣就設定成功啦!
先確認 toolchain 需要的 dependencies 是否能正常下載, 沒問題後再開始 build toolchain
ct-ng source
:::warning
目前在下載 zlib
時存在已知問題: crosstool-ng#1337
Workaround 是我們需要手動去下載 toolchain 需要的 tarball
wget https://zlib.net/fossils/zlib-1.2.12.tar.gz
cp zlib-1.2.12.tar.gz .build/tarballs/
之後就可以開始 build toolchain 了!
:::
:::warning
因為我們是用 Colab, 需要額外一些設定
root
.config
, 加入以下幾個設定CT_EXPERIMENTAL=y
CT_ALLOW_BUILD_AS_ROOT=y
CT_ALLOW_BUILD_AS_ROOT_SURE=y
printf 'CT_EXPERIMENTAL=y\nCT_ALLOW_BUILD_AS_ROOT=y\nCT_ALLOW_BUILD_AS_ROOT_SURE=y' >> .config
LD_LIBRARY_PATH
和 LIBRARY_PATH
export LD_LIBRARY_PATH=
export LIBRARY_PATH
import os
if 'LD_LIBRARY_PATH' in os.environ:
del os.environ['LD_LIBRARY_PATH']
if 'LIBRARY_PATH' in os.environ:
del os.environ['LIBRARY_PATH']
:::
處理完必要的設定後, 就可以開始 build toolchain 啦!
ct-ng build
我們可以從以下部分 output 看出 ct-ng 幫我們 build 了哪些 tools
因為是整條 toolchain 都要 build, 所以需要很多時間
[INFO ] Performing some trivial sanity checks
[INFO ] Build started 20230927.124446
[INFO ] Building environment variables
[WARN ] Directory '/root/src' does not exist.
[WARN ] Will not save downloaded tarballs to local storage.
[EXTRA] Preparing working directories
[EXTRA] Installing user-supplied crosstool-NG configuration
[EXTRA] =================================================================
[EXTRA] Dumping internal crosstool-NG configuration
[EXTRA] Building a toolchain for:
[EXTRA] build = x86_64-pc-linux-gnu
[EXTRA] host = x86_64-pc-linux-gnu
[EXTRA] target = x86_64-ubuntu16.04-linux-gnu
[EXTRA] Dumping internal crosstool-NG configuration: done in 0.12s (at 00:01)
[INFO ] =================================================================
[INFO ] Retrieving needed toolchain components' tarballs
[EXTRA] Retrieving 'linux-4.4.302'
[EXTRA] Verifying SHA512 checksum for 'linux-4.4.302.tar.xz'
[EXTRA] Retrieving 'ncurses-6.2'
[EXTRA] Verifying SHA512 checksum for 'ncurses-6.2.tar.gz'
[EXTRA] Retrieving 'libiconv-1.16'
[EXTRA] Verifying SHA512 checksum for 'libiconv-1.16.tar.gz'
[EXTRA] Retrieving 'gettext-0.21'
[EXTRA] Verifying SHA512 checksum for 'gettext-0.21.tar.xz'
[EXTRA] Retrieving 'glibc-2.23'
[EXTRA] Verifying SHA512 checksum for 'glibc-2.23.tar.xz'
[INFO ] Retrieving needed toolchain components' tarballs: done in 7.22s (at 00:09)
[INFO ] =================================================================
[INFO ] Extracting and patching toolchain components
[EXTRA] Extracting linux-4.4.302
[EXTRA] Patching linux-4.4.302
[EXTRA] Extracting ncurses-6.2
[EXTRA] Patching ncurses-6.2
[EXTRA] Extracting libiconv-1.16
[EXTRA] Patching libiconv-1.16
[EXTRA] Extracting gettext-0.21
[EXTRA] Patching gettext-0.21
[EXTRA] Extracting glibc-2.23
[EXTRA] Patching glibc-2.23
[INFO ] Extracting and patching toolchain components: done in 35.60s (at 00:44)
[INFO ] =================================================================
[INFO ] Installing ncurses for build
[EXTRA] Configuring ncurses
[EXTRA] Building ncurses
[EXTRA] Installing ncurses
[INFO ] Installing ncurses for build: done in 48.22s (at 01:33)
[INFO ] =================================================================
[INFO ] Installing zlib for host
[EXTRA] Configuring zlib
[EXTRA] Building zlib
[EXTRA] Installing zlib
[INFO ] Installing zlib for host: done in 11.21s (at 01:44)
[INFO ] =================================================================
[INFO ] Installing GMP for host
[EXTRA] Configuring GMP
[EXTRA] Building GMP
[EXTRA] Installing GMP
[INFO ] Installing GMP for host: done in 83.08s (at 03:07)
[INFO ] =================================================================
[INFO ] Installing MPFR for host
[EXTRA] Configuring MPFR
[EXTRA] Building MPFR
[EXTRA] Installing MPFR
[INFO ] Installing MPFR for host: done in 56.22s (at 04:03)
[INFO ] =================================================================
[INFO ] Installing ISL for host
[EXTRA] Configuring ISL
[EXTRA] Building ISL
[EXTRA] Installing ISL
[INFO ] Installing ISL for host: done in 85.82s (at 05:29)
[INFO ] =================================================================
[INFO ] Installing MPC for host
[EXTRA] Configuring MPC
[EXTRA] Building MPC
[EXTRA] Installing MPC
build 完後就可以在 ~/x-tools
底下看到我們 Linux 的 toolchain x86_64-ubuntu16.04-linux-gnu
了🎉🎉🎉
從上圖可以看到, 我們的 toolchain folder x86_64-ubuntu16.04-linux-gnu
底下還有另外一個相同名稱的 folder, 這兩個有什麼區別呢?
從這一層開始就是 cross compile 會用到的地方了
這一層又叫做 Toolchain Directory, 可以看作是當前系統和目標系統的中介 (cross build)
ls -lh ~/x-tools/x86_64-ubuntu16.04-linux-gnu
total 808K
dr-xr-xr-x 2 root root 4.0K Sep 27 14:10 bin/
-r--r--r-- 1 root root 784K Sep 27 14:10 build.log.bz2
dr-xr-xr-x 2 root root 4.0K Sep 27 14:09 include/
dr-xr-xr-x 4 root root 4.0K Sep 27 14:09 lib/
dr-xr-xr-x 3 root root 4.0K Sep 27 14:09 libexec/
dr-xr-xr-x 4 root root 4.0K Sep 27 14:10 share/
dr-xr-xr-x 8 root root 4.0K Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu/
bin
包含了產生目標系統 binary 所需要的 cross toolchain
ls -lh ~/x-tools/x86_64-ubuntu16.04-linux-gnu/bin
total 60M
-r-xr-xr-x 1 root root 1.3M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-addr2line*
-r-xr-xr-x 2 root root 1.3M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-ar*
-r-xr-xr-x 2 root root 2.1M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-as*
-r-xr-xr-x 2 root root 1.2M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-c++*
lrwxrwxrwx 1 root root 32 Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-cc -> x86_64-ubuntu16.04-linux-gnu-gcc*
-r-xr-xr-x 1 root root 1.3M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-c++filt*
-r-xr-xr-x 1 root root 1.2M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-cpp*
-r-xr-xr-x 1 root root 5.1K Sep 27 12:44 x86_64-ubuntu16.04-linux-gnu-ct-ng.config*
-r-xr-xr-x 1 root root 43K Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-elfedit*
-r-xr-xr-x 2 root root 1.2M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-g++*
-r-xr-xr-x 2 root root 1.2M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-gcc*
-r-xr-xr-x 2 root root 1.2M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-gcc-11.2.0*
-r-xr-xr-x 1 root root 35K Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-gcc-ar*
-r-xr-xr-x 1 root root 35K Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-gcc-nm*
-r-xr-xr-x 1 root root 35K Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-gcc-ranlib*
-r-xr-xr-x 1 root root 793K Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-gcov*
-r-xr-xr-x 1 root root 565K Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-gcov-dump*
-r-xr-xr-x 1 root root 593K Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-gcov-tool*
-r-xr-xr-x 1 root root 1.4M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-gprof*
-r-xr-xr-x 4 root root 2.7M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-ld*
-r-xr-xr-x 4 root root 2.7M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-ld.bfd*
-r-xr-xr-x 1 root root 15K Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-ldd*
-r-xr-xr-x 1 root root 28M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-lto-dump*
-r-xr-xr-x 2 root root 1.3M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-nm*
-r-xr-xr-x 2 root root 1.5M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-objcopy*
-r-xr-xr-x 2 root root 2.7M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-objdump*
-r-xr-xr-x 1 root root 11K Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-populate*
-r-xr-xr-x 2 root root 1.3M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-ranlib*
-r-xr-xr-x 2 root root 1003K Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-readelf*
-r-xr-xr-x 1 root root 1.3M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-size*
-r-xr-xr-x 1 root root 1.3M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-strings*
-r-xr-xr-x 2 root root 1.5M Sep 27 14:10 x86_64-ubuntu16.04-linux-gnu-strip*
包含目標系統的 headers 和 libraries, 給 cross compiler 使用
且讓 toolchain folder 和目標系統的 libraries 分開, 避免被污染
ls -lh ~/x-tools/x86_64-ubuntu16.04-linux-gnu/x86_64-ubuntu16.04-linux-gnu
total 24K
dr-xr-xr-x 2 root root 4.0K Sep 27 14:10 bin/
dr-xr-xr-x 2 root root 4.0K Sep 27 12:44 debug-root/
dr-xr-xr-x 3 root root 4.0K Sep 27 14:10 include/
dr-xr-xr-x 3 root root 4.0K Sep 27 12:54 lib/
dr-xr-xr-x 2 root root 4.0K Sep 27 14:10 lib64/
dr-xr-xr-x 7 root root 4.0K Sep 27 13:35 sysroot/
呼~做完了 cross compile 的準備後, 接著就讓我們開始在 Linux cross compile Windows binary 吧!