在 Gentoo Linux 下使用 crossdev 建立自己的 toolchain
Gentoo Linux 除了是一套非常強大、易於客製化的 Linux 系統以外,他亦可以讓你輕鬆的建 構不同平台的 toolchain,本文將介紹 Gentoo Linux 的 crossdev 套件,以及如何透過 crossdev 命令建立出不同平台的 toolchain.
Toolchain 中譯為 交叉工具鏈 ,是在進行嵌入式開發必備的工具,包含了以下幾部份:
binutils
用來生成二進制(binary)文件的基本工具
gcc
GNU C/C++ 編譯器
gdb
GNU 除錯工具
glibc/ulibc/newlib
系統相關 C 語言函式庫
linux headers
僅在編譯 Linux 相關平台所需要,為 Linux Kernel 相關的 header files(頭文件)
在非 Gentoo Linux 的平台,一般我們都使用 crosstool-ng 來協助產生需要的開發環境, 但是對於 Gentoo Linux 而言,使用內建的 crossdev 套件即可以快速構件所需要的開發環 境。
要使用 crossdev,首先我們當然是要安裝他囉,在 Gentoo 下使用 emerge 命令進行安裝
Gentoo kernel # emerge sys-devel/crossdev
安裝完成後,我們可以使用 crossdev -t help 查看 crossdev 支援哪些平台
Gentoo kernel # crossdev -t help
Supported Architectures:
- alpha - arm / armeb / aarch64
- hppa (parisc) - ia64
- i386 / i486 / i586 / i686 (x86) - m68k
- mips / mipsel / mips64 / mips64el
- powerpc (ppc) / powerpc64 (ppc64)
- sparc / sparc64 - s390 / s390x
- sh / sh[1-5] / sh64 - x86_64 (amd64)
Supported C Libraries:
- glibc (gnu)
- klibc [prob wont work]
- musl
- newlib [bare metal/no operating system]
- uclibc [not all arches are ported]
Special Targets:
- avr http://www.nongnu.org/avr-libc/
- bfin http://blackfin.uclinux.org/
- h8300 http://h8300-hms.sourceforge.net/
- mingw32 http://www.mingw.org/
- mingw64 http://mingw-w64.sourceforge.net/
- msp430 http://mspgcc.sourceforge.net/
- nds32 http://github.com/nds32
- nios2 http://www.altera.com/products/ip/processors/nios2/ni2-index.html
- xc16x http://www.infineon.com/
- ee / iop / dvp (ps2) [Playstation 2 targets]
- ppu / spu (cell) [Cell/Playstation 3 targets]
Softfloat toolchains:
Include 'softfloat' in the 'vendor' field
e.g. armeb-softfloat-linux-uclibc powerpc-booya_softfloat-linux-gnu
由上面的命令結果可以知道,基本上主流的 CPU 架構都支援,因此我們可以放心的學習使用 crossdev 建構不同平台的 toolchain.
假設我們今天要建構的 toolchain 是針對 ARMv7a 並且為 HardFloat ,執行於 Linux 環境的話,要怎樣作呢?在 Gentoo 下,使用以下命令 (其中 -S 代表選用 stable 版的套件)
Gentoo kernel # crossdev -S -t armv7a-hardfloat-linux-gnueabi
假設一切順利,你會看到 Gentoo 開始進行編譯,並把完整的 toolchain 編譯出來,不過通 常第一次執行的時候都會遇到如下錯誤 :(
,* please convert /etc/portage/profile/package.use.mask to a directory
,* If you file a bug, please attach the following logfiles:
,* /var/log/portage/cross-armv7a-hardfloat-linux-gnueabi-info.log
這是因為 Gentoo 的 crossdev 必須在 /etc/portage/package.* 皆為 資料夾 的情況 才可以使用,因此你可以手動將那些檔案都變成資料夾,或是使用以下 腳本 幫你自動處理:
#!/bin/bash
PROFILE_DIR="/etc/portage"
if [ ! -e ${PROFILE_DIR} ]; then
mkdir ${PROFILE_DIR};
fi
for PACK_DIR in package.accept_keywords package.keywords package.use package.unmask package.mask; do
CUR_DIR="${PROFILE_DIR}/${PACK_DIR}"
if [ ! -e ${CUR_DIR} ]; then
mkdir ${CUR_DIR}
fi
if [ -e ${CUR_DIR} -a ! -d ${CUR_DIR} ]; then
mv ${CUR_DIR} ${CUR_DIR}.moving
mkdir ${CUR_DIR}
mv ${CUR_DIR}.moving ${CUR_DIR}/monolithic
fi
done
echo "Completed!"
除此之外,由於 crossdev 會依據你建立的新的 toolchain,產生出相對應的 ebuild 檔案,因 此建議使用者擁有自己的 Local overlay。那我們要怎樣去建立 Local overlay 呢?首先 編輯 /etc/portage/make.conf 添加以下資訊
PORTDIR_OVERLAY="${PORTDIR_OVERLAY} /usr/local/portage"
接著建立 /usr/local/portage 資料夾
Gentoo kernel # mkdir -p /usr/local/portage
這樣當你使用 crossdev 建立新的 toolchain,就會在這個 Local overlay 看到相對應的 ebuild 被建立出來,如下
Gentoo kernel # tree -L 2 /usr/local/portage/
/usr/local/portage/
├── cross-armv7a-hardfloat-linux-gnueabi
│ ├── binutils -> /usr/portage/sys-devel/binutils
│ ├── gcc -> /usr/portage/sys-devel/gcc
│ ├── gdb -> /usr/portage/sys-devel/gdb
│ ├── glibc -> /usr/portage/sys-libs/glibc
│ └── linux-headers -> /usr/portage/sys-kernel/linux-headers
├── metadata
│ └── layout.conf
└── profiles
└── categories
8 directories, 2 files
建立其他平台的 toolchain
在上面我們講解到了如何使用 crossdev 建立 ARMv7a HardFloat 的 Linux toolchain, 那如果我們的目標是裸版 (baremetal)呢?
針對裸版(baremetal)開發,我們的 toolchain 名稱就不會是 <arch>-linux-gnueabi 這 樣的組成,並且我們基本上只會使用 stage4 來進行編譯,在 crossdev 中,可以使用 -s 參數來指定要編譯的 stage,針對裸版 (baremetal) 的平台,我們基本上都會使用 --stage4 來建立 toolchain。
Stage Options:
-s0, --stage0 Build just binutils
-s1, --stage1 Also build a bare C compiler (no C library/
C++/shared GCC libs/C++ exceptions/etc...)
-s2, --stage2 Also build kernel headers
-s3, --stage3 Also build the C library
-s4, --stage4 Also build a full compiler [default]
(shared libs GCC/various lang frontends/etc...)
以下列出幾個不同平台的 toolchain 建立命令:
- MSP430
Gentoo msp430 # crossdev -S -s4 -t msp430
- ARM Cortex-M
Gentoo stm32 # crossdev -S -s4 -t arm-none-eabi
- Ubuntu 的 arm-linux-gnueabihf
Gentoo stm32 # crossdev -S USE="-fortran -mudflap -nls -openmp multilib" EXTRA_ECONF="--with-cpu=cortex-a8 --with-float=hard" -t arm-linux-gnueabihf
測試我們建立的 toolchain
建立完 toolchain 後,我們可以用簡單的程式搭配 QEMU 來測試我們的 toolchain 是否能正常 工作,此處以 armv7a-hardfloat-linux-gnueabi- 作為範例,首先建立以下檔案並命名為 hello.c
#include <stdio.h>
int main()
{
printf("Hello cross-compiling world!\n");
return 0;
}
由於我們建立的 toolhcain 是針對 armv7a-hardfloat-linux-gnueabi 所建立,因此我們 會獲得 armv7a-hardfloat-linux-gnueabi-gcc 這個 gcc 命令,使用他來進行編譯
coldnew@Rosia ~ $ armv7a-hardfloat-linux-gnueabi-gcc hello.c -static -o hello
我們可以先使用 file 命令來檢查是否真的編譯為 ARMv7a 平台的程式
coldnew@Rosia ~ $ file hello
hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 2.6.32, not stripped
或是用 qemu-arm 直接執行這個 ELF 格式的程式
coldnew@Rosia ~ $ qemu-arm hello
Hello cross-compiling world!