--- title: \[Day 27\] Cross Compile 行前準備 tags: ithome, ithome2023, cmake --- [TOC] https://cmake.org/cmake/help/book/mastering-cmake/chapter/Cross%20Compiling%20With%20CMake.html [Day 27] Cross Compile 行前準備 # 本日內容 * Toolchain 是什麼? * 安裝 `crosstool-NG` * 設定 Toolchain * Build Toolchain * 預告 [Day 27 - Colab](https://colab.research.google.com/drive/1it-UckVjDFQl9jwDWzaMZl-o2sYSZjW1?usp=sharing) # Toolchain 是什麼? Toolchain, 就像他的名字一樣, 就是一堆 tools 將彼此的 input 和 output 串起來, 最終產生該平台的 binary 說起來簡單, 但實際上到底有哪些東西呢? 詳細內容可以參考 [crosstool-NG 文章](https://crosstool-ng.github.io/docs/toolchain-construction/), 這邊僅簡單敘述 下面的每個工具的 output, 都會是下一個工具的 input 換句話說, 較後面的工具會 depends 前一個工具, 最終變成一大串肉粽 也就是 toolchain 所需要的 cross compiler 1. GMP 1. MPFR 1. MPC 1. binutils 1. core pass 1 compiler 1. kernel headers 1. C library headers and start files 1. core pass 2 compiler 1. complete C library 1. final compiler 從 2-pass compiler 開始就是 platform-dependent 了 總而言之, 為了達成 cross compile 的目的 我們需要釐清這串肉粽的依賴鏈, 才能知道不同平台需要哪些工具, 而這些工具又 depends 哪些工具 (好繞口...) 詳細如何 build 出 cross compiler 請見 [此文章](https://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/) 好在這些事情已經有人幫我們處理了, 就是今天 demo 會使用的 [crosstool-NG](https://github.com/crosstool-ng/crosstool-ng)! `crosstool-NG` 提供了很多平台的 config 檔 (下面會介紹) 讓我們根據這些 config 檔 build 出不同平台的 cross toolchain 下面會用 `x86_64-ubuntu16.04-linux-gnu` 作為範例 從安裝 `crosstool-NG` 開始到最後 build 出 toolchain 完整操作一遍! # 安裝 `crosstool-NG` 詳細安裝步驟請見 [官方文件](https://crosstool-ng.github.io/docs/) 1. 到 [官網]() 下載 `crosstool-ng`, 這邊我們下載 txz 版本 ```shell= wget http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.25.0.tar.xz ``` 2. 解壓縮 ```shell= tar xf crosstool-ng-1.25.0.tar.xz ``` 3. 在 crosstool 下 configure Colab 還需要裝 `gperf`, `bison`, `help2man`, `libtool-bin`, `libtool-doc`, `flex`, `texinfo` 才能正常設定 ```shell= apt-get install -y \ libtool-bin \ libtool-doc \ help2man \ gperf \ bison \ flex \ texinfo \ gawk cd crosstool-ng-1.25.0 ./configure --prefix=/usr/local ``` 4. Compile 並安裝到系統 ```shell= make && sudo make install ``` 5. 安裝成功後, 我們就可以用 `ct-ng` 來設定 toolchain package 啦!!! ```shell= ct-ng --version ``` # 設定 Toolchain 我們可以用 `ct-ng menuconfig` 來設定 * 想要的 Toolchain * 安裝路徑 * Architecture * Processors * Components 版本 有兩種方法: GUI (Linux-kernel style) 和 CLI ## GUI 可以用 `ct-ng menuconfig` 來叫出 gui 來設定, 清楚明瞭 這種方法適合想要客製化 toolchain config 的人 ![](https://hackmd.io/_uploads/SyJ5pmbga.png) 不過因為我們是用 Colab 環境, 比較不方便用 GUI, 這邊就略過不介紹了 所以我們會用第二種方法: 從 CLI 設定 ## CLI `crosstool-ng` 提供了很~多 toolchain 的 config samples 在 `samples/` 底下, 我們可以用 CLI 看 ```shell= $ 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>]`) ```shell= cp samples/x86_64-ubuntu16.04-linux-gnu/crosstool.config .config ``` 再用 `yes "" | ct-ng oldconfig` 進行設定 (這裡我們用 `yes` 直接套用所有默認的設定) 設定完成後, 我們可以用 `ct-ng show-config` 確認剛剛環境是否設定成功 如果成功的話, 應該要看到我們剛剛選擇的環境設定 ```shell= $ 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 ``` 這樣就設定成功啦! # Build Toolchain 先確認 toolchain 需要的 dependencies 是否能正常下載, 沒問題後再開始 build toolchain ```shell= ct-ng source ``` :::warning 目前在下載 `zlib` 時存在已知問題: [crosstool-ng#1337](https://github.com/crosstool-ng/crosstool-ng/issues/1337) Workaround 是我們需要手動去下載 toolchain 需要的 tarball ```shell= wget https://zlib.net/fossils/zlib-1.2.12.tar.gz cp zlib-1.2.12.tar.gz .build/tarballs/ ``` 之後就可以開始 build toolchain 了! ::: :::warning 因為我們是用 Colab, 需要額外一些設定 1. Allow run as `root` 修改 `.config`, 加入以下幾個設定 ```txt= CT_EXPERIMENTAL=y CT_ALLOW_BUILD_AS_ROOT=y CT_ALLOW_BUILD_AS_ROOT_SURE=y ``` 2. 清掉 `LD_LIBRARY_PATH` 和 `LIBRARY_PATH` ```shell= export LD_LIBRARY_PATH= export LIBRARY_PATH ``` ```python= 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 啦! ```shell= ct-ng build ``` 我們可以從以下部分 output 看出 ct-ng 幫我們 build 了哪些 tools 因為是整條 toolchain 都要 build, 所以需要很多時間 ```shell= [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` 了🎉🎉🎉 ![](https://hackmd.io/_uploads/SJAAG6ZeT.png) ## 為什麼有兩個 toolchain folder? 從上圖可以看到, 我們的 toolchain folder `x86_64-ubuntu16.04-linux-gnu` 底下還有另外一個相同名稱的 folder, 這兩個有什麼區別呢? ## 外層的 Toolchain Folder 從這一層開始就是 cross compile 會用到的地方了 這一層又叫做 Toolchain Directory, 可以看作是當前系統和目標系統的中介 ```shell= 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 ```shell= 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* ``` ## 內層的 Folder 包含目標系統的 headers 和 libraries, 給 cross compiler 使用 且讓 toolchain folder 和目標系統的 libraries 分開, 避免被污染 ```shell= 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 吧!