嵌入式軟件開發之------淺析製作ARMv8 native gcc 編譯器(十)

導讀:在學習嵌入式的時候,需要搭建 交叉編譯 環境,也就是說在PC/服務器上編譯嵌入式產品用的軟件。或者具體點說,很多人開發的產品是基於ARM、MIPS的嵌入式設備,在自己的電腦上或服務器(通常是X86機器)使用交叉編譯工具(gcc),來編譯產品軟件。網上也有很多交叉編譯工具鏈的製作,甚至還有 crosstool-ng  用來製作 交叉編譯用的gcc,如果不想自己製作,還可以下載別人製作好的工具鏈,比如ARM 用的 Linaro Toolchain帶來了很多的方便。目前嵌入式領域ARM已經佔領了大部分的份額,之前ARMv7時代,嵌入式設備性能弱,內存小,顯然在嵌入式設備上安裝gcc並不是一個明智的選擇,而ARMv8已經不是ARMv7的簡單升級,甚至可以理解爲全新的架構,只不過兼容ARMv7的指令集而已。ARMv8重新設計了架構,很明顯爲了高性能和通用計算做了很多優化,也漸漸的出現了ARM版本的服務器,發展勢頭不容小覷。當前接觸過的高端ARMv8處理器,單核和多核性能已經超過了intel部分中低端處理器。爲了更深的研究ARMv8架構,自己買了個NanoPi M4的開發板,主控芯片用的RK3399,兩個A72加4個A53,剛拿到手就突發奇想,爲何不將gcc安裝到自己的開發板裏呢?然後百度谷歌了一下,幾乎都是cross compile的製作過程,沒有找到製作ARM直接使用的gcc,一下就激起了興趣,就喜歡做別人沒做過的事,享受探索未知的過程。下面就是製作過程。

一、基礎知識

    編譯過 交叉工具鏈 (太多博客教程了)的人 configure的時候遇到三個很基本的設置,build、host和target。三個設置的含義如下:

build:當前編譯gcc代碼的機器,通常都是x86,我自己就是用win10+vmware+ubuntu18.04

host :編譯出來的gcc'運行在哪個平臺上

target:用編譯出來的gcc再編譯的軟件運行在哪個平臺上

三個詞確實有點繞,就拿編譯交叉工具鏈 aarch64-linux-gnu-xx來解釋,當然是用x86的機器來編譯生成aarch64-linux-gnu-xx(build),生成的aarch64-linux-gnu-xx當然也是運行在x86的平臺上(host),用aarch64-linux-gnu-xx編譯的軟件是運行在aarch64上的(target)。很顯然交叉工具鏈是 build=host=x86,target=aarch64,這種形式成爲cross gcc,顯然要編譯aarch64上的gcc,build=x86,host=target=aarch64,這種形式成爲native gcc。build通常無需配置,configure的時候自動檢測。所以編譯native gcc只是cross gcc 最大的區別是host不一樣。corss gcc 所需要的binutild,kernel header,gmp,mpfr,mpc,glibc,native gcc 一樣需要。事實上,我在製作native gcc的時候,就是將cross gcc的製作過程將host 改成了aarch64-linux-gnu 而已。

而cross gcc 的編譯過程從buildroot的編譯過程中摘抄出來的,也並沒有詳細瞭解每一個配置項的含義。

本人的編譯環境是win10+vmware+ubuntu18.04,其中ubuntu需要安裝一些工具和庫,如果遇到缺少一些庫出現的錯誤,也很容易百度到。

源代碼用的:linux4.4、gcc-linaro-7.4、gmp-6.1.2、mpfr-3.1.6、mpc-1.0.3、glibc-2.26,其中交叉編譯工具鏈gcc-linaro-7.5。(想想爲什麼用交叉工具鏈?因爲編譯出來的gcc是要運行在ARM平臺上啊,難不成指望x86的gcc編譯出來的gcc能在ARM上運行?)

二、製作過程

1、建立基本的文件目錄

其實建立文件目錄只是爲了更好的區分安裝路徑,並沒有什麼規則,只要自己分的清,怎麼着都行,像我自己建立的nativetool文件,然後分別建立了glibc、kernel_headers、src、target、tmp

glibc是安裝glibc的路徑,kernel_headers 是linux頭文件的路徑,src是存放用到的源代碼的路徑,target是編譯生成gcc的安裝路徑,tmp是gmp、mpfr和mpc的安裝路徑。

surpass@ubuntu:~/share/nativetool$ ls
glibc  kernel_headers  src  target  tmp

注意後面的步驟make -jx根據自己的CPU核數和內存大小來定,我自己電腦設置的4核8g內存,用make -j4能過,開始用的make -j ,編譯gcc代碼的時候,很快內存耗盡,又分配10G的swap空間也很快耗盡,如果出現內存耗盡的情況,檢查是否設置的編譯線程數太多了。

2、安裝linux的頭文件

編譯native gcc的過程中,需要依賴linux的頭文件,你的ARM平臺上用的哪個版本的linux就是用哪個版本的linux頭文件,下面是安裝頭文件路徑的命令(切換到linux代碼路徑下,同時也將頭文件安裝到了glibc中)。

make mrproper
make arch=aarch64 headers_check
make ARCH=arm64 INSTALL_HDR_PATH=/home/surpass/share/nativetool/glibc/usr headers_install
make ARCH=arm64 INSTALL_HDR_PATH=/home/surpass/share/nativetool/kernel_headers headers_install

3、編譯安裝binutils

切換到binutils代碼路徑下,

配置:

AR="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ar" \
AS="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-as" \
LD="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ld" \
NM="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-nm" \
CC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
GCC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
CXX="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-g++" \
CPP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-cpp" \
OBJCOPY="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objcopy" \
RANLIB="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ranlib" \
AR_FOR_BUILD="/usr/bin/ar" \
AS_FOR_BUILD="/usr/bin/as" \
CC_FOR_BUILD="/usr/bin/gcc" \
GCC_FOR_BUILD="/usr/bin/gcc" \
CXX_FOR_BUILD="/usr/bin/g++" \
LD_FOR_BUILD="/usr/bin/ld" \
CPPFLAGS="-I/home/surpass/share/nativetool/tmp/include" \
CFLAGS="-O2 -I/home/surpass/share/nativetool/tmp/include" \
CXXFLAGS="-O2 -I/home/surpass/share/nativetool/tmp/include" \
LDFLAGS="-L/home/surpass/share/nativetool/tmp/lib -Wl,-rpath,/home/surpass/share/nativetool/tmp/lib" \
INTLTOOL_PERL=/usr/bin/perl \
MAKEINFO=true \
CONFIG_SITE=/dev/null \
./configure \
--prefix="/home/surpass/share/nativetool/target/usr" \
--enable-shared \
--disable-static \
--disable-gtk-doc \
--disable-gtk-doc-html \
--disable-doc \
--disable-docs \
--disable-documentation \
--disable-debug \
--with-xmlto=no\
--with-fop=no \
--disable-dependency-tracking  \
--disable-multilib \
--disable-werror \
--host=aarch64-zlk-linux \
--target=aarch64-zlk-linux-gnu \
--disable-shared --enable-static \
--with-sysroot=/home/surpass/share/nativetool/glibc/ \
--enable-poison-system-directories \
--disable-sim \
--disable-gdb \

編譯:
make -j4

安裝:
make -j4 install

3、編譯安裝gmp、mpfr和gmp

配置項和編譯命令都一樣,所以就放在一起

配置:

AR="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ar" \
AS="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-as" \
LD="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ld" \
NM="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-nm" \
CC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
GCC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
CXX="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-g++" \
CPP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-cpp" \
OBJCOPY="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objcopy" \
RANLIB="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ranlib" \
CPPFLAGS="-I/home/surpass/share/nativetool/tmp/include" \
CFLAGS="-O2 -I/home/surpass/share/nativetool/tmp/include" \
CXXFLAGS="-O2 -I/home/surpass/share/nativetool/tmp/include" \
LDFLAGS="-L/home/surpass/share/nativetool/tmp/lib -Wl,-rpath,/home/surpass/share/nativetool/tmp/lib" \
INTLTOOL_PERL=/usr/bin/perl \
CONFIG_SITE=/dev/null \
./configure \
--prefix="/home/surpass/share/nativetool/tmp/" \
--host=aarch64-zlk-linux   \
--target=aarch64-zlk-linu

編譯:
make -j4

安裝:
make -j4 install 

4、編譯安裝glibc

編譯glibc的時候不要直接在glibc代碼路徑下配置,另外建立一個文件夾來配置編譯,我是在glibc'源代碼下建立了build文件夾,然後切換到build下

配置:

AR="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ar" \
AS="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-as" \
LD="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ld" \
NM="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-nm" \
CC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
GCC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
CPP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-cpp" \
CXX="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-g++" \
FC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gfortran" \
F77="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gfortran" \
RANLIB="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ranlib" \
READELF="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-readelf" \
STRIP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-strip" \
OBJCOPY="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objcopy" \
OBJDUMP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objdump" \
AR_FOR_BUILD="/usr/bin/ar" \
AS_FOR_BUILD="/usr/bin/as" \
CC_FOR_BUILD="/usr/bin/gcc" \
GCC_FOR_BUILD="/usr/bin/gcc" \
CXX_FOR_BUILD="/usr/bin/g++" \
LD_FOR_BUILD="/usr/bin/ld" \
CPPFLAGS_FOR_BUILD="-I/home/surpass/share/nativetool/tmp/include" \
CFLAGS_FOR_BUILD="-O2 -I/home/surpass/share/nativetool/tmp/include" \
CXXFLAGS_FOR_BUILD="-O2 -I/home/surpass/share/nativetool/tmp/include" \
LDFLAGS_FOR_BUILD="-L/home/surpass/share/nativetool/tmp/lib -Wl,-rpath,/home/surpass/share/nativetool/tmp/lib" \
FCFLAGS_FOR_BUILD="" \
DEFAULT_ASSEMBLER="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ar" \
DEFAULT_LINKER="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ld" \
CPPFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64" \
CFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os " \
CXXFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os " \
LDFLAGS="" FCFLAGS=" -Os " \
FFLAGS=" -Os " \
STAGING_DIR="/home/surpass/share/nativetool/glibc" \
INTLTOOL_PERL=/usr/bin/perl \
CFLAGS="-O2 " \
CPPFLAGS="" \
CXXFLAGS="-O2 " \
ac_cv_path_BASH_SHELL=/bin/bash \
libc_cv_forced_unwind=yes \
libc_cv_ssp=no \
ac_cv_prog_MAKE="/usr/bin/make -j5"  /bin/bash \
../configure \
--target=aarch64-zlk-linux-gnu \
--host=aarch64-zlk-linux-gnu \
--build=x86_64-pc-linux-gnu \
--prefix=/usr \
--enable-shared  \
--without-cvs \
--disable-profile \
--without-gd \
--enable-obsolete-rpc \
--enable-kernel=4.4 \
--disable-experimental-malloc \
--with-headers=/home/surpass/share/nativetool/kernel_headers/include \

編譯:
make -j4

安裝:
make -j4 install_root=/home/surpass/share/nativetool/glibc install

5、編譯gcc

同樣在gcc源代碼路徑下建立build目錄,然後切換到build目錄下,

配置:

AR="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ar" \
AS="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-as" \
LD="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ld" \
NM="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-nm" \
CC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
GCC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
CPP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-cpp" \
CXX="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-g++" \
FC="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gfortran" \
F77="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gfortran" \
RANLIB="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ranlib" \
READELF="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-readelf" \
STRIP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-strip" \
OBJCOPY="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objcopy" \
OBJDUMP="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objdump" \
AR_FOR_BUILD="/usr/bin/ar" \
AS_FOR_BUILD="/usr/bin/as" \
CC_FOR_BUILD="/usr/bin/gcc" \
GCC_FOR_BUILD="/usr/bin/gcc" \
CXX_FOR_BUILD="/usr/bin/g++" \
LD_FOR_BUILD="/usr/bin/ld" \
CPPFLAGS_FOR_BUILD="-I/home/surpass/share/nativetool/tmp/include" \
CFLAGS_FOR_BUILD="-O2 -I/home/surpass/share/nativetool/tmp/include" \
CXXFLAGS_FOR_BUILD="-O2 -I/home/surpass/share/nativetool/tmp/include" \
LDFLAGS_FOR_BUILD="-L/home/surpass/share/nativetool/glibc/lib -Wl,-rpath,/home/surpass/share/nativetool/glibc/lib" \
AR_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ar" \
AS_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-as" \
LD_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ld" \
NM_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-nm" \
CC_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
GCC_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc" \
CPP_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-cpp" \
CXX_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-g++" \
FC_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gfortran" \
F77_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-gfortran" \
RANLIB_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-ranlib" \
READELF_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-readelf" \
STRIP_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-strip" \
OBJCOPY_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objcopy" \
OBJDUMP_FOR_TARGET="/home/surpass/share/tool/aarch64-linux-gnu/bin/aarch64-linux-gnu-objdump" \
CPPFLAGS_FOR_TARGET="-I/home/surpass/share/nativetool/tmp/include" \
CFLAGS_FOR_TARGET="-O2 -I/home/surpass/share/nativetool/tmp/include" \
CXXFLAGS_FOR_TARGET="-O2 -I/home/surpass/share/nativetool/tmp/include" \
LDFLAGS_FOR_TARGET="-L/home/surpass/share/nativetool/tmp/lib -Wl,-rpath,/home/surpass/share/nativetool/tmp/lib" \
CPPFLAGS="-I/home/surpass/share/nativetool/tmp/include" \
CFLAGS="-O2 -I/home/surpass/share/nativetool/tmp/include" \
CXXFLAGS="-O2 -I/home/surpass/share/nativetool/tmp/include" \
LDFLAGS="-L/home/surpass/share/nativetool/tmp/lib -Wl,-rpath,/home/surpass/share/nativetool/tmp/lib" \
INTLTOOL_PERL=/usr/bin/perl \
MAKEINFO=missing \
CFLAGS_FOR_TARGET="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os " \
CXXFLAGS_FOR_TARGET="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os " \
../configure \
--prefix="/home/surpass/share/nativetool/target/usr" \
--host=aarch64-zlk-linux-gnu \
--target=aarch64-zlk-linux-gnu \
--with-sysroot=/home/surpass/share/nativetool/glibc/ \
--enable-static  \
--enable-__cxa_atexit \
--with-gnu-ld \
--disable-libssp \
--disable-multilib \
--with-gmp=/home/surpass/share/nativetool/tmp/ \
--with-mpc=/home/surpass/share/nativetool/tmp/ \
--with-mpfr=/home/surpass/share/nativetool/tmp/ \
--disable-libquadmath \
--enable-tls \
--disable-libmudflap \
--enable-threads \
--without-isl \
--without-cloog \
--disable-decimal-float \
--with-abi="lp64" \
--with-cpu=cortex-a72.cortex-a53 \
--enable-languages=c,c++ \
--with-build-time-tools=/home/surpass/share/tool/aarch64-linux-gnu/bin/ \
--enable-shared \
--disable-libgomp \

編譯:
make -j4 

安裝:
make -j4 install

總結:

    上面的過程,其實就是從buildroot編譯cross gcc 的過程中摘抄出來改了一下,編譯期間也遇到了不少的問題,百度谷歌也很少能查的到,只有查看分析log。上面沒有給配置項添加註釋,我也沒有去查源代碼中的自帶的說明弄清每一項配置的含義,個人覺得很多時候解決問題並不一定都需要做到精通,畢竟人的精力和時間都是有限的,時間應該花在知識面的拓展上,每一項技能掌握個百分之六七十,然後知識面非常的廣,如果遇到某方面的問題,再花時間專門研究做到精通。筆者工作這幾年深刻的感覺到,知識面的廣度很多時候比只深度掌握幾個點知識重要的多的多,很多的時候不是因爲不精通解決不了問題,而是因爲不知道造成的大量時間浪費。尤其是對於一些新技術問題的解決,知識面廣的人表現出來的優勢遠不是隻懂某幾樣技術的人可比的,而對於某些人所謂精通的領域,也是稍微多花點時間也可以達到差不多的水平。所以對於筆者,時間花在儘可能多的知識面覆蓋上,並且至少能理解個百分之五十,實際工作中也發現這是個正確的路子。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章