powerpc交叉編譯
A. 如何在 Intel x86 伺服器上構建 IBM Powerlinux 應用程序 第2頁
環境和配置
測試環境有一個 IBM Flex System® 組成,該系統有多個 IBM Flex System x240 計算節點和兩個基於 IBM POWER7 處理器的節點(一個 Flex System p260 和一個 Flex System p460)。出於本項目的目的,我使用一個 Flex system x240 計算節點來交叉編譯 Apache httpd 和 Postgresql。構建二進製程序後,我將它們轉移到 Flex System p460 計算節點。圖 7 顯示了 IBM Flex System 測試環境的布局圖。
圖 7. IBM Flex System 測試環境
以下是我的系統配置、操作系統級別和其他與系統設置相關的信息。
Flex System x240 計算節點
用於交叉編譯二進製程序的 Intel 節點僅需要足夠的處理能力和內存,以便能夠構建 Power 二進製程序。配置如下:
基於內核的虛擬機 (KVM) 管理程序 Red Hat 6.5
32 個處理器
64 GB 內存
IBM Storwize® V7000 存取區域網路 (SAN) 連接磁碟
KVM Guest 系統
Red Hat Enterprise Linux 6.5
4 個處理器
16 GB 內存
一個 virtio 磁碟:100 GB
一個配置為 br0 的虛擬網路介面卡 (NIC)
所有其他 KVM Guest 系統都已關閉,以消除破壞環境的任何可能性。
Flex System p440 計算節點
Flex System p440 計算節點包含多個邏輯分區 (LPAR),其中一個配置為測試伺服器。PowerLinux 伺服器配置如下:
IBM PowerVM® 來賓
Red Hat Enterprise Linux 6.5
8 個處理器(專用)
32 GB 內存
Storwize V7000 SAN 連接磁碟 (50 GB)
通過虛擬 I/O 伺服器 (VIOS) 共享的乙太網適配器
LPAR 配置
最小內存:256 MB
目標內存:32 GB
最大內存:64 GB
最少處理器數:8
目標處理器數:8
最大處理器數:32
處理模式:專用
專用內存
虛擬乙太網適配器(通過 VIOS 建立)
適配器 ID:2
VLAN ID:1
需要此適配器來激活虛擬伺服器:已選擇
以下是我運行的其他一些命令:
# ppc64_cpu --frequency
min: 3.56 GHz (cpu 28)
max: 3.56 GHz (cpu 4)
avg: 3.56 GHz
# ppc64_cpu --cores-present
Number of cores present = 8
# sysctl.conf
kernel.sem = 250 32000 32 12288
使用 toolchain 構建應用程序
通常,構建開源發行版的過程是一個迭代過程。如果您很幸運的話,該過程可能已構建完成。不幸的是,因為大多數開源發行版都構建於 x86 伺服器之上,所以在嘗試為不同架構(比如 IBM Power 架構)構建它們時可能遇到問題。
如果在 Power 上構建開源包時遇到問題,只需在互聯網上搜索類似情形,查看這些已報告的問題是否與您的經歷密切相關。如果是相關的,那麼在大多數情況下,您可以找到如何解決該問題的建議。
對我而言,盡管為配置腳本選擇正確參數後,postgresql 很好地構建完成了,但 apache httpd 沒那麼幸運。接下來的幾節將介紹為 Power 架構構建 apache httpd 所需的修復程序。
交叉編譯器經驗
編寫本文時,我使用的交叉編譯器版本是一個僅供 IBM 內部使用的版本,它專為修復我在測試期間遇到的一個錯誤而構建。讀者可以下載 AT 7.0-5 版,它是最新的交叉編譯器(在發表本文時),擁有接下來的幾段中描述的錯誤的修復程序。
在我嘗試交叉編譯 apr-1.5.1 源代碼發行版時,我看到了以下編譯器消息。
"sorry - this program has been built without plugin support"
按照我在互聯網上搜索可能的幫助和解決方案的建議,我找到多個鏈接提到編譯器需要使用 「plugin enabled」 選項來構建。我向 toolchain 支持小組報告了此問題,toolchain 維護人員很快就回復了我,為我提供了一個使用 plugin enabled 選項構建的修改版本。請注意,toolchain 的交叉編譯器和原生編譯器版本都需要使用 plugin enabled 選項構建。我能夠在獲得擁有該修復程序的 toolchain 版本後繼續工作。
這是我使用 PowerLinux toolchain 的第一次經歷。
交叉編譯 httpd 2.4.3
要交叉編譯 Apache httpd,需要使用另外 3 個包。它們是:apr、apr-util 和 pcre。找到下載最新包的位置後,開始使用 toolchain 交叉編譯器在 x86 伺服器上構建它們。
我構建 apr-1.5.1 時遇到的問題是構建 gen_test_char.o 模塊。請參閱 ASF Bugzilla – 錯誤 51257 了解有關的更多細節。我修改了 Makefile.in 文件(如下所示)並運行 buildconf 腳本,以便將更改包含在配置腳本中。
對 Makefile.in 的修改如下所示:
[root@stgisv240 apr-1.5.1]# diff -u Makefile.in ../../apr-1.5.1/Makefile.in
--- Makefile.in 2014-03-17 10:10:26.000000000 -0500
+++ ../../apr-1.5.1/Makefile.in 2014-07-03 13:36:11.125013781 -0500
@@ -46,7 +46,6 @@
CLEAN_TARGETS = apr-config.out apr.exp exports.c export_vars.c .make.dirs build/apr_rules.out tools/gen_test_char@EXEEXT@ - tools/gen_test_char.o tools/gen_test_char.lo \
include/private/apr_escape_test_char.h
DISTCLEAN_TARGETS = config.cache config.log config.status include/apr.h include/arch/unix/apr_private.h @@ -132,10 +131,9 @@
make_tools_dir:
$(APR_MKDIR) tools
-OBJECTS_gen_test_char = tools/gen_test_char.lo $(LOCAL_LIBS)
-tools/gen_test_char.lo: make_tools_dir
-tools/gen_test_char@EXEEXT@:$(OBJECTS_gen_test_char)
- $(LINK_PROG) $(OBJECTS_gen_test_char) $(ALL_LIBS)
+tools/gen_test_char@EXEEXT@: make_tools_dir
+tools/gen_test_char@EXEEXT@: tools/gen_test_char.c
+ $(BUILD_CC) $(CFLAGS_FOR_BUILD) $< -o $@
include/private/apr_escape_test_char.h: tools/gen_test_char@EXEEXT@
$(APR_MKDIR) include/private
修改 Makefile.in 文件後,我運行 buildconf 來創建了一個新配置腳本。下一段將介紹用於配置腳本的參數和變數。順便說一下,我是根據其他嘗試在其他平台(比如 ARM)上交叉編譯 Apache httpd 及其組件的開發人員的建議,為配置腳本選擇配置參數的。
以下是我在 x86 伺服器上運行 apr-1.5.1 組件的配置腳本時,使用的參數和環境變數。
# Config script using Power Linux toolchain on x86
BUILD_CC=gcc
CC_FOR_BUILD=gcc
CC=powerpc64-linux-gcc
CPP=powerpc64-linux-cpp
AS=powerpc64-linux-as
AR=powerpc64-linux-ar
RANLIB=powerpc64-linux-gcc-ranlib
CXX=powerpc64-linux-c++
LD=powerpc64-linux-ld
STRIP=powerpc64-linux-strip
export CC CPP AS ASCPP AR RANLIB CXXCPP CXX LD STRIP CFLAGS LDFLAGS CC_FOR_BUILD
./configure --prefix=/tmp/usr/local/apr --host=powerpc64-linux ac_cv_file__dev_zero=no
ac_cv_func_setpgrp_void=no apr_cv_tcp_nodelay_with_cork=no ac_cv_sizeof_struct_iovec=1
BUILD_CC=gcc make install
我在 Power 伺服器上了略加修改的相同發行版。請注意,用於 Power 伺服器的 PowerLinux toolchain 使用了具有類似命名的可執行程序,比如從原生 cpp 和 binutils 包安裝的 cpp 和 ld。修改腳本中的 CPP 和 LD 變數,如下所示。確保 Power toolchain 的路徑首先傳入您的 PATH 環境中。
以下是我在 Power 伺服器上運行 apr-1.5.1 的配置腳本時使用的參數和環境變數。
# Config script using PowerLinux toolchain on Power
BUILD_CC=gcc
CC_FOR_BUILD=gcc
CC=powerpc64-linux-gcc
CPP=cpp # Note the difference
AS=powerpc64-linux-as
AR=powerpc64-linux-ar
RANLIB=powerpc64-linux-gcc-ranlib
CXX=powerpc64-linux-c++
LD=ld # Note the difference
STRIP=powerpc64-linux-strip
#CFLAGS="-mcpu=440fp -mtune=440fp --sysroot $SYSROOT"
#LDFLAGS=-L$SYSROOT/lib
export CC CPP AS ASCPP AR RANLIB CXXCPP CXX LD STRIP CFLAGS LDFLAGS CC_FOR_BUILD
./configure --prefix=/home/usr/local/apr ac_cv_file__dev_zero=no
ac_cv_func_setpgrp_void=no apr_cv_tcp_nodelay_with_cork=no ac_cv_sizeof_struct_iovec=1
ac_cv_struct_rlimit=yes
BUILD_CC=gcc make install
以下是我在 x86 伺服器上運行 apr-util-1.5.3 組件的配置腳本時使用的參數和環境變數。
# Configure script for apr-util-1.5.3 on x86
BUILD_CC=gcc
CC_FOR_BUILD=gcc
CC=powerpc64-linux-gcc
CPP=powerpc64-linux-cpp
AS=powerpc64-linux-as
AR=powerpc64-linux-ar
RANLIB=powerpc64-linux-gcc-ranlib
CXX=powerpc64-linux-c++
LD=powerpc64-linux-ld
STRIP=powerpc64-linux-strip
export CC CPP AS ASCPP AR RANLIB CXXCPP CXX LD STRIP CFLAGS LDFLAGS CC_FOR_BUILD
./configure --prefix=/tmp/usr/local/apr --host=powerpc64-linux --with-
apr=/tmp/usr/local/apr ac_cv_file__dev_zero=no ac_cv_func_setpgrp_void=no
apr_cv_tcp_nodelay_with_cork=no ac_cv_sizeof_struct_iovec=1
以下是我在 Power 伺服器上運行 apr-util-1.5.3 組件的配置腳本時使用的參數和環境變數。
# Configure script for apr-util-1.5.3 on Power
BUILD_CC=gcc
CC_FOR_BUILD=gcc
CC=powerpc64-linux-gcc
CPP=cpp
AS=powerpc64-linux-as
AR=powerpc64-linux-ar
RANLIB=powerpc64-linux-gcc-ranlib
CXX=powerpc64-linux-c++
LD=ld
STRIP=powerpc64-linux-strip
export CC CPP AS ASCPP AR RANLIB CXXCPP CXX LD STRIP CFLAGS LDFLAGS CC_FOR_BUILD
./configure --prefix=/home/usr/local/apr --host=powerpc64-linux --with-
apr=/tmp/usr/local/apr ac_cv_file__dev_zero=no ac_cv_func_setpgrp_void=no
apr_cv_tcp_nodelay_with_cork=no ac_cv_sizeof_struct_iovec=1
以下是我在 x86 伺服器上運行 httpd 組件的配置腳本時使用的參數和環境變數。
# Configure script for httpd 2.4.3 on x86
CC_FOR_BUILD=gcc
CC=powerpc64-linux-gcc
CPP=powerpc64-linux-cpp
AS=powerpc64-linux-as
AR=powerpc64-linux-ar
RANLIB=powerpc64-linux-gcc-ranlib
CXX=powerpc64-linux-c++
LD=powerpc64-linux-ld
STRIP=powerpc64-linux-strip
export CC CPP AS ASCPP AR RANLIB CXXCPP CXX LD STRIP CFLAGS LDFLAGS CC_FOR_BUILD
./configure --prefix=/tmp/usr/local --host=ppc64 ap_cv_void_ptr_lt_long=no --with-
pcre=/tmp/usr/local/bin/pcre-config --with-apr=/tmp/usr/local/apr --with-mpm=worker--
with-apr-util=/tmp/usr/local/apr/bin/apu-1-config
以下是我在 Power 伺服器上運行 httpd 組件的配置腳本時使用的參數和環境變數。
# Configure script for httpd 2.4.3 on Power
CC_FOR_BUILD=gcc
CC=powerpc64-linux-gcc
CPP=cpp
AS=powerpc64-linux-as
#ASCPP=powerpc-apm-linux-gnu-as
AR=powerpc64-linux-ar
RANLIB=powerpc64-linux-gcc-ranlib
#CXXCPP=powerpc-apm-linux-gnu-cpp
CXX=powerpc64-linux-c++
LD=/opt/at7.0-5-rc1/bin/ld
STRIP=powerpc64-linux-strip
#CFLAGS="-mcpu=440fp -mtune=440fp --sysroot $SYSROOT"
#LDFLAGS=-L$SYSROOT/lib
export CC CPP AS ASCPP AR RANLIB CXXCPP CXX LD STRIP CFLAGS LDFLAGS CC_FOR_BUILD
./configure --prefix=/home/usr/local --host=ppc64 ap_cv_void_ptr_lt_long=no--with-
pcre=/home/usr/local/bin/pcre-config --with-apr=/home/usr/local/apr --with-mpm=worker--
with-apr-util=/home/usr/local/apr/bin/apu-1-config
交叉編譯 PostgreSQL 9.4.3
不同於之前構建 httpd 所需的源代碼發行版,我在交叉編譯 PostgreSQL 時未遇到問題。PostgreSQL 是使用以下配置腳本來構建的。
以下是我在 x86 伺服器上運行 PostgresSQL 的配置腳本時使用的參數和環境變數。
# Configure script for postgresql-9.3.4 on x86
CC=powerpc64-linux-gcc
CPP=powerpc64-linux-cpp
AS=powerpc64-linux-as
AR=powerpc64-linux-ar
RANLIB=powerpc64-linux-gcc-ranlib
CXX=powerpc64-linux-c++
D=powerpc64-linux-ld
STRIP=powerpc64-linux-strip
export CC CPP AS ASCPP AR RANLIB CXXCPP CXX LD STRIP CFLAGS LDFLAGS CC_FOR_BUILD
./configure --prefix=/tmp/usr/local --host=powerpc64-linux --without-readline --without-zlib
與 Apache 配置腳本一樣,您可以注意到針對 Power 伺服器 toolchain 使用了具有類似命名的可執行程序,比如從原生 cpp和 binutils 包安裝的 cpp 和 ld。修改腳本中的 CPP 和 LD 變數,如下所示。確保 toolchain 的路徑首先傳入您的 PATH 環境中。
以下是我在 Power 伺服器上運行 PostgresSQL 的配置腳本時使用的參數和環境變數。
# Configure script for postgresql-9.3.4 on Power
CC=powerpc64-linux-gcc
CPP=cpp
AS=powerpc64-linux-as
AR=powerpc64-linux-ar
RANLIB=powerpc64-linux-gcc-ranlib
CXX=powerpc64-linux-c++
LD=powerpc64-linux-ld
STRIP=powerpc64-linux-strip
export CC CPP AS ASCPP AR RANLIB CXXCPP CXX LD STRIP CFLAGS LDFLAGS CC_FOR_BUILD
./configure --prefix=/home/usr/local --host=powerpc64-linux --without-readline --without-zlib
結束語
toolchain 交叉編譯器的實際價值在於,開發人員可在他們熟悉的開發平台上(在大多數情況下是 x86)編譯和構建 Power Architecture 應用程序。從我們的用例中可以看到,toolchain 可生成像原生編譯的應用程序一樣高效地執行的二進制可執行程序和庫。而且,交叉編譯的庫與原生編譯的應用程序兼容。最後但同樣重要的是,交叉編譯的應用程序可在本地調試以及使用 gdb 調試器遠程調試。
PowerLinux toolchain 與在 x86 平台上使用原生 Linux toolchain 沒什麼不同。希望本文能讓讀者很好地了解 PowerLinux toolchain 的特性和功能。
B. 如何為嵌入式開發建立交叉編譯環境
下面我們將以建立針對arm的交叉編譯開發環境為例來解說整個過程,其他的體系結構與這個相類似,只要作一些對應的改動。我的開發環境是,宿主機 i386-redhat-7.2,目標機 arm。
這個過程如下
1. 下載源文件、補丁和建立編譯的目錄
2. 建立內核頭文件
3. 建立二進制工具(binutils)
4. 建立初始編譯器(bootstrap gcc)
5. 建立c庫(glibc)
6. 建立全套編譯器(full gcc)
下載源文件、補丁和建立編譯的目錄
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
如果你選的glibc的版本號低於2.2,你還要下載一個叫glibc-crypt的文件,例如glibc-crypt-2.1.tar.gz。 Linux 內核你可以從www.kernel.org 或它的鏡像下載。
Binutils、gcc和glibc你可以從FSF的ftp站點ftp://ftp.gun.org/gnu/ 或它的鏡像去下載。 在編譯glibc時,要用到 Linux 內核中的 include 目錄的內核頭文件。如果你發現有變數沒有定義而導致編譯失敗,你就改變你的內核版本號。例如我開始用linux-2.4.25+vrs2,編譯glibc-2.2.3 時報 BUS_ISA 沒定義,後來發現在 2.4.23 開始它的名字被改為 CTL_BUS_ISA。如果你沒有完全的把握保證你改的內核改完全了,就不要動內核,而是把你的 Linux 內核的版本號降低或升高,來適應 glibc。
Gcc 的版本號,推薦用 gcc-2.95 以上的。太老的版本編譯可能會出問題。Gcc-2.95.3 是一個比較穩定的版本,也是內核開發人員推薦用的一個 gcc 版本。
如果你發現無法編譯過去,有可能是你選用的軟體中有的加入了一些新的特性而其他所選軟體不支持的原因,就相應降低該軟體的版本號。例如我開始用 gcc-3.3.2,發現編譯不過,報 as、ld 等版本太老,我就把 gcc 降為 2.95.3。 太新的版本大多沒經過大量的測試,建議不要選用。
回頁首
2. 建立工作目錄
首先,我們建立幾個用來工作的目錄:
在你的用戶目錄,我用的是用戶liang,因此用戶目錄為 /home/liang,先建立一個項目目錄embedded。
$pwd
/home/liang
$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=/home/liang/embedded
$export TARGET=arm-linux
$export PREFIX=$PRJROOT/tools
$export TARGET_PREFIX=$PREFIX/$TARGET
$export PATH=$PREFIX/bin:$PATH
如果你不慣用環境變數的,你可以直接用絕對或相對路徑。我如果不用環境變數,一般都用絕對路徑,相對路徑有時會失敗。環境變數也可以定義在.bashrc文件中,這樣當你logout或換了控制台時,就不用老是export這些變數了。
體系結構和你的TAEGET變數的對應如下表
你可以在通過glibc下的config.sub腳本來知道,你的TARGET變數是否被支持,例如:
$./config.sub arm-linux
arm-unknown-linux-gnu
在我的環境中,config.sub 在 glibc-2.2.3/scripts 目錄下。
網上還有一些 HOWTO 可以參考,ARM 體系結構的《The GNU Toolchain for ARM Target HOWTO》,PowerPC 體系結構的《Linux for PowerPC Embedded Systems HOWTO》等。對TARGET的選取可能有幫助。
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/ 下載到這些補丁。
再將你下載的 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
接下來為你的交叉編譯環境建立你的內核頭文件的鏈接
$mkdir -p $TARGET_PREFIX/include
$ln -s $PRJROOT/kernel/linux-2.4.21/include/linux $TARGET_PREFIX/include/linux
$in -s $PRJROOT/kernel/linux-2.4.21/include/asm-arm $TARGET_PREFIX/include/asm
也可以把 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
回頁首
建立二進制工具(binutils)
binutils是一些二進制工具的集合,其中包含了我們常用到的as和ld。
首先,我們解壓我們下載的binutils源文件。
$cd $PRJROOT/build-tools
$tar -xvjf binutils-2.10.1.tar.bz2
然後進入build-binutils目錄配置和編譯binutils。
$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-objmp 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-obj arm-linux-size
我們來解釋一下上面生成的可執行文件都是用來干什麼的
add2line - 將你要找的地址轉成文件和行號,它要使用 debug 信息。
Ar-產生、修改和解開一個存檔文件
As-gnu 的匯編器
C++filt-C++ 和 java 中有一種重載函數,所用的重載函數最後會被編譯轉化成匯編的標號,c++filt 就是實現這種反向的轉化,根據標號得到函數名。
Gasp-gnu 匯編器預編譯器。
Ld-gnu 的連接器
Nm-列出目標文件的符號和對應的地址
Obj-將某種格式的目標文件轉化成另外格式的目標文件
Objmp-顯示目標文件的信息
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 前,我們先要改一個文件 $PRJROOT/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
你如果沒定義 -Dinhibit,編譯時將會報如下的錯誤
../../gcc-2.95.3/gcc/libgcc2.c:41: stdlib.h: No such file or directory
../../gcc-2.95.3/gcc/libgcc2.c:42: unistd.h: No such file or directory
make[3]: *** [libgcc2.a] Error 1
make[2]: *** [stmp-multilib-sub] Error 2
make[1]: *** [stmp-multilib] Error 1
make: *** [all-gcc] Error 2
如果沒有定義 -D__gthr_posix_h,編譯時會報如下的錯誤
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[2]: *** [stmp-multilib-sub] Error 2
make[1]: *** [stmp-multilib] Error 1
make: *** [all-gcc] Error 2
還有一種與-Dinhibit同等效果的方法,那就是在你配置configure時多加一個參數-with-newlib,這個選項不會迫使我們必須使用newlib。我們編譯了bootstrap-gcc後,仍然可以選擇任何c庫。
接著就是配置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
這條命令中的 -target、--prefix 和配置 binutils 的含義是相同的,--without-headers 就是指不需要頭文件,因為是交叉編譯工具,不需要本機上的頭文件。-enable-languages=c是指我們的 boot-gcc 只支持 c 語言。--disable-threads 是去掉 thread 功能,這個功能需要 glibc 的支持。
接著我們編譯並安裝 boot-gcc
$make all-gcc
$make install-gcc
我們來看看 $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 的頭文件。
回頁首
建立 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
然後你還要修改 libc.so 文件
將
GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a)
改為
GROUP ( libc.so.6 libc_nonshared.a)
這樣連接程序 ld 就會在 libc.so 所在的目錄查找它需要的庫,因為你的機子的/lib目錄可能已經裝了一個相同名字的庫,一個為編譯可以在你的宿主機上運行的程序的庫,而不是用於交叉編譯的。
回頁首
建立全套編譯器(full gcc)
在建立boot-gcc 的時候,我們只支持了C。到這里,我們就要建立全套編譯器,來支持C和C++。
$cd $PRJROOT/build-tools/build-gcc
$../gcc-2.95.3/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++
--enable-languages=c,c++ 告訴 full gcc 支持 c 和 c++ 語言。
然後編譯和安裝你的 full gcc
$make all
$make install
我們再來看看 $PREFIX/bin 裡面多了哪些東西
$ls $PREFIX/bin
你會發現多了 arm-linux-g++ 、arm-linux-protoize 和 arm-linux-c++ 幾個文件。
G++-gnu的 c++ 編譯器。
Protoize-與Unprotoize相反,將K&R C的源碼轉化為ANSI C的形式,函數原型中加入參數類型。
C++-gnu 的 c++ 編譯器。
到這里你的交叉編譯工具就算做完了,簡單驗證一下你的交叉編譯工具。
用它來編譯一個很簡單的程序 helloworld.c
#include <stdio.h>
int main(void)
{
printf("hello world\n");
return 0;
}
$arm-linux-gcc helloworld.c -o helloworld
$file helloworld
helloworld: ELF 32-bit LSB executable, ARM, version 1,
dynamically linked (uses shared libs), not stripped
上面的輸出說明你編譯了一個能在 arm 體系結構下運行的 helloworld,證明你的編譯工具做成功了。
轉載僅供參考,版權屬於原作者
