cross compiler Toolchain 交叉編譯工具鏈 的建立
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
要為嵌入式Linux系統建立交叉編譯的toolchain。例子使用moblin,涉及的binutils,gcc,glibc和kernel的版本都是非常新的,碰到了很多問題,網上有很多資料,但是版本大多比較舊,不能解決目前最新版本的問題。每解決一個問題,後面又出現一個問題,有些沮喪,折騰了一個星期。下面是為目前新的版本建立交叉編譯環境的過程,以moblin環境為例。我想,這將是一篇很長的文章。
Moblin的開發環境應使用MIC2的moblin-chroot或者KVM的環境,我們只是想按傳統的方式自己來建立,目的是為了學習交叉編譯的構建。推薦資料:http://www.linuxfromscratch.org/lfs/view/development/index.html。
一、下載相關的介質
準備介質:從http://repo.moblin.org/moblin/development/core/source/下載相關的資源:
- kernel-2.6.29.1-18.1.moblin2.src.rpm
- binutils-2.19-10.26.moblin2.src.rpm
- gcc43-4.3.3_20081022-12.6.moblin2.src.rpm
- glibc-2.9-3.53.moblin2.src.rpm
請注意:在以前的交叉環境的編譯中,還需要 glibc-linuxthread……。Linuxkernel在2.6的版本支援thread,就是NPTL(New POSIX ThreadingLibray),在2.6.16的版本後比較穩定。因此不需要linuxthread。如果載入linuxthread,可能會引起標頭檔案定義的衝突。如果我們選擇比較新的版本來構造cross compiler,不要安裝linuxtrhead。
為了有一個好組織結構,我在workspace目錄下面根據O'Reilly的建議,建立了bootldr build-tools debug doc images kernel project sysapps tmp tools子目錄,我們將在build-tools下面編譯,將最終工具放置在tools下面。
在build-tools下面建立環境變數的指令碼檔案 myenv
$ vi myenv
#使用i586-linux,是因為intel的atom系列晶片的選擇,一般的x86可以使用i686-linux
export TARGET=i586-linux
export PREFIX=<dir-path>/tools
export TARGET_PREFIX=$PREFIX/$TARGET
export PATH=$PATH:$PREFIX/bin
$ chmod 744 myenv
$ . myenv
步驟二、初步建立binutil工具
1、準備原始碼:解壓縮和打補丁
在build-tools目錄下面設定build-binutil和src-binbuild兩個目錄,將binutils-2.19-10.26.moblin2.src.rpm放置在src-binutils目錄下面將rpm包開啟。
$ rpm2cpio binutils-2.19-10.26.moblin2.src.rpm |cpio -idv
獲取source code的tar.bz2和相關的補丁。
$ tar xvfj binutils-2.19.tar.bz2
$ cd binutils-2.19
打補丁如下。patch的引數有-p0,-p1等,差異只要是打補丁的位置。為了避免補丁誤打到我們的作業系統中,在整個交叉編譯環境建立的過程中,我們不要使用root的身份。
patch -p0 < ../binutils-skip-rpaths.patch
patch -p0 < ../cross-avr-omit_section_dynsym.patch
patch -p0 < ../s390-pic.patch
patch -p0 < ../unit-at-a-time.patch
patch -p0 < ../x86-64-biarch.patch
另外 moblin 還提供cross-avr-nesc-as.patch,但這個補丁所針對的檔案沒有找到,忽略它。
2、bintuils的編譯和安裝
進入build-binutils目錄,執行
$ ../src-binutils/binutils-2.19/configure --target=$TARGET --prefix=$PREFIX
- --target:我們的目標環境是atom的x86裝置,還可能是ARM、MIPS,和我們開發機器不一樣。這個引數用於高速配置指令碼對建立相應cross linker進行適配。
- --prefix:存放目錄
- --disable-nls:可以增加這個引數,This disables internationalization as i18n is not needed for the temporary tools.
- --disable-werror:This prevents the build from stopping in the event that there are warnings from the host's compiler.
在build-binutils目錄下面生成Makefile檔案,然後執行make , make install。完成,可以在$PREFIX/bin下面看到我們的新的binutil。
三、匯入kernel標頭檔案
1、將kernel原始碼解開,並打補丁
打補丁的指令碼如下:
$ patch -p1 < ../patch-2.6.29.1
patch -p1 < ../0001-drm-Split-out-the-mm-declarations-in-a-separate-hea.patch
patch -p1 < ../0002-drm-Add-a-tracker-for-global-objects.patch
patch -p1 < ../0003-drm-Export-hash-table-functionality.patch
patch -p1 < ../0007-drm-Add-unlocked-IOCTL-functionality-from-the-drm-r.patch
patch -p1 < ../linux-2.6.19-modesetting-by-default.patch
patch -p1 < ../linux-2.6.29-dont-wait-for-mouse.patch
patch -p1 < ../linux-2.6.29-drm-i915-Fix-LVDS-dither-setting.patch
patch -p1 < ../linux-2.6.29-drm-revert.patch
patch -p1 < ../linux-2.6.29-e100-add-support-for-82552-10-100-adapter.patch
patch -p1 < ../linux-2.6.29-enable-async-by-default.patch
patch -p1 < ../linux-2.6.29-even-faster-kms.patch
patch -p1 < ../linux-2.6.29-fast-initrd.patch
patch -p1 < ../linux-2.6.29-fast-kms.patch
patch -p1 < ../linux-2.6.29-flip-ide-net.patch
patch -p1 < ../linux-2.6.29-input-introduce-a-tougher-i8042.reset.patch
patch -p1 < ../linux-2.6.29-jbd-longer-commit-interval.patch
patch -p1 < ../linux-2.6.29-kms-after-sata.patch
patch -p1 < ../linux-2.6.29-msiwind.patch
patch -p1 < ../linux-2.6.29-pnv-agp.patch
patch -p1 < ../linux-2.6.29-pnv-drm.patch
patch -p1 < ../linux-2.6.29-pnv-fix-gtt-size.patch
patch -p1 < ../linux-2.6.29-pnv-fix-i2c.patch
patch -p1 < ../linux-2.6.29-psb-driver.patch
patch -p1 < ../linux-2.6.29-psb-S0i1_and_S0i3_OSPM_support.patch
patch -p1 < ../linux-2.6.29-retry-root-mount.patch
patch -p1 < ../linux-2.6.29-silence-acer-message.patch
patch -p1 < ../linux-2.6.29-sreadahead.patch
patch -p1 < ../linux-2.6.29-timberdale.patch
patch -p1 < ../linux-2.6.29-touchkit.patch
patch -p1 < ../linux-2.6.30-fix-async.patch
patch -p1 < ../linux-2.6.30-fix-suspend.patch
patch -p1 < ../linux-2.6-build-nonintconfig.patch
2、匯入標頭檔案
[[email protected] linux-2.6.29]$ make ARCH=x86 INSTALL_HDR_PATH=$TARGET_PREFIX headers_install
四、初始編譯器GCC的建立
開始只能建立支援C語言的引導編譯器,因為缺少C連結庫(glibc)的支援。等到glibc編譯好之後,可以重新編譯gcc並提供完整的C++支援,同樣我們建立src-gcc和build-gcc兩個目錄。
1、介質準備
打補丁如下:
patch -p0 < ../acats-timeout.patch
patch -p0 < ../boehm-gc-strict-aliasing.patch
patch -p0 < ../fpreserve-function-arguments43.patch
patch -p0 < ../gcc41-ia64-stack-protector.patch
patch -p0 < ../gcc41-java-slow_pthread_self.patch
patch -p0 < ../gcc41-ppc32-retaddr.patch
patch -p0 < ../gcc43-c++-builtin-redecl.patch
patch -p0 < ../gcc43-ecj-link.patch
patch -p0 < ../gcc43-java-debug-iface-type.patch
patch -p0 < ../gcc43-libgomp-omp_h-multilib.patch
patch -p0 < ../gcc43-pr34037.patch
patch -p0 < ../gcc43-pr36741-revert.patch
patch -p0 < ../gcc43-pr37189.patch
patch -p0 < ../gcc43-rename-info-files.patch
patch -p0 < ../gcc43-textdomain.patch
patch -p0 < ../gcc43-x86_64-va_start.patch
patch -p0 < ../gcc4-ppc64-m32-m64-multilib-only.patch
#patch -p0 < ../gcc-dir-version.patch 這個補丁打之後,version.o的編譯出現問題,忽略它
patch -p0 < ../gcc-sles-version.patch
patch -p0 < ../nvl423594.patch
patch -p0 < ../nvl425783.patch
patch -p0 < ../nvl425784.patch
patch -p0 < ../nvl425788.patch
patch -p0 < ../nvl425789.patch
patch -p0 < ../nvl425791.patch
patch -p0 < ../nvl425794.patch
patch -p0 < ../nvl425798-1.patch
patch -p0 < ../nvl425798-2.patch
patch -p0 < ../nvl425799.patch
patch -p0 < ../nvl425806.patch
patch -p0 < ../nvl426087.patch
patch -p0 < ../nvl428413.patch
patch -p0 < ../nvl434500.patch
patch -p0 < ../nvl436041.patch
patch -p0 < ../nvl440482.patch
cd ..
patch -p0 < nvl441016.patch 將裡面的20081002改為20081022,修訂目錄
cd gcc-4.3.3-20081022
patch -p0 < ../nvl464739.patch
2、編譯GCC
這個過程出現了很多問題。很多和後面glibc編譯相關
$../src-gcc/gcc-4.3.3-20081022/configure --target=$TARGET--prefix=$PREFIX --without-headers --enable-languages=c--disable-threads --disable-shared -disable-decimal-float
../../../gcc-4.3.1/libgcc/config/libbid/bid_decimal_globals.c: In function '__dfp_test_except':
../../../gcc-4.3.1/libgcc/config/libbid/bid_decimal_globals.c:64: error: 'FE_INEXACT' undeclared (first use in this function)
../../../gcc-4.3.1/libgcc/config/libbid/bid_decimal_globals.c:64: error: (Each undeclared identifier is reported only once
../../../gcc-4.3.1/libgcc/config/libbid/bid_decimal_globals.c:64: error: for each function it appears in.)
--disable-shared,forces GCC to link its internal libraries statically,沒有這個選項,會有 crti.o: No such file: No such file or directory collect2: ld returned 1 exit status--disable-multilib,用於x86_64,在這裡也可以使用。
然後執行:
make all-gcc
make install-gcc
make all-target-libgcc
make install-target-libgcc
很多資料中之有前面兩項,這隻建立了gcc,沒有建立libgcc.a,這樣會在glibc的編譯中出現-lgcc沒有找到的錯誤。報告:
……/build-tools/build-glibc/libc_pic.a
i586-linux-gcc -nostdlib -nostartfiles -r -o/home/wei/workspace/mywork/moblin/build-tools/build-glibc/elf/librtld.map.o'-Wl,-('/home/wei/workspace/mywork/moblin/build-tools/build-glibc/elf/dl-allobjs.os/home/wei/workspace/mywork/moblin/build-tools/build-glibc/libc_pic.a-lgcc '-Wl,-)'-Wl,-Map,/home/wei/workspace/mywork/moblin/build-tools/build-glibc/elf/librtld.mapT
/workspace/wei/mywork/moblin/tools/bin/../lib/gcc/i586-linux/4.3.3/../../../../i586-linux/bin/ld: cannot find -lgcc
在glibc的編譯中,還需要libgcc_eh.a(否則出現錯誤:-lgcc_eh沒有找到……bin/ld: cannot find -lgcc_eh),使用了--disable-shared的選項,將不會生成libgcc_eh.a,可以通過對libgcc.a的連結來實現。
[[email protected] build-gcc]$ ln -vs libgcc.a `i586-linux-gcc -print-libgcc-file-name | sed 's/libgcc/&_eh/'`
執行報告:
“/workspace/wei/mywork/moblin/tools/bin/../lib/gcc/i586-linux/4.3.3/libgcc_eh.a” -> “libgcc.a”
五、建立C庫(glibc)
1、準備介質
還是老方法,解壓和打補丁。
[[email protected] src-glibc]$ rpm2cpio glibc-2.9-3.53.moblin2.src.rpm | cpio -idv
[[email protected] src-glibc]$ tar xvfj glibc-20081113T2206.tar.bz2
[[email protected] src-glibc]$ tar xvfj glibc-fedora-20081113T2206.tar.bz2 -C glibc-20081113T2206
修改glibc-ia64-lib64.patch ,將libc/sysdeps改為sysdeps
[[email protected] glibc-20081113T2206]$ patch -p0 < ../glibc-ia64-lib64.patch
2、編譯協助檔案
如果我們在編譯的過程中出現下面的問題:
....../build-tools/build-glibc/elf/librtld.os: In function `_dl_tlsdesc_dynamic':
....../build-tools/src-glibc/glibc-20081113T2206/elf/../sysdeps/i386/dl-tlsdesc.S:131:undefined reference to `__i686.get_pc_thunk.bx'
增加一個補丁:glibc-dl-tlsedsc.patch,內容如下:
--- sysdeps/i386/dl-tlsdesc.S.org 2008-11-17 18:17:04.004203199 +0100
+++ sysdeps/i386/dl-tlsdesc.S 2008-11-17 18:18:28.029877701 +0100
@@ -128,8 +128,7 @@
.Lslow:
cfi_adjust_cfa_offset (28)
movl %ebx, 16(%esp)
- call __i686.get_pc_thunk.bx
- addl $_GLOBAL_OFFSET_TABLE_, %ebx
+ LOAD_PIC_REG(bx)
call [email protected]
movl 16(%esp), %ebx
jmp .Lret
我們還需要準備兩個檔案:
[[email protected] build-glibc]$ echo "libc_cv_forced_unwind=yes" > config.cache
[[email protected] build-glibc]$ echo "libc_cv_c_cleanup=yes" >> config.cache
[[email protected] build-glibc]$ echo "libc_cv_gnu89_inline=yes" >> config.cache
當然這些引數也可以做為configure的引數加上。頭兩個是為了順利使用configure指令碼生成Makefile檔案,而
libc_cv_gnu89_inline=yes是為了解決編譯中重複定義的出現,例如:
stat.c:50: 錯誤:‘__stat’重定義
/workspace/wei/mywork/moblin/build-tools/src-glibc/glibc-20081113T2206/elf/../nptl/sysdeps/pthread/allocalim.h:27:multiple definition of `__libc_use_alloca'include/alloca.h:extern int__libc_use_alloca (size_t size) __attribute__ ((const));
我記得是即使加上這個配置,在第一編譯的也會出現什麼__stat __mknod的重複定義的問題,不要使同make clean之類,直接刪除build-glibc,重現再來一次就可以解決。
第二個檔案:
$ echo "CFLAGS += -march=i486 -mtune=native" > configparms
也可以使用i686,否則會出現
/home/wei/workspace/mywork/moblin/build-tools/build-glibc/libc_pic.os: In function `__libc_fork':
/workspace/wei/mywork/moblin/build-tools/src-glibc/glibc-20081113T2206/posix/../nptl/sysdeps/unix/sysv/linux/i386/../fork.c:79:undefined reference to `__sync_bool_compare_and_swap_4'
/home/wei/workspace/mywork/moblin/build-tools/build-glibc/libc_pic.os: In function `nscd_getpw_r':
/workspace/wei/mywork/moblin/build-tools/src-glibc/glibc-20081113T2206/nscd/nscd_getpw_r.c:232:undefined reference to `__sync_fetch_and_add_4'
這是因為Glibc已經不再支援i386,需要定義一個i486以上的版本。
3、編譯和安裝
$../src-glibc/glibc-20081113T2206/configure--host=$TARGET --prefix=$PREFIX --enable-add-ons--with-headers=$TARGET_PREFIX/include --cache-file=config.cache--disable-profile --build=i686-pc-linux-gnu
- --enable-add-ons,允許增加NPTL的執行緒庫
$ make
$ make install
六、進行完整的編譯
有了Glibc後,可以進行完整編譯
1、重新建立binutils
$ confiure --prefix=$PREFIX --target=$TARGET --disable-nls --with-lib-path=$TARGET/lib --with-sysroot=$TARGET
如果沒有--with-sysroot來重新重新編譯binutils,那麼在gcc的完整編譯中,會引導到系統的lib中,很多了路徑會出現問題。
2、重新建立gcc
$ configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++ --enable-shared
$ make
$ make install
不容易啊,終於搞定了。