嵌入式編譯環境搭建

1. 選定軟件版本號

選擇軟件版本號時,先看看glibc源代碼中的INSTALL文件。那裏列舉了該版本的glibc編譯時所需的binutils 和gcc的版本號。例如在 glibc-2.2.3/INSTALL 文件中推薦 gcc 用 2.95以上,binutils 用 2.10.1 以上版本。

我選的各個軟件的版本是:
linux-2.4.21+rmk2
binutils-2.10.1
gcc-2.95.3
glibc-2.2.3
glibc-linuxthreads-2.2.3
這是因爲這種搭配已經有人嘗試過了,是可以成功構建的,而有的組合則不一定,這時候要求我們自己修改某些軟件(如降低gcc的版本)的版本來試驗。由於我的初衷是要知道和熟悉這個過程,這樣今後要搭建其他版本的toolchain時也就比較簡單了。

2. 建立工作目錄
首先,我們建立幾個用來工作的目錄:(可根據自己喜好任意選擇建立的目錄)
我用的是/workdir/,先建立一個項目目錄embedded。
$pwd  
/workdir
$mkdir embedded

再在這個項目目錄 embedded 下建立三個目錄 build-tools、kernel 和 tools。
build-tools-用來存放你下載的 binutils、gcc 和 glibc 的源代碼和用來編譯這些源代碼的目錄。
kernel-用來存放你的內核源代碼和內核補丁。
tools-用來存放編譯好的交叉編譯工具和庫文件。
$cd embedded
$mkdir  build-tools kernel tools

執行完後目錄結構如下:
$ls embedded
build-tools kernel tools

3. 輸出和環境變量
我們輸出如下的環境變量方便我們編譯。
$export PRJROOT=/workdir/embedded
$export TARGET=arm-linux
$export PREFIX=$PRJROOT/tools
$export TARGET_PREFIX=$PREFIX/$TARGET
$export PATH=$PREFIX/bin:$PATH

如果你不慣用環境變量的,你可以直接用絕對或相對路徑。我如果不用環境變量,一般都用絕對路徑,相對路徑有時會失敗。環境變量也可以定義在.bashrc文件中,這樣當你logout或換了控制檯時,就不用老是export這些變量了。
體系結構和你的TAEGET變量的對應如下表:
你可以在通過glibc(also in ~/gcc-2.95.3/)下的config.sub腳本來知道,你的TARGET變量是否被支持,例如:
$./config.sub  arm-linux
arm-unknown-linux-gnu

4. 建立編譯目錄
爲了把源碼和編譯時生成的文件分開,一般的編譯工作不在的源碼目錄中,要另建一個目錄來專門用於編譯。用以下的命令來建立編譯你下載的binutils、gcc和glibc的源代碼的目錄。
$cd $PRJROOT/build-tools
$mkdir build-binutils build-boot-gcc build-gcc build-glibc gcc-patch
build-binutils-編譯binutils的目錄
build-boot-gcc-編譯gcc 啓動部分的目錄
build-glibc-編譯glibc的目錄
build-gcc-編譯gcc 全部的目錄
gcc-patch-放gcc的補丁的目錄

gcc-2.95.3 的補丁有 gcc-2.95.3-2.patch、gcc-2.95.3-no-fixinc.patch 和gcc-2.95.3-returntype-fix.patch,可以從 http://www.linuxfromscratch.org/ 下載到這些補丁,當然也可以直接google。
再將你下載的 binutils-2.10.1、gcc-2.95.3、glibc-2.2.3 和 glibc-linuxthreads-2.2.3 的源代碼放入 build-tools 目錄中
看一下你的 build-tools 目錄,有以下內容:
$ls
binutils-2.10.1.tar.bz2     build-gcc                 gcc-patch
build-binutls            build-glibc            glibc-2.2.3.tar.gz
build-boot-gcc           gcc-2.95.3.tar.gz     glibc-linuxthreads-2.2.3.tar.gz

建立內核頭文件
把你從 www.kernel.org 下載的內核源代碼放入 $PRJROOT /kernel 目錄
進入你的 kernel 目錄:
$cd $PRJROOT /kernel

解開內核源代碼
$tar -xzvf linux-2.4.21.tar.gz 或 $tar -xjvf linux-2.4.21.tar.bz2

小於 2.4.19 的內核版本解開會生成一個 linux 目錄,沒帶版本號,就將其改名。
$mv linux linux-2.4.x

給 Linux 內核打上你的補丁
$cd linux-2.4.21
$patch -p1 < ../patch-2.4.21-rmk2

編譯內核生成頭文件
$make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig

你也可以用 config 和 xconfig 來代替 menuconfig,但這樣用可能會沒有設置某些配置文件選項和沒有生成下面編譯所需的頭文件。推薦大家用 make menuconfig,這也是內核開發人員用的最多的配置方法。配置完退出並保存,檢查一下的內核目錄中的 include/linux/version.h 和 include/linux/autoconf.h 文件是不是生成了,這是編譯 glibc 是要用到的,version.h 和 autoconf.h 文件的存在,也說明了你生成了正確的頭文件。

還要建立幾個正確的鏈接
$cd include
$ln -s asm-arm asm
$cd asm
$ln -s arch-epxa arch
$ln -s proc-armv proc

接下來把Linux 內核頭文件拷貝過來用
$mkdir -p $TARGET_PREFIX/include
$cp -r $PRJROOT/kernel/linux-2.4.21/include/linux  $TARGET_PREFIX/include
$cp -r $PRJROOT/kernel/linux-2.4.21/include/asm-arm  $TARGET_PREFIX/include/asm 
$cp –r include/asm-generic/ ${TARGET_PREFIX}/include

建立二進制工具(binutils)
binutils是一些二進制工具的集合,其中包含了我們常用到的as和ld。

首先,我們解壓我們下載的binutils源文件。
$cd $PRJROOT/build-tools
$tar -xvjf binutils-2.10.1.tar.bz2

然後進入build-binutils目錄配置和編譯binutils。(should make sure that you have ‘lex’ (or ‘flex’) installed, or you can’t pass the ‘configure’, I used UBUNTU and it’s not installed beforehand) labels behind configure are necessary, or you can’t pass ‘make’

$cd build-binutils
$../binutils-2.10.1/configure --target=$TARGET --prefix=$PREFIX

--target 選項是指出我們生成的是 arm-linux 的工具,--prefix 是指出我們可執行文件安裝的位置。
會出現很多 check,最後產生 Makefile 文件。
有了 Makefile 後,我們來編譯並安裝 binutils,命令很簡單。
$make
$make install

看一下我們 $PREFIX/bin 下的生成的文件
$ls $PREFIX/bin
arm-linux-addr2line    arm-linux-gasp arm-linux-objdump              arm-linux-strings
arm-linux-ar                   arm-linux-ld           arm-linux-ranlib               arm-linux-strip
arm-linux-as                   arm-linux-nm           arm-linux-readelf    
arm-linux-c++filt              arm-linux-objcopy      arm-linux-size

我們來解釋一下上面生成的可執行文件都是用來幹什麼的
add2line - 將你要找的地址轉成文件和行號,它要使用 debug 信息。
Ar-產生、修改和解開一個存檔文件
As-gnu 的彙編器
C++filt-C++ 和 java 中有一種重載函數,所用的重載函數最後會被編譯轉化成彙編的標號,c++filt 就是實現這種反向的轉化,根據標號得到函數名。
Gasp-gnu 彙編器預編譯器。
Ld-gnu 的連接器
Nm-列出目標文件的符號和對應的地址
Objcopy-將某種格式的目標文件轉化成另外格式的目標文件
Objdump-顯示目標文件的信息
Ranlib-爲一個存檔文件產生一個索引,並將這個索引存入存檔文件中
Readelf-顯示 elf 格式的目標文件的信息
Size-顯示目標文件各個節的大小和目標文件的大小
Strings-打印出目標文件中可以打印的字符串,有個默認的長度,爲4
Strip-剝掉目標文件的所有的符號信息

建立初始編譯器(bootstrap gcc)
首先進入 build-tools 目錄,將下載 gcc 源代碼解壓
$cd $PRJROOT/build-tools
$tar -xvzf  gcc-2.95.3.tar.gz

然後進入 gcc-2.95.3 目錄給 gcc 打上補丁
$cd gcc-2.95.3
$patch -p1< ../gcc-patch/gcc-2.95.3.-2.patch
$patch -p1< ../gcc-patch/gcc-2.95.3.-no-fixinc.patch
$patch -p1< ../gcc-patch/gcc-2.95.3-returntype-fix.patch

echo timestamp > gcc/cstamp-h.in
在我們編譯並安裝 gcc 前,我們先要改一個文件 $PREFIX/build-tools/gcc-2.95.3/gcc/config/arm/t-linux,把
TARGET_LIBGCC2-CFLAGS = -fomit-frame-pointer -fPIC
這一行改爲
TARGET_LIBGCC2-CFLAGS = -fomit-frame-pointer -fPIC -Dinhibit_libc -D__gthr_posix_h

接着就是配置boostrap gcc, 後面要用bootstrap gcc 來編譯 glibc 庫。
$cd ..; cd build-boot-gcc
$../gcc-2.95.3/configure --target=$TARGET --prefix=$PREFIX /
>--without-headers  --enable-languages=c --disable-threads(not needed when you modify the file mentioned above)

這條命令中的 -target、--prefix 和配置 binutils 的含義是相同的,--without-headers 就是指不需要頭文件,因爲是交叉編譯工具,不需要本機上的頭文件。-enable-languages=c是指我們的 boot-gcc 只支持 c 語言。--disable-threads 是去掉 thread 功能,這個功能需要 glibc 的支持。
接着我們編譯並安裝 boot-gcc
$make all-gcc
$make install-gcc

An error like ‘~~/arm.c:530: error: invalid lvalue in assignment’ will occur if you compile it on a 64-bit machine.        The contant of this line is:
(arm_prog_mode =TARGET_APCS_32 ? PROG_MODE_PROG32 : PROG_MODE_PROG26;)
Open file gcc-2.95.3/gcc/config/arm/arm.h and find the line:
#define arm_prog_mode ((enum attr_prog_mode) arm_prgmode)
Modify it as:
#define arm_prog_mode (arm_prgmode)

我們來看看 $PREFIX/bin 裏面多了哪些東西
$ls $PREFIX/bin
你會發現多了 arm-linux-gcc 、arm-linux-unprotoize、cpp 和 gcov 幾個文件。

Gcc-gnu 的 C 語言編譯器
Unprotoize-將 ANSI C 的源碼轉化爲 K&R C 的形式,去掉函數原型中的參數類型。
Cpp-gnu的 C 的預編譯器
Gcov-gcc 的輔助測試工具,可以用它來分析和優程序。
使用 gcc3.2 以及 gcc3.2 以上版本時,配置 boot-gcc 不能使用 --without-headers 選項,而需要使用 glibc 的頭文件。

Accordding to method of book ‘building embedded linux system’ to build gcc, an error like below will occur,we should add a parameter ‘—disable-thread’
{
In file included from gthr-default.h:1,
                 from ../../gcc-2.95.3/gcc/gthr.h:98,
                 from ../../gcc-2.95.3/gcc/libgcc2.c:3034:
../../gcc-2.95.3/gcc/gthr-posix.h:37: pthread.h: No such file or directory
make[3]: *** [libgcc2.a] Error 1
make[3]: Leaving directory `/workdir/embedded/build-tools/build-boot-gcc/gcc'
make[2]: *** [stmp-multilib-sub] Error 2
make[2]: Leaving directory `/workdir/embedded/build-tools/build-boot-gcc/gcc'
make[1]: *** [stmp-multilib] Error 1
make[1]: Leaving directory `/workdir/embedded/build-tools/build-boot-gcc/gcc'
make: *** [all-gcc] Error 2
}
Add ‘—disable-thread’, error as below:
{
In file included from gthr-default.h:1,
                 from ../../gcc-2.95.3/gcc/gthr.h:98,
                 from ../../gcc-2.95.3/gcc/libgcc2.c:3034:
../../gcc-2.95.3/gcc/gthr-posix.h:37: pthread.h: No such file or directory
make[3]: *** [libgcc2.a] Error 1
make[3]: Leaving directory `/workdir/embedded/build-tools/build-boot-gcc/gcc'
make[2]: *** [stmp-multilib-sub] Error 2
make[2]: Leaving directory `/workdir/embedded/build-tools/build-boot-gcc/gcc'
make[1]: *** [stmp-multilib] Error 1
make[1]: Leaving directory `/workdir/embedded/build-tools/build-boot-gcc/gcc'
make: *** [all-gcc] Error 2
}
No errors if you modify the file $PREFIX/build-tools/gcc-2.95.3/gcc/config/arm/t-linux as the method above
 
建立 c 庫(glibc)
首先解壓 glibc-2.2.3.tar.gz 和 glibc-linuxthreads-2.2.3.tar.gz 源代碼
$cd $PRJROOT/build-tools
$tar -xvzf glibc-2.2.3.tar.gz
$tar -xzvf glibc-linuxthreads-2.2.3.tar.gz --directory=glibc-2.2.3

然後進入 build-glibc 目錄配置 glibc
$cd build-glibc
$CC=arm-linux-gcc ../glibc-2.2.3/configure --host=$TARGET --prefix="/usr"
--enable-add-ons --with-headers=$TARGET_PREFIX/include
CC=arm-linux-gcc 是把 CC 變量設成你剛編譯完的boostrap gcc,用它來編譯你的glibc。--enable-add-ons是告訴glibc用 linuxthreads 包,在上面我們已經將它放入了 glibc 源碼目錄中,這個選項等價於 -enable-add-ons=linuxthreads。--with-headers 告訴 glibc 我們的linux 內核頭文件的目錄位置。
配置完後就可以編譯和安裝 glibc
$make
$make install_root=$TARGET_PREFIX prefix="" install
An error like below occurs when i

發佈了33 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章