特別聲明:本文可以轉(zhuǎn)發(fā),但是一定要注明出處“摘自王良明的博客:非常開源www.”,唯獨(dú)百度文庫不能收錄。
注意:本文是在ubuntu 9.04 desktop i386操作系統(tǒng)上完成的,對(duì)于在ubuntu 10.04操作系統(tǒng)上制作工具量的方法參見“手工制作最新版arm-linux交叉工具鏈(ubuntu 10.04)”
目錄
———————————————————
一、交叉編譯開發(fā)環(huán)境概況
1、交叉編譯工具鏈包含的文件
2、編譯配置命令configure的三個(gè)關(guān)鍵參數(shù)
3、制作工具鏈的流程圖
4、目錄視圖
二、制作工具鏈
1、準(zhǔn)備需要的軟件包
2、準(zhǔn)備工作環(huán)境
3、安裝Linux內(nèi)核頭文件
4、編譯安裝binutils
5、安裝Glibc 的頭文件
6、編譯gcc(第一階段,生成臨時(shí)arm-linux-gcc)
7、編譯庫文件GLIBC
8、編譯gcc(第二階段,生成最終arm-linux-gcc)
9、編譯gdb+gdbserver
三、配置交叉開發(fā)環(huán)境
1、配置工作環(huán)境變量
2、配置vim的工作參數(shù)
3、配置nfs+ftp
四、常見問題及處理
———————————————————
網(wǎng)上關(guān)于制作交叉編譯工具鏈的方法不多,就算有也是不全面,參照這些文檔操作幾乎是百分之百失??!本文算是一篇非常全面的文檔了,從安裝操 作系統(tǒng)開始,直到最后交叉編譯成功的整個(gè)過程都做了詳細(xì)的闡述,不過涉及的命令很多,參數(shù)尤甚,在具體的操作過程中需細(xì)心,如果有哪位同仁發(fā)現(xiàn)有新的問 題,歡迎隨時(shí)聯(lián)系交流,從使得本文檔更加完善。
一、交叉編譯開發(fā)環(huán)境概況。
【圖1】交叉開發(fā)環(huán)境物理設(shè)備連接圖
1、交叉編譯工具鏈包含的文件
【圖3】工具鏈中的文件類型
在Linux平臺(tái)上,編輯工具主要是vim,其他的文件(如編譯器、連接器、頭文件、庫文件和幫助文件)則是本文重點(diǎn)要講述的。
2、編譯配置命令configure的三個(gè)關(guān)鍵參數(shù)
在具體的編譯一個(gè)程序之前,我們一般事先要做配置,常用的方法是執(zhí)行源文件根目錄下的configure配置腳本,這個(gè)配置腳本帶有很多的命令行參 數(shù),對(duì)于交叉編譯來說,最主要也是最需要搞清楚的三個(gè)參數(shù)是:–host, –build, –target。(主意:參數(shù)前面是兩個(gè)減號(hào)“-”)
–host:配置后并且編譯好的程序能夠運(yùn)行的機(jī)器類型。這里指定的機(jī)器類型的格式是:“CPU類型-機(jī)器類型-操作系統(tǒng)類型-描述”,比如 i686-pc-linux-gnu表述X86類型CPU,個(gè)人電腦,linux操作系統(tǒng),描述GNU。在Linux系統(tǒng)上,這個(gè)參數(shù)一般取變量 MACHTYPE的值。如:- -host=${MACHTYPE}。如果不特別指定本參數(shù),那么默認(rèn)就是${MACHTYPE}。
–build:執(zhí)行編譯任務(wù)的機(jī)器類型。一般后續(xù)的編譯命令是make,通常配置和編譯工作都在同一臺(tái)機(jī)器上完成(其實(shí)就是本機(jī))。但也存在一種特 殊情況,即在另一臺(tái)速度更快的電腦上完成編譯任務(wù)(這種情況往往是編譯特大型的程序)。如果不指定本參數(shù),那么默認(rèn)就是–host指定的值。
–target:編譯后的程序用來處理的那些程序能夠運(yùn)行的機(jī)器類型。這個(gè)參數(shù)在編譯gcc時(shí)常用,比如本文編譯gcc時(shí)就是通過指定 –target參數(shù)的值為arm-linux,表示這樣編譯出來的gcc(實(shí)際程序名是arm-linux-gcc)用來編譯其他程序時(shí)生成的可執(zhí)行程序 可以在ARM類型的CPU上跑(當(dāng)然要在linux操作系統(tǒng)的支持下)。
舉例1:
本文用到的例子因?yàn)榕渲煤途幾g都在同一臺(tái)電腦上進(jìn)行,所以是:
–host=${MACHTYPE} –build=${MACHTYE} –target=arm-linx
3、制作工具鏈的流程圖
制作工具鏈?zhǔn)且粋€(gè)考驗(yàn)體力、智力和耐力的工作,完成一個(gè)完整工具鏈的制作耗費(fèi)數(shù)天的時(shí)間是不足為怪的。那么從宏觀上事先了解整個(gè)制作個(gè)過程是非常必要的,這樣就能從全局了解和把握它。
【圖4】制作工具鏈的流程圖
根 據(jù)箭頭指向我們很容易知道編譯的先后次序:binutils的編譯是獨(dú)立的,而要注意的是gcc的編譯分成兩個(gè)階段,第一階段是靜態(tài)編譯成arm- linux-gcc,目的是為了用它來編譯交叉開發(fā)所需要的庫文件和頭文件,然后利用這些交叉庫和頭文件對(duì)gcc進(jìn)行第二階段的編譯,從而生成最終的交叉 編譯器arm-linux-gcc,在操作過程中我們要時(shí)時(shí)注意每一次編譯所用到的編譯器什么,圖中已經(jīng)給出了答案:即,除了編譯glibc使用臨時(shí)的 arm-linux-gcc外,其他統(tǒng)一采用主機(jī)上的gcc。最終生成的交叉工具arm-linux-*、交叉庫/頭和交叉編譯器arm-linux- gcc就是我們需要的交叉工具鏈。
4、目錄視圖
在整個(gè)制作過程中,我們建立了一系列的目錄(包括編譯過程中建立的目錄和工具鏈目錄),如下圖所示:
【圖5】制作工具鏈過程中創(chuàng)建的目錄
二、制作工具鏈
主意:下面的綠色部分表示命令,“#”之后的內(nèi)容是說明,命令中非單字母參數(shù)前是兩個(gè)減號(hào)“-”,由于排版問題只顯示了一個(gè)“-”,比如參數(shù)–host前是兩個(gè)“-”。所有的命令都是以root用戶運(yùn)行的。
1、準(zhǔn)備需要的軟件包
上面linux內(nèi)核地址錯(cuò)誤,應(yīng)該是ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.28.tar.bz2
把這些軟件包下載到目錄/usr/local/arm/tars下。
2、準(zhǔn)備工作環(huán)境
在windows上安裝vmware,然后新建一個(gè)虛擬機(jī)(8G磁盤空間和512M內(nèi)存,NAT網(wǎng)卡),在虛擬機(jī)里安裝ubuntu 9.04 desktop i386版本。
1)、設(shè)置root用戶登錄:
(1)菜單“系統(tǒng)–>管理–>登錄菜單–>安全”,勾選“允許本地系統(tǒng)管理員登錄(A)”;(2)打開一個(gè)終端(菜單“應(yīng)用程序
–>附件–>終端”),輸入命令:sudo -s,然后輸入密碼切換到超級(jí)用戶去修改root的密碼:passwd root
2)、更新安裝源和加裝必要的軟件:
注銷當(dāng)前用戶(鼠標(biāo)點(diǎn)擊右上角的關(guān)機(jī)圖標(biāo),然后點(diǎn)擊“退出…”),然后以root用戶重新登錄。
sed -i ‘s|cn.arch|tw.arch|g’ /etc/apt/sources.list #換成臺(tái)灣的安裝源,這樣安裝軟件速度要快很多。
apt-get update && apt-get upgrade && reboot #對(duì)全部軟件進(jìn)行升級(jí)。升級(jí)之后需要重啟電腦,以后登陸統(tǒng)一用root。菜單“系統(tǒng)–>系統(tǒng)管理–>更新管理器”會(huì)提示還有軟件需要升級(jí),然后再重啟電腦。
dpkg -l|grep ^ii|awk ‘{print $2}’ > packages.orig #先記錄截止目前安裝的所有軟件包。
rapt-get install openssh-serve # 安裝遠(yuǎn)程管理服務(wù)器,這樣我們可以遠(yuǎn)程登陸了。
echo “UseDNS no” >> /etc/ssh/sshd_config #關(guān)閉ssh登錄時(shí)的DNS反向解析,從而加快ssh登錄。
使用命令ifconfig可以查看網(wǎng)卡的ip地址,記下地址一遍以后遠(yuǎn)程登陸。在windows上安裝一個(gè)遠(yuǎn)程登陸工具putty,從這里 (http://www./wp-content/downloads/putty.zip)可以下載,解壓之后把里面的 putty.exe放到電腦桌面上,然后直接雙擊即可啟動(dòng)(輸入虛擬機(jī)的ip地址即可登陸)。
apt-get install vim #安裝全功能編輯工具vim。
echo “export HISTSIZE=5000″ >> /root/.bashrc #記錄最近5000條歷史命令。
. /root/.bashrc #或者:
exit #退出putty,然后再次從putty登陸虛擬機(jī)。
apt-get install patch texinfo m4 flex bison #加裝這些軟件包
apt-get build-dep glibc #安裝編譯glibc依賴的軟件包。
apt-get build-dep gcc-4.2 #安裝編譯gcc時(shí)所依賴的軟件包。
3)、設(shè)置環(huán)境變量:
export TOP=/usr/local/arm #設(shè)置目標(biāo)工具鏈目錄的頂成目錄。
export TAR=${TOP}/tars #設(shè)置源文件壓縮包的存放目錄路徑。
export CLFS=${TOP}/clfs #設(shè)置編譯過程工作目錄。
export SYSROOT=${TOP}/4.2.1 #設(shè)置目標(biāo)工具鏈的工作目錄。
export TARGET_PREFIX=${TOP}/4.2.1 #設(shè)置目標(biāo)工具鏈的安裝目錄。
export LINUX_VERSION=2.6.28 #設(shè)置 Linux 的版本號(hào)
export BINUTILS_VERSION=2.18 #設(shè)置 binutils 的版本號(hào)
export GLIBC_VERSION=2.6.1 #設(shè)置 glibc 的版本號(hào)
export GCC_VERSION=4.2.1 #設(shè)置 目標(biāo)工具鏈的版本號(hào)。
export CLFS_TARGET=”arm-linux” #設(shè)置目標(biāo)交叉編譯工具鏈的編譯器(arm-linux-gcc)的路徑,因?yàn)樵谕瓿傻谝浑A段arm-linux-gcc的編譯后,我們將會(huì)把它安裝到這里,并且使用它來編譯出第二階段 arm-linux-gcc 制作所依賴的動(dòng)態(tài)鏈接庫 glibc。
export PATH=${TARGET_PREFIX}/bin:$PATH
unset CFLAGS #禁用兩個(gè)環(huán)境變量,因?yàn)榭赡軐?dǎo)致編譯過程出錯(cuò)
unset CXXFLAGS #默認(rèn)情況下這兩個(gè)環(huán)境變量為空,但隨不同的Linux 平臺(tái)的不同,或者用戶自己之前的使用過程中設(shè)置了這兩個(gè)變量設(shè)置目標(biāo)工具鏈的目標(biāo)體系,Gcc編譯器會(huì)根據(jù)這個(gè)變量來確定目標(biāo)交叉編譯工具鏈?zhǔn)菫槟莻€(gè)目標(biāo)體系的cpu編譯程序的。
為了使得每次登陸后自動(dòng)設(shè)置這些環(huán)境變量,可以把上述內(nèi)容加到文件/root/.bashrc的末尾。
3、安裝Linux內(nèi)核頭文件
install -dv ${SYSROOT}/usr/include #建立Linux頭文件安裝目錄
install -dv ${TOP}/source #建立源碼解壓目錄
cd ${TOP}/source #進(jìn)入源碼解壓目錄
tar -xjf ${TAR}/linux-${LINUX_VERSION}.tar.bz2 #解壓解包 Linux 內(nèi)核源碼包
cd linux-${LINUX_VERSION} #進(jìn)入Linux 內(nèi)核源碼目錄
make mainstone_defconfig ARCH=arm #設(shè)置 Linux 內(nèi)核源碼匹配的cpu 體系,我們用的是PXA270
make include/linux/version.h #生成Linux 版本頭文件。
#復(fù)制制作目標(biāo)交叉編譯工具鏈所要的Linux頭文件
cp -a include/{asm-generic,linux,mtd,scsi,sound} ${SYSROOT}/usr/include
cp -a include/asm-arm ${SYSROOT}/usr/include/asm
4、編譯安裝binutils
mkdir -p ${TARGET_PREFIX} #建立目標(biāo)交叉編譯工具鏈安裝目錄
cd ${TOP}/source #進(jìn)入源碼解壓目錄
tar -jxf ${TAR}/binutils-${BINUTILS_VERSION}.tar.bz2 #解壓binutils 源碼包到此目錄
cd binutils-${BINUTILS_VERSION} #進(jìn)入 binutils 的源碼目錄
patch -Np1 -i ${TAR}/binutils-${BINUTILS_VERSION}-posix-1.patch #給binutils打補(bǔ)丁
mkdir -p ${TOP}/source/BUILD/binutils-${BINUTILS_VERSION} #建立 binutils 的編譯目錄
cd ${TOP}/source/BUILD/binutils-${BINUTILS_VERSION} #進(jìn)入 binutils 的編譯目錄
#設(shè)立匯編器的環(huán)境變量
export AR=ar #注意:這里定義的兩個(gè)環(huán)境變量是臨時(shí)性的,重啟機(jī)器后沒有了,那么下次再來執(zhí)行下面的命令前還要定義這兩個(gè)環(huán)境變量。
export AS=as
#對(duì) binutils 進(jìn)行配置
${TOP}/source/binutils-${BINUTILS_VERSION}/configure
–prefix=${TARGET_PREFIX} –target=${CLFS_TARGET}
–with-sysroot=${SYSROOT} –disable-nls –enable-shared –disable-multilib
–enable-werror=no
make configure-host #編譯 binutils
注意:做下面的步驟之前請(qǐng)參考文后的“問題1”處理
make
make install #安裝 binutils
#復(fù)制后續(xù)編譯所要的 binutils 的頭文件
cp -v ${TOP}/source/binutils-${BINUTILS_VERSION}/include/libiberty.h ${SYSROOT}/usr/include
5、安裝Glibc 的頭文件
cd ${TOP}/source #進(jìn)入源碼解壓目錄
tar -jxf ${TAR}/glibc-${GLIBC_VERSION}.tar.bz2 #解壓 Glibc 的源碼包到此目錄
#改變?cè)创a目錄名,為了標(biāo)識(shí)這份源碼是為安裝頭文件而解壓、配置、補(bǔ)丁的。這里采用改變目錄名的方式來實(shí)現(xiàn),目的在于保留這些編譯、設(shè)置過的源碼,以后可以直接用這些編譯過的內(nèi)容直接安裝,不需要再次編譯。因?yàn)榫幾g是很耗時(shí)的事情。
mv glibc-${GLIBC_VERSION} glibc-${GLIBC_VERSION}-headers-build
cd glibc-${GLIBC_VERSION}-headers-build #進(jìn)入glibc頭文件安裝源碼目錄
#下面兩行是為了消除在配置glibc時(shí) gcc 對(duì)glibc的依賴。因?yàn)檫@里只是為了安裝頭文件,并不是要配置、編譯、安裝 Glibc。
cp configure{,.orig}
sed -e ‘s/3.4/3.[0-9]/g’ configure.orig > configure
#解壓glibc 的cpu體系支持源碼包到glibc 頭文件安裝源碼目錄,因?yàn)間libc 默認(rèn)是沒有ARM cpu支持的,GNU組織專門加入了此源碼包來解決此問題。
tar -jxf ${TAR}/glibc-ports-${GLIBC_VERSION}.tar.bz2
#改變cpu 體系支持源碼目錄為 ports ,因?yàn)間libc對(duì)所有加入的而外支持包的默認(rèn)搜索目錄為 ports。
mv glibc-ports-${GLIBC_VERSION} ports
#建立glibc頭文件配置、安裝的工作目錄
mkdir -p ${TOP}/source/BUILD/glibc-${GLIBC_VERSION}-headers-build
#進(jìn)入glibc頭文件配置、安裝的工作目錄
cd ${TOP}/source/BUILD/glibc-${GLIBC_VERSION}-headers-build
#以下三步是為了把glibc頭文件配置成支持 NPTL(linux 的新線程標(biāo)準(zhǔn))而設(shè)立的必須條件,并把這些條件寫入緩存文件(可以從下面的配置選項(xiàng) –cache-file=config.cache看出)
echo “l(fā)ibc_cv_forced_unwind=yes” > config.cache
echo “l(fā)ibc_cv_c_cleanup=yes” >> config.cache
echo “l(fā)ibc_cv_arm_tls=yes” >> config.cache
export CC=gcc #指定配置使用的編譯器
#配置glibc
${TOP}/source/glibc-${GLIBC_VERSION}-headers-build/configure
–prefix=/usr –host=${CLFS_TARGET} –with-headers=${SYSROOT}/usr/include
–cache-file=config.cache
make install-headers install_root=${SYSROOT} #安裝 glibc頭文件
cp -v bits/stdio_lim.h ${SYSROOT}/usr/include/bits #復(fù)制編譯后續(xù)編譯所要的頭文件
#建立必要的地頭文件,內(nèi)容為空,因?yàn)檫@個(gè)頭文件在第一階段Gcc 編譯安裝時(shí)要被 check 到,但這是后面編譯安裝目標(biāo)機(jī)的glibc時(shí)才被生成安裝的。
touch ${SYSROOT}/usr/include/gnu/stubs.h
#拷貝建立支持NPTL編譯器所必須的頭文件
cp -f
${TOP}/source/glibc-${GLIBC_VERSION}-headers-
build/ports/sysdeps/unix/sysv/linux/arm/nptl/bits/pthreadtypes.h
${SYSROOT}/usr/include/bits
6、編譯gcc(第一階段,生成臨時(shí)arm-linux-gcc)
export CC=gcc #指定配置使用的編譯器
cd ${TOP}/source #進(jìn)入源碼解壓目錄
tar -jxf ${TAR}/gcc-${GCC_VERSION}.tar.bz2 #解壓gcc源碼
#改變?cè)创a目錄,為了標(biāo)識(shí)這是第一階段用的gcc源碼,目的前面說過了。
mv gcc-${GCC_VERSION} gcc-${GCC_VERSION}-stage1
cd gcc-${GCC_VERSION}-stage1 #進(jìn)入第一階段源碼目錄
#打上支持posix 標(biāo)準(zhǔn)的補(bǔ)丁,新的線程標(biāo)準(zhǔn)NPTL是符合posix標(biāo)準(zhǔn)的。
patch -Np1 -i ${TAR}/gcc-${GCC_VERSION}-posix-1.patch
#打上交叉編譯gcc搜索頭文件路徑的補(bǔ)丁
patch -Np1 -i ${TAR}/gcc-${GCC_VERSION}-cross_search_paths-1.patch
cd ${TOP}/source #進(jìn)入源碼解壓目錄
mkdir -p BUILD/gcc-${GCC_VERSION}-stage1 #建立編譯第一階段gcc的工作目錄
cd BUILD/gcc-${GCC_VERSION}-stage1 #進(jìn)入編譯第一階段gcc 的工作目錄
#配置第一階段gcc。
${TOP}/source/gcc-${GCC_VERSION}-stage1/configure
–prefix=${TARGET_PREFIX} –host=${MACHTYPE} –target=${CLFS_TARGET}
–disable-multilib –with-sysroot=${SYSROOT} –disable-nls –disable-shared
–enable-languages=c
#注意配置選項(xiàng)–enable-languages=c 和–disable-shared!因?yàn)檫@一階段的gcc
制作時(shí),還沒有生成其給目標(biāo)機(jī)編譯程序時(shí)所依賴的動(dòng)態(tài)庫,所以要—disable-shared,因此第一階段的gcc是個(gè)靜態(tài)的arm-linux-
gcc。之所以只用了–enable-languages=c,而后面生成第二階段的arm-linux-gcc卻用了–enable-
languages=c,c++,是因?yàn)槲覀冞@一階段的arm-linux-gcc是為了生成制作第二階段arm-linux-gcc所依賴的glibc
動(dòng)態(tài)函數(shù)庫而制作,編譯glibc只需要arm-linux-gcc,并不需要arm-linux-g++。加上c++也是沒錯(cuò)的。
主意:如果下面一步報(bào)錯(cuò),請(qǐng)參考文后的“問題2”處理,然后再執(zhí)行下面的步驟
make all-gcc #編譯第一階段gcc
make install-gcc #安裝第一階段gcc
7、編譯庫文件GLIBC
cd ${TOP}/source
tar -jxf ${TAR}/glibc-${GLIBC_VERSION}.tar.bz2 #解壓glibc源碼
cd glibc-${GLIBC_VERSION} #進(jìn)入源碼目錄
#解壓glibc 的cpu體系支持源碼包到glibc 頭文件安裝源碼目錄,因?yàn)間libc 默認(rèn)是沒有ARM cpu支持的,GNU組織專門加入了此源碼包來解決此問題。
tar -jxf ${TAR}/glibc-ports-${GLIBC_VERSION}.tar.bz2
#改變cpu 體系支持源碼目錄為 ports ,因?yàn)間libc對(duì)所有加入的而外支持包的默認(rèn)搜索目錄為 ports。
mv glibc-ports-${GLIBC_VERSION} ports
#以下四步均為給glibc打補(bǔ)丁。
patch -Np1 -i ${TAR}/glibc-2.6.1-libgcc_eh-1.patch
patch -Np1 -i ${TAR}/glibc-2.6.1-localedef_segfault-1.patch
patch -Np1 -i ${TAR}/glibc-2.6.1-cross_hacks-1.patch
patch -Np1 -i ${TAR}/glibc-2.6.1-RTLD_SINGLE_THREAD_P-1.patch
mkdir -p ${TOP}/source/BUILD/glibc-${GLIBC_VERSION} #建立配置、編譯、安裝glibc的工作目錄
cd ${TOP}/source/BUILD/glibc-${GLIBC_VERSION} #進(jìn)入配置、編譯、安裝glibc的工作目錄
#以下三步是為了把glibc頭文件配置成支持 NPTL(linux 的新線程標(biāo)準(zhǔn))而設(shè)立的必須條件,并把這些條件寫入緩存文件(可以從下面的配置選項(xiàng) –cache-file=config.cache看出)
echo “l(fā)ibc_cv_forced_unwind=yes” > config.cache
echo “l(fā)ibc_cv_c_cleanup=yes” >> config.cache
echo “l(fā)ibc_cv_arm_tls=yes” >> config.cache
#指定配置使用的編譯器為gcc,即本機(jī)的gcc
export BUILD_CC=”gcc”
#指定編譯glibc時(shí)使用第一階段的交叉gcc,即上面生成的arm-linux-gcc
export CC=”${CLFS_TARGET}-gcc”
#指定匯編glibc時(shí)使用的匯編器為arm-linux-ar,即在制作binutils 時(shí)生成的交叉匯編器
export AR=”${CLFS_TARGET}-ar”
export RANLIB=”${CLFS_TARGET}-ranlib”
#配置交叉編譯工具鏈所依賴的動(dòng)態(tài)庫glibc
${TOP}/source/glibc-${GLIBC_VERSION}/configure
–prefix=/usr –libexecdir=/usr/lib/glibc –host=${CLFS_TARGET}
–build=${MACHTYPE} –disable-profile –enable-add-ons –with-tls
–enable-kernel=2.6.0 –with-__thread –with-binutils=${TARGET_PREFIX}/bin
–with-headers=${SYSROOT}/usr/include –cache-file=config.cache
主意:下面一步會(huì)報(bào)錯(cuò),請(qǐng)參考文后的“問題3”處理,然后再執(zhí)行下面的步驟
make #編譯交叉編譯工具鏈所依賴的動(dòng)態(tài)庫glibc
make install install_root=${SYSROOT} #安裝交叉編譯工具鏈所依賴的動(dòng)態(tài)庫
8、編譯gcc(第二階段,生成最終arm-linux-gcc)
export CC=gcc
cd ${TOP}/source #進(jìn)入源碼解壓目錄
tar -jxf ${TAR}/gcc-${GCC_VERSION}.tar.bz2 #解壓gcc源代碼
#改名源碼目錄,為了標(biāo)識(shí)這是編譯第二階段的gcc 所用的源碼
mv gcc-${GCC_VERSION} gcc-${GCC_VERSION}-stage2
cd gcc-${GCC_VERSION}-stage2 #進(jìn)入源碼目錄
#打上支持posix 標(biāo)準(zhǔn)的補(bǔ)丁,新的線程標(biāo)準(zhǔn)NPTL是符合posix標(biāo)準(zhǔn)的。
patch -Np1 -i ${TAR}/gcc-${GCC_VERSION}-posix-1.patch
#打上交叉編譯gcc搜索頭文件路徑的補(bǔ)丁
patch -Np1 -i ${TAR}/gcc-${GCC_VERSION}-cross_search_paths-1.patch
cd ${TOP}/source #進(jìn)入源碼解壓目錄
mkdir -p BUILD/gcc-${GCC_VERSION}-stage2 #建立第二階段gcc的編譯工作目錄
cd BUILD/gcc-${GCC_VERSION}-stage2 #進(jìn)入第二階段gcc的編譯工作目錄
#配置第二階段交叉編譯工具鏈
${TOP}/source/gcc-${GCC_VERSION}-stage2/configure
–prefix=${TARGET_PREFIX} –host=${MACHTYPE} –target=${CLFS_TARGET}
–disable-multilib –with-sysroot=${SYSROOT} –disable-nls –enable-shared
–enable-languages=c,c++ –enable-__cxa_atexit –enable-c99
–enable-long-long –enable-threads=posix
make all-gcc #編譯第二階段交叉編譯工具鏈
make install-gcc install_root=${TARGET_PREFIX} #安裝交叉編譯工具鏈
9、編譯gdb
基于arm的交叉嵌入式開發(fā)往往采用gdb/gdbserver進(jìn)行遠(yuǎn)程調(diào)試,gdbserver連同被調(diào)試的程序在開發(fā)板上跑,而gdb和被調(diào)試程序的源程序在電腦上,可以用如下的圖形表示:
【圖6】遠(yuǎn)程調(diào)試拓?fù)鋱D
【圖7】程序的錯(cuò)誤類型和處理工具
1)、準(zhǔn)備源碼:
wget http://ftp./gnu/gdb/gdb-7.0.tar.bz2
tar -jxf gdb-7.0.tar.bz2
apt-get install libncurses5-dev
2)、編譯GDB客戶端:
cd gdb-7.0
./configure –target=${CLFS_TARGET} –prefix=${TARGET_PREFIX}
make && make install
3)、編譯GDB服務(wù)器:
cd gdb/gdbserver
export CC=arm-linux-gcc #指定配置使用的編譯器
./configure –target=${CLFS_TARGET} –host=${CLFS_TARGET}
sed -i ‘s|#define HAVE_SYS_REG_H|//#define HAVE_SYS_REG_H|g’ config.h
make CC=arm-linux-gcc
cp gdbserver ${TARGET_PREFIX}/bin #把編譯后的程序暫時(shí)保存到目錄${TARGET_PREFIX}/bin中,等以后制作好了嵌入式根文件系統(tǒng)后在拷貝到嵌入式根文件系統(tǒng)的/bin目錄下。
4)、舉例說明遠(yuǎn)程調(diào)試方法
arm-linux-gcc -g hello.c -o hello #交叉編譯
cp hello /srv/rootfs/bin #主意:目錄/srv/rootfs/bin以nfs類型被目標(biāo)板mount到根目錄上。
#通過minicom鏈接到開發(fā)板,并啟動(dòng)調(diào)試器:
/root # gdbserver 192.168.0.100:1234 /bin/hello
arm-linux-gdb #電腦主機(jī)上啟動(dòng)調(diào)試器客戶端
(gdb) target remote 192.168.0.100:1234 #假定開發(fā)板的ip地址是192.168.0.100
(gdb) symbol -file /path/to/hello #指定程序源碼文件的目錄
…… #此后就像調(diào)試本地程序一樣進(jìn)行調(diào)試了。
5)、gdb的調(diào)試命令:
(gdb) list n,m #顯示從n行到m行的源代碼,如“l(fā)ist 10,30”列出10至30行的源代碼
(gdb) break 9 #在第9行設(shè)置一個(gè)中斷點(diǎn)
(gdb) run #在gdb里運(yùn)行被調(diào)試程序
(gdb) print i #顯示變量i的值
(gdb) info locals #顯示全部的本地變量值
(gdb) help #顯示全部的可用gdb命令, 用戶“help <命令> ”顯示具體的命令的用法。
(gdb) whatis i # 顯示變量i的類型,比如“整型、結(jié)構(gòu)體、字符型”等。
(gdb) print x=100 #給變量x賦值100
(gdb) step #開始單步運(yùn)行
(gdb) n #單步執(zhí)行一條語句
(gdb) display i,j,p #同時(shí)顯示三個(gè)變量i,j,p的值
(gdb) bt #顯示整個(gè)調(diào)用堆棧(比如main函數(shù)調(diào)用abc函數(shù),abc函數(shù)有調(diào)用了fun函數(shù)調(diào)用路徑會(huì)打印出來)。
(gdb) info break #列出已定義的全部斷點(diǎn)
(gdb) delete breakpoints 9 #刪除第9行的中斷點(diǎn)
(gdb) continue #繼續(xù)執(zhí)行被調(diào)試程序
(gdb) quit #退出調(diào)試
gdb的調(diào)試命令非常豐富,想要深入研究的同仁可以參考操作手冊(cè)gdb.pdf
三、配置交叉開發(fā)環(huán)境
1、配置工作環(huán)境變量
這樣配置好的工具鏈就可以打包拷貝到其他的X86機(jī)器上運(yùn)行,只要把目錄/usr/local/arm/4.2.1/bin加到PATH環(huán)境變量里,比如:
export PATH=/usr/local/arm/4.2.1/bin:$PATH
arm-linux-gcc -v 顯示如下結(jié)果:
Using built-in specs.
Target: arm-linux
Configured with: /usr/local/arm/source/gcc-4.2.1-stage2/configure
–prefix=/usr/local/arm/4.2.1 –host=i486-pc-linux-gnu –target=arm-linux
–disable-multilib –with-sysroot=/usr/local/arm/4.2.1 –disable-nls
–enable-shared –enable-languages=c,c++ –enable-__cxa_atexit –enable-c99
–enable-long-long –enable-threads=posix
Thread model: posix
gcc version 4.2.1
主意上面的幾個(gè)關(guān)鍵字:
1)、目錄主機(jī)(Target)是arm-linux ;
2)、 運(yùn)行主機(jī)(–host)是i486-pc-linux-gnu;
3)、系統(tǒng)根(sysroot)是/usr/local/arm/4.2.1,這個(gè)目錄下有交叉編譯庫文件和頭文件;
4)、能編譯的語言有c\c++;
5)、線程兼容posix。
最后做一番測試:
cat > cross.c <<EOF
#include <stdio.h>
main(){printf(“Hello CrossTool !”);}
EOF
arm-linux-gcc cross.c -o cross #交叉編譯;
file cross #查看程序類型
cross: ELF 32-bit LSB executable, ARM, version 1, dynamically linked (uses shared libs), for GNU/Linux 2.6.0, not stripped
主意上面的幾個(gè)關(guān)鍵字:arm, dynamically linked,表示運(yùn)行于arm平臺(tái),且是動(dòng)態(tài)鏈接的。
2、配置vim的工作參數(shù)
執(zhí)行下述命令把vim的配置參數(shù)加到用戶家目錄下的.vimrc中即可:
cat >$HOME/.vimrc <<EOF
set autoindent
set cindent
set cinoptions={0,1s,t0,n-2,p2s,(03s,=.5s,>1s,=1s,:1s
set nowrap
syntax enable
set ts=4
set hlsearch
set ruler
set showcmd
set nu
EOF
–這樣以后用vi或者vim編輯程序時(shí)會(huì)高亮語法顯示、自動(dòng)縮進(jìn)等等,非常方便。
vim使用技巧:
刪除 DOS 回車符 ^M::%s/\r//g
刪除行尾空格:%s= *==g
刪除行尾空格和 DOS 回車符:%s#\s*\r\?$##
壓縮多行空行為一行:%s/^\n\+/\r/
普通替換:%s/fred/joe/igc
刪除所有的空行:光標(biāo)移到首行,一次輸入!Ggrep -v “^$”
整理雜亂的c語言代碼:gg=G
整理{}內(nèi)的代碼:=a{
3、配置NFS+TFTP+BOOTP
需要NFS的目的是建立網(wǎng)絡(luò)文件系統(tǒng),開發(fā)箱通過它把嵌入式根文件系統(tǒng)“安裝”過來,另外開發(fā)箱通過tftp協(xié)議把內(nèi)核下載下來,通過BOOTP自動(dòng)配置網(wǎng)卡參數(shù)。
1)、開發(fā)板內(nèi)核啟用NFS支持:
(1)打開嵌入式內(nèi)核中的NFS配置
make menuconfig –> File systems –> Network File Systems –> Root file system NFS
(2)修改嵌入式內(nèi)核中的內(nèi)核啟動(dòng)命令串:
make menuconfig –> Boot
console=ttyS0,115200 mem=64M rw root=/dev/nfs init=/sbin/init
nfsroot=210.210.200.2:/srv/rootfs
ip=210.210.200.1:210.210.200.2:210.210.200.2:255.255.255.252::eth0:off
主意:上述內(nèi)核啟動(dòng)命令串中的參數(shù)ip的格式如下:
ip=<本地網(wǎng)卡ip>:<nfs服務(wù)器ip>:<網(wǎng)關(guān)>:<網(wǎng)絡(luò)掩碼>:<主機(jī)名>:<網(wǎng)卡名>:<是否自動(dòng)配置>
然后要重新編譯嵌入式內(nèi)核。
2)、電腦上安裝NFS+TFTP+BOOTP
apt-get install nfs-kernel-server tftpd bootp openbsd-inetd
# 編輯/etc/exports,在末尾加入下面一行:
/srv/rootfs *(rw,rsync,no_subtree_check,no_root_squash)
/etc/init.d/nfs-kernel-server restart #啟動(dòng)NFS服務(wù)
#修改文件/etc/inetd.conf,加入如下一行:
bootps dgram udp wait root /usr/sbin/bootpd bootpd -i -t 120
tftp dgram udp wait nobody /usr/sbin/tcpd /usr/sbin/in.tftpd /srv/tftpboot
#修改文件/etc/bootptab,內(nèi)容如下:
CrossBox11:ht=1: ha=0x123456789A00: ip=210.210.200.1: sm=255.255.255.252
主意:上述行中的“0x123456789A00”指開發(fā)箱的網(wǎng)卡物理地址(MAC),在具體操作過程中要替換成你的開發(fā)箱的網(wǎng)卡物理地址。
#重啟inetd,從而監(jiān)聽bootp和tftp服務(wù):
/etc/init.d/openbsd-inetd restart
四、常見問題及處理
問題1:在編譯binutils時(shí)報(bào)錯(cuò):WARNING: `makeinfo’ is missing on your system. You should only need it if you modified a `.texi’ or `.texinfo’ file, …處理:由電腦上安裝的texinfo軟件包版本太新導(dǎo)致。編輯源代碼根目錄下(/usr/local/arm/source/binutils- 2.18/)的configure程序,在configure里找到以下語句:’texinfo[^0-9]*([1-3][0-9]|4\. [4-9]|[5-9])’把它改為:’texinfo[^0-9]*([1-3] [0-9]|4\.[4-9]|4\.[1-9][0-9]*|[5-9])’
可以用下列的命令改掉:
sed -i ’s%[0-9]|4\.[4-9]|[5-9]%[0-9]|4\.[4-9]|4\.[1-9][0-9]*|[5-9]%g’ /usr/local/arm/source/binutils-2.18/configure
問題2:在第一階段編譯gcc的時(shí)候報(bào)如下錯(cuò)/usr/local/arm/4.2.1/arm-linux /bin/ld: crti.o: No such file: No such file or directory處理:在運(yùn)行配置configure命令的時(shí)候添加參數(shù)–disable-shared。比如我當(dāng)時(shí)經(jīng)過長時(shí)間的檢查發(fā)現(xiàn)雖然加了這個(gè) 參數(shù),但是這個(gè)參數(shù)與后面的參數(shù)連在一起了,中間少了一個(gè)空格。
問題3:在編譯glibc庫的時(shí)候報(bào)錯(cuò):undefined reference to `charmap_hash’和undefined reference to `locfile_hash’。處理:
vim ${TOP}/source/glibc-${GLIBC_VERSION}/locale/programs/locfile.c在頭文件包含語句下面增加一行:
const struct keyword_t * locfile_hash (register const char *str, register unsigned int len);
vim ${TOP}/source/glibc-${GLIBC_VERSION}/locale/programs/charmap.c在頭文件包含語句下面增加一行:
const struct keyword_t * charmap_hash (register const char *str, register unsigned int len);