高通clang交叉編譯器下載
1. SE是什麼編譯器
Clang交叉編譯器。
_lang具有更現代的設計茄渣,並且通常被認為比GCC更先進。除此之外,Clang還獲得了更為寬松的許可,該許可允許製造可商購的衍生物。ARM / Keil從Clang派生了一個編譯器,從而停止了其先前專有編譯器的開發。考慮到所有這些,我們決定更深入地研究Clang,以使用它創建我們自己的編譯器為目標。
_EGGER將所有內容打包到一個易於下載的「軟體包」中,完全集成並且可以立即使用。Clang和GCC都有非常先進的前端,可以將源代碼轉換為中間表示(IR),並且都可以生成出色的代碼。到目前為止,SEGGER一直專注於針對基於Cortex-M微控制器的ARM Thumb-2代碼的銀吵代碼生成器的更改。下一步將包括改善與其他編譯器的兼容性,而不僅僅是GCC和Clang(針對實用程序和其他專顫搏悄業),以使其易於切換。
2. 如何在Windows上建立arm-linux開發環境
如何在Windows上建立arm-linux開發環境 FriendlyARM 目 前,有很多地方介紹了如何在cygwin上為ARM7建立arm-elf-gcc交叉編譯工具鏈,但是對ARM9卻鮮有介紹,為了方便大家更好在 Windows上進行嵌入式linux開發,我們鋒則在cygwin上移植了arm-linux-gcc for ARM920T。 要在Windows上建立arm-linux開發環境,您需要先安裝cygwin(見「cygwin完全安裝指南」)。
1. 解壓交叉編譯器 下載:FriendlyARM.tgz 下載gdbserver(for ARM920t):gdbserver.tgz 下載gdbserver所依賴的庫:lib-for-gdbserver.tgz(請把庫解壓到目標板的/usr/lib目錄下) #mkdir /opt ;創建opt目錄,如果已經存在則不需要創建 #tar xvzf FriendlyARM.tgz -C /opt ;把交叉編譯器安裝在/opt/FriendlyARM目錄,注意必須是此目錄 2. 配置啟動腳本/etc/profile 3. 測試 退出cygwin,重新啟動一個終端,輸入:arm-linux-gcc -v,如果出現以前讓下信慧基局息,說明您已經正確安裝,否則仔細檢查/etc/profile是否配置好。
3. 如何使用clang+llvm+binutils+newlib+gdb搭建交叉編譯環境
1,Build llvm/clang/lldb/lld 3.5.0等組件
1.0 准備:
至少需要從llvm.org下載llvm, cfe, lldb, compiler-rt,lld等3.5.0版本的代碼。
$tar xf llvm-3.5.0.src.tar.gz
$cd llvm-3.5.0.src
$mkdir -p tools/clang
$mkdir -p tools/clang/tools/extra
$mkdir -p tools/lld
$mkdir -p projects/compiler-rt
$tar xf cfe-3.5.0.src.tar.xz -C tools/clang --strip-components=1
$tar xf compiler-rt-3.5.0.src.tar.xz -C projects/compiler-rt --strip-components=1
$tar xf lldb-3.5.0.src.tar.xz -C tools/clang/tools/extra --strip-components=1
$tar xf lld-3.5.0.src.tar.xz -C tools/lld --strip-components=1
1.1 【可選】使用clang --stdlib=libc++時,自動添加-lc++abi。
libc++組件可以使用gcc libstdc++的supc++ ABI,也可以使用c++abi,cxxrt等,實際上自動添加-lc++abi是不必要的,這里這么處理,主要是為了方便起見。實際上完全可以在「clang++ -stdlib=libc++」時再手工添加-lc++abi給鏈接器。
這里涉及到鏈接時DSO隱式還是顯式的問題,早些時候ld在鏈接庫時會自動引入由庫引入的依賴動態庫,後來因為這個行為的不可控性,所以ld鏈接器的行為做了修改,需要顯式的寫明所有需要鏈接的動態庫,才會有手工添加-lc++abi這種情況出現。
--- llvm-3.0.src/tools/clang/lib/Driver/ToolChain.cpp 2012-03-26 18:49:06.663029075 +0800
+++ llvm-3.0.srcn/tools/clang/lib/Driver/ToolChain.cpp 2012-03-26 19:36:04.260071355 +0800
@@ -251,6 +251,7 @@
switch (Type) {
case ToolChain::CST_Libcxx:
CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lc++abi");
break;
case ToolChain::CST_Libstdcxx:
1.2 【必要】給clang++添加-fnolibgcc開關。
這個開關主要用來控制是否連接到libgcc或者libunwind。
註:libgcc不等於libunwind。libgcc_eh以及supc++的一部分跟libunwind功能相當。
註:libgcc_s和compiler_rt的一部分相當。
這個補丁是必要的, 不會對clang的正常使用造成任何影響 ,只有在使用「-fnolibgcc"參數時才會起作用。
之所以進行了很多unwind的引入,主要是為了避免不必要的符號缺失麻煩,這里的處理相對來說是干凈的,通過as-needed規避了不必要的引入。
--- llvm-static-3.5.0.bak/tools/clang/lib/Driver/Tools.cpp 2014-09-10 13:46:02.581543888 +0800
+++ llvm-static-3.5.0/tools/clang/lib/Driver/Tools.cpp 2014-09-10 16:03:37.559019321 +0800
@@ -2060,9 +2060,15 @@
".a");
CmdArgs.push_back(Args.MakeArgString(LibClangRT));
- CmdArgs.push_back("-lgcc_s");
- if (TC.getDriver().CCCIsCXX())
- CmdArgs.push_back("-lgcc_eh");
+ if (Args.hasArg(options::OPT_fnolibgcc)) {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lunwind");
+ CmdArgs.push_back("--no-as-needed");
+ } else {
+ CmdArgs.push_back("-lgcc_s");
+ if (TC.getDriver().CCCIsCXX())
+ CmdArgs.push_back("-lgcc_eh");
+ }
}
static void addProfileRT(
@@ -7150,24 +7156,50 @@
bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android;
bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) ||
Args.hasArg(options::OPT_static);
+
+
+
if (!D.CCCIsCXX())
- CmdArgs.push_back("-lgcc");
+ if (Args.hasArg(options::OPT_fnolibgcc)) {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lunwind");
+ CmdArgs.push_back("--no-as-needed");
+ } else
+ CmdArgs.push_back("-lgcc");
if (StaticLibgcc || isAndroid) {
if (D.CCCIsCXX())
- CmdArgs.push_back("-lgcc");
+ if (Args.hasArg(options::OPT_fnolibgcc)) {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lunwind");
+ CmdArgs.push_back("--no-as-needed");
+ } else
+ CmdArgs.push_back("-lgcc");
} else {
if (!D.CCCIsCXX())
CmdArgs.push_back("--as-needed");
- CmdArgs.push_back("-lgcc_s");
+ if (Args.hasArg(options::OPT_fnolibgcc))
+ CmdArgs.push_back("-lunwind");
+ else
+ CmdArgs.push_back("-lgcc_s");
if (!D.CCCIsCXX())
CmdArgs.push_back("--no-as-needed");
}
if (StaticLibgcc && !isAndroid)
- CmdArgs.push_back("-lgcc_eh");
+ if (Args.hasArg(options::OPT_fnolibgcc)) {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lunwind");
+ CmdArgs.push_back("--no-as-needed");
+ } else
+ CmdArgs.push_back("-lgcc_eh");
else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX())
- CmdArgs.push_back("-lgcc");
+ if (Args.hasArg(options::OPT_fnolibgcc)) {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lunwind");
+ CmdArgs.push_back("--no-as-needed");
+ } else
+ CmdArgs.push_back("-lgcc");
// According to Android ABI, we have to link with libdl if we are
// linking with non-static libgcc.
--- llvm-static-3.5.0.bak/tools/clang/include/clang/Driver/Options.td 2014-08-07 12:51:51.000000000 +0800
+++ llvm-static-3.5.0/tools/clang/include/clang/Driver/Options.td 2014-09-10 13:36:34.598511176 +0800
@@ -788,6 +788,7 @@
def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>;
def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>;
def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group<f_Group>, Flags<[CC1Option]>;
+def fnolibgcc : Flag<["-"], "fnolibgcc">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>;
def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>;
def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>;
def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">;
1.3 llvm的其他補丁。
llvm/clang將gcc toolchain的路徑hard code在代碼中,請查閱tools/clang/lib/Driver/ToolChains.cpp。
找到x86_64-redhat-linux之類的字元串。
如果沒有你系統特有的gcc tripple string,請自行添加。
這個tripple string主要是給llvm/clang搜索gcc頭文件等使用的,不影響本文要構建的toolchain
1.4 構建clang/llvm/lldb
本文使用ninja。順便說一下,llvm支持configure和cmake兩種構建方式。可能是因為工程太大,這兩種構建方式的工程文件都有各種缺陷(主要表現在開關選項上,比如configure有,但是cmake卻沒有等)。llvm-3.4.1就是因為cmake工程文件的錯誤而導致了3.4.2版本的發布。
綜合而言,cmake+ninja的方式是目前最快的構建方式之一,可以將構建時間縮短一半以上。
mkdir build
cd build
cmake \
-G Ninja \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_BUILD_TYPE="Release" \
-DCMAKE_CXX_FLAGS="-std=c++11" \
-DBUILD_SHARED_LIBS=OFF \
-DLLVM_ENABLE_PIC=ON \
-DLLVM_TARGETS_TO_BUILD="all" \
-DCLANG_VENDOR="MyOS" ..
ninja
ninja install
如果系統原來就有clang/clang++的可用版本,可以添加:
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
這樣就會使用系統的clang++來構建llvm/clang
2,測試clang/clang++。
自己找幾個簡單的c/cpp/objc等編譯測試一下即可。完整測試可以在構建時作ninja check-all
3,libunwind/libc++/libc++abi,一套不依賴libgcc, libstdc++的c++運行庫。
3.1 從https://github.com/pathscale/libunwind 獲取代碼。
libunwind有很多個實現,比如gnu的libunwind, path64的libunwind,還有libcxxabi自帶的Unwinder.
這里作下說明:
1),gnu的libunwind會有符號缺失和沖突。
2),libcxxabi自帶的Unwinder是給mac和ios用的,也就是只能在darwin體系構建。目前Linux的實現仍然不全,等linux實現完整了或許就不再需要path64的unwind實現了。
暫時建議使用pathscale的unwind實現。
mkdir -p build
cd build
cmake -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_C_FLAGS="-m64" ..
ninja
mkdir -p /usr/lib
cp src/libunwind.so /usr/lib
cp src/libunwind.a /usr/lib
3.2 第一次構建libcxx.
必須先構建一次libcxx,以便後面構建libcxxabi。這里構建的libcxx實際上是使用gcc的libgcc/stdc++/supc++的。
打上這個補丁來禁止libgcc的引入:
diff -Nur libcxx/cmake/config-ix.cmake libcxxn/cmake/config-ix.cmake
--- libcxx/cmake/config-ix.cmake 2014-06-25 06:57:50.000000000 +0800
+++ libcxxn/cmake/config-ix.cmake 2014-06-25 09:05:24.980350544 +0800
@@ -28,5 +28,4 @@
check_library_exists(c printf "" LIBCXX_HAS_C_LIB)
check_library_exists(m ccos "" LIBCXX_HAS_M_LIB)
check_library_exists(rt clock_gettime "" LIBCXX_HAS_RT_LIB)
-check_library_exists(gcc_s __gcc_personality_v0 "" LIBCXX_HAS_GCC_S_LIB)
編譯安裝:
mkdir build
cd build
cmake \
-G Ninja \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
..
ninja
ninja install
3.3,測試第一次構建的libcxx。
使用"clang++ -stdlib=libc++ -o test test.cpp -lstdc++"編譯簡單c++代碼,檢查是否出錯。(如果前面構建clang是已經apply了c++abi的鏈接補丁,這里會出現找不到c++abi的情況,跳過即可)
使用"ldd test"查看test二進制動態庫使用情況。可以發現,test依賴於libgcc_s/libc++/libstdc++。(多少有些不爽了吧?使用了libc++居然還要依賴libstdc++?)
4. cygwin 中如何安裝arm-linux-gcc交叉編譯器
交叉編譯工具鏈作為嵌入式Linux開發的基礎,直接影響到嵌入式開發的項目進度和完成質量。由於目前大多數開發人員使用Windows作為嵌入式開發的宿主機,在Windows中通過安裝VMware等虛擬機軟體來進行嵌入式Linux開發,這樣對宿主機的性能要求極高。Cygwin直接作為Windows下的軟體完全能滿足嵌入式Linux的開發工作,對硬體的要求低及方便快捷的特點成為嵌入式開發的最佳選擇。
目前網路上Cygwin下直接可用的交叉編譯器寥寥無幾且版本都比較低,不能滿足開源軟體對編譯器版本依賴性的要求(如低版本工具鏈編譯U-Boot出現軟浮點問題等);Crosstool等交叉工具鏈製作工具也是更新跟不上自由軟體版本的進度;同時系統介紹Cygwin下製作交叉編譯器方面的資料很少。針對上述情況,基於最新版gcc等自由軟體構建Cygwin下的交叉編譯器顯得尤為迫切和重要。
構建前准備工作
首先Cygwin下必須保證基本工具比如make}gcc等來構建bootstrap-gcc編譯器,這可以在安裝Cygwin時選擇安裝。參照gcc等安裝說明文檔來在Cygwin下查看是否已經安裝,如輸入gcc --v等。
源碼下載
gcc-4.5.0的編譯需mpc的支持,而mpc又依賴gmp和mpfr庫。從各個項目官方網站上下載的最新的源碼:
binutils-2.20. l .tar.bz2
gmp-S.O. l .tar.bz2
mpc-0.8.2.tar.gz
mpfr-3.O.O.tar.bz2
gcc-4.S.O.tar.bz2
linux-2.6.34.tar.bz2
glibc-2.11.2.tar.bz2
glibc-ports-2. l l .tar.bz2
gdb-7. l.tar.bz2
設置環境變數
HOST:工具鏈要運行的目標機器;BUILD:用來建立工具鏈的機器;TARGET工具鏈編譯產生的二進制代碼可以運行的機器。
BUILD=i686-pc-cygwin
HOST=i686-pc-cygwin TARGET=arm-linux
SYSROOT指定根目錄,$PREFIX指定安裝目錄。目標系統的頭文件、庫文件、運行時對象都將被限定在其中,這在交叉編譯中有時很重要,可以防止使用宿主機的頭文件和庫文件。本文首選$SYSROOT為安裝目錄,$PREFIX主要作為glibc庫安裝目錄。
SYSROOT=/cross-root
PREFIX=/cross-root/arm-linux
由於GCC-4.5.0需要mpfr,gmp,mpc的支持,而這三個庫又不需要交叉編譯,僅僅是在編譯交叉編譯鏈時使用,所以放在一個臨時的目錄。
TEMP_PREFIX=/build-temp
控制某些程序的本地化的環境變數:
LC ALL=POSIX
設置環境變數:
PATH=$SYSROOT/bin:兒in:/usr/bin
設置編譯時的線程數f31減少編譯時間:
PROCS=2
定義各個軟體版本:
BINUTILS V=2.20.1
GCC V=4.5.0
GMP V=5.0.1
MPFR V=3.0.0
MPC V二0.8.2
LINUX V二2.6.34
GLIBC V=2.11.2
GLIBC-PORTS V=2.11
GDB V=7.1
構建過程詳解
鑒於手工編譯費時費力,統一把構建過程寫到Makefile腳本文件中,把其同源碼包放在同一目錄下,執行make或順次執行每個命令即可進行無人值守的編譯安裝交叉工具
鏈。以下主要以Makefile執行過程為主線進行講解。
執行「make」命令實現全速運行
可在Cygwin的Shell環境下執行「make>make.log 2>&1」命令把編譯過程及出現的錯誤都輸出到make.log中,便於查找:
all:prerequest install-deps install-cross-stage-one install-
cross-stage-two
預處理操作
"make prerequest',命令實現單步執行的第一步,實現輸出變數、建立目錄及解壓源碼包等操作。0'set十h」關閉bash的Hash功能,使要運行程序的時候,shell將總是搜索PATH里的目錄[4]。這樣新工具一旦編譯好,shell就可以在$(SYSROOT)/bin目錄里找到: prerequest:
set +h&&mkdir -p $(SYSROOT)/bin&&
mkdir -p $(PREFIX)/include&&
mkdir -p $(TEMP一REFIX)&&
export PATH LCes ALL&&
tar -xvf gmp-$(GMP_V).tar.bz2&&
tar -xvf mpfr-$(MPFR_V).tar.bz2&&
tar -xvf mpc-$(MPC_V).tar.gz&&
tar -xvf binutils-$(BINUTILS_V).tar.bz2&&
tar -xvf gcc-$(GCC_V).tar.bz2&&
tar -xvf linux-$(LINUX_V).tar.bz2&&
tar -xvf glibc-$(GLIBC_V).tar.bz2&&
tar -xvf glibc-ports-$(GLIBC-PORTS_V).tar.bz2&&
my glibc-ports-$(GLIBC-PORTS_V)
glibc-$(GLIBC_V)/ports&&
tar -xvf gdb-$(GDB V).tar.bz2
非交叉編譯安裝gcc支持包mpc
00make install-deps」命令實現單步執行的第二步,實現mpc本地編譯,mpc依賴於gmp和mpfr
install-deps:gmp mpfr mpc
gmp:gmp-$(GMP_V)
mkdir -p build/gmp&&cd build/gmp&&
../../gmp-*/configure
--disable-shared --prefix=$(TEMP_PREFIX)&&
$(MAKE)一$(PROCS)&&$(MAKE) install
mpfr:mpfr-$(MPFR_V)
mkdir -p b-uild/mpfr&&cd build/mpfr&&
../..//mpfr-*/configure
LDF'LAGS="-Wl,-search_paths_first」--disable-shared
--with-gmp=$(TEMP_PREFIX)
--prefix=$(TEMP_PREFIX)&&
$(MAKE)一$(PROCS) all&&$(MAKE) install
mpc: mpc-$(MPC_V) gmp mpfr
mkdir -p build/mpc&&cd build/mpc&&
../../mpc-*/configure
--with-mpfr=$(TEMP PREFIX)
--with-gmp=$(TEMP_PREFIX)
--prefix=$(TEMP_PREFIX)&&
$(MAKE)一$(PROCS)&&$(MAKE) install
交叉編譯第一階段
"make install-cross-stage-one',命令實現單步執行的第三步,編譯安裝binutils,bootstrap-gcc和獲取Linux內核頭文件:
install-cross-stage-one:cross-binutils cross-gcc get-kernel-headers
編譯安裝binutils
cross-binutils: binutils-$(BINUTILS_ V)
mkdir -p build/binutils&&cd build/binutils&&
../..//binutils-*/configure --prefix=$(SYSROOT)
--target=$(TARGET)--disable-nls&&
$(MAKE)j$(PROCS)&&$(MAKE) install
編譯安裝bootstrap-gcc。使用一disable-shared參數的意思是不編譯和安裝libgcc_ eh.a文件。glibc軟體包依賴這個庫,因為它使用其內部的一lgcc_eh來創建系統[6]。這種依賴
性,可通過建立一個指向libgcc.a符號鏈接得到滿足,因為該文件最終將含有通常在libgcc- eh.a中的對象(也可通過補丁文件實現)。
cross-gcc:gcc-$(GCC_V)
mkdir -p build/gcc&&cd build/gcc&&
二//gcc-*/configure
--target=$(TARGET)--prefix=$(SYSROOT)
--disable-nls --disable-shared --disable-multilib
--disable-decimal-float--disable-threads
--disable-libmudflap --disable-libssp
--disable-libgomp --enable-languages=c
--with-gmp=$(TEMP_PREFIX)
--with-mpfr=$(TEMP_PREFIX)
--with-mpc=$(TEMP_PREFIX)&&
$(MAKE) -j$(PROCS)&&$(MAICE) install&&
In -vs libgcc.a'arm-linux-gcc -print-libgcc-file-name I
sed's/libgcc/& eh/'}
獲取Linux內核頭文件:
get-kernel-headersainux-$(LINUX_V)
cd linux-$(LINUX_V)&&
$(MAICE) mrproper&&$(MAKE) headers check&&
$(MAKE) ARCH=arm&&
INSTALLes HDR_ PATH=dest headers_ install&&
find dest/include
(-name .install一。-name ..installNaNd)-delete&&
cp -rv desdinclude/* $(PREFIX)/include
交叉編譯第二階段
編譯安裝glibc、重新編譯安裝binutils、完整編譯安裝gcc和編譯安裝gdb o "make install-cross-stage-two',命令實現單步執行的第四步: install-cross-stage-two:cross-glibc cross-rebinutils cross-g++ cross-gdb
編譯安裝glibca glib。的安裝路徑特意選為$(PREFIX),與gcc更好找到動態鏈接庫也有關系,選在$(SYSROOT)提示找不到crti.o; glibc已經不再支持i386; glibc對ARM等的處理器的支持主要通過glibc-ports包來實現;正確認識大小寫敏感(Case Sensitive)和大小寫不敏感(CaseInsensitive)系統,大小寫敏感問題主要影響到glibc,是交叉編譯glibc成功的關鍵:Cygwin幫助手冊中可知Cygwin是默認大小寫不敏感的n},但是UNIX系統是大小寫敏感的,這也是Cygwin和UNIX類系統的一個區別。通過作者自行參考製作的glibc-2.11.2-cygwin.patch補T使glibc變為Case-Insensitive,此補丁主要是對大小寫敏感問題改名來實現。
交叉編譯過程中安裝的鏈接器,在安裝完Glibc以前都無法使用。也就是說這個配置的forced unwind支持測試會失敗,因為它依賴運行中的鏈接器。設置libc_ cvforced unwind=yes這個選項是為了通知configure支持force-unwind,而不需要進行測試。libc cv_c_cleanup=yes類似的,在configure腳本中使用libc_cv_c cleanup=yes,以便配置成跳過測試而支持C語言清理處理。
cross-glibc:glibc-$(GLIBC_V)
cd glibc-$(GLIBC_V)&&
patch -Np 1 –i...//glibc-2.11.2-cygwin.patch&&
cd..&&mkdir -p build/glibc&&
cd build/glibc&&
echo"libc cv_forcedes unwind=yes">config.cache&&
echo "libc cv_c_cleanup=yes">>config.cache&&
echo "libc cv_arm_tls=yes">>config.cache&&
../../glibc-*/configure --host=$(TARGET)
--build=$(../OneScheme/glibc-2.11.2/scripts/config.guess)
--prefix=$(PREFIX)--disable-profile
--enable-add-ons --enable-kernel=2.6.22.5
--with-headers=$(PREFIX)/include
--cache-file=config.cache&&
$(MAKE)&&$(MAKE) install
重新編譯安裝binutils。編譯之前要調整工具鏈,使其
指向新生成的動態連接器。
調整工具鏈:
SPECS=
'dirname $(arm-linux-gcc -print-libgcc-file-name)'/specs
arm-linux-gcc -mpspecs
sed -e 's@/lib(64)\?/ld@$(PREFTX)&@g' -e ,}/}}*cPP}$/{n;s,$,-isystem $(PREFIX)/include,}"
>$SPECS
echo "New specs file is: $SPECS"
unset SPECS
測試調整後工具鏈:
echo 'main(川』>mmy.c
arm-linux-gcc
-B/cross-root/arm-linux/lib mmy.c
readelf -1 a.out I grep』:/cross-roobarm-linux'
調整正確的輸出結果:
[Requesting program interpreter: /tools/lib/ld-linux.so.2j
一切正確後刪除測試程序:
rm -v mmy.c a.out
重新編譯binutils。指定--host,--build及--target,否則配置不成功,其config.guess識別能力不如gcc做的好。
cross-rebinutils: binutils-$(BINUTILS_V)
mkdir -p build/rebinutils&&
cd build/rebinutils&&CC="$(TARGET)-gcc
-B/cross-roodarm-linux/lib/"&&AR=$(TARGET)-ar&&
RANLIB=$(TARGET)-ranlib&&../..//binutils-*/configure
--host=$(HOST)--build=$(BUILD)--target=$(TARGET)
--prefix=$(SYSROOT)--disable-nls
--with-lib-path=$(PREFIX)/lib&&
$(MAKE)--$(PROCS)&&$(MAKE) install
高於4.3版的gcc把這個編譯當作一個重置的編譯器,並且禁止在被一prefix指定的位置搜索startfiles。因為這次不是重置的編譯器,並且$(SYSROOT)目錄中的startfiles對於創
建一個鏈接到$$(SYSROOT)目錄庫的工作編譯器很重要,所以我們使用下面的補丁,它可以部分還原gcc的老功能tai . patch -Npl –i../gcc-4.5.0-startfiles_fix-l.patch
在正常條件下,運行gcc的fixincludes腳本,是為了修復可能損壞的頭文件。它會把宿主系統中已修復的頭文件安裝到gcc專屬頭文件目錄里,通過執行下面的命令,可以抑
制fixincludes腳本的運行[9](此時目錄為/gcc-4.5.0)。
cp -v gcc/Makefile.in{,.orig}
sed 's@\./fixinc\.sh@-c true@'
gcc/Makefile.in.orig > gcc/Makefile.in
下面更改gcc的默認動態鏈接器的位置,使用已安裝在/cross-root/ann-linux目錄下的鏈接器,這樣確保在gcc真實的編譯過程中使用新的動態鏈接器。即在編譯過程中創建的所有
二進制文件,都會鏈接到新的glibc文件
for file in
$(find gcc/config -name linux64.h-o -name linux.h –o -name sysv4.h)
do cp -uv $file{,.orig}
sed -a 's@/lib(64)?(32)?/Id@/cross-root/arm-linux&@g』-e's@/usr@/cross-rootlarm-linux@g' $file.orig>$file echo『
#undef STANDARD INCLUDE DIR
#define STANDARD_ INCLUDE DIR "/cross-root/arm-linux/include"
#define STANDARD STARTFILE PREFIX 1 "/cross-root/arm-linux/lib"
#define STANDARD_ STARTFILE_ PREFIX_ 2」」』>>$file
touch $file.orig done
完整編譯安裝gcc。最好通過指定--libexecdir更改libexecdir到atm-linux目錄下。--with-local-prefix選項指定gcc本地包含文件的安裝路徑此處設為$$(PREFIX),安裝後就會在內核頭文件的路徑下。路徑前指定$(Pwd)則以當前路徑為基點,不指定則默認以/home路徑為基點,這點要注意。
cross-g++:gcc-$(GCC-)
mkdir -p build/g十+&&cd build/g++&&
CC="$(TARGET)-gcc AR=$(TARGET)-ar&&
-B/cross-roodarm-linux/lib/"&&
RANLIB=$(TARGET)-ranlib&&
..//gcc-*/configure
--host=$(HOST)--build=$(BUILD)--target=$(TARGET)
--prefix=$(SYSROOT)--with-local-prefix=$(PREFIX)
--enable-clocale=gnu --enable-shared
--enable-threads=posix --enable -cxa_atexit
--enable-languages=c,c++--enable-c99
--enable-long-long --disable-libstdcxx-pch
--disable-libunwind-exceptions
--with-gmp=$(TEMP_PREFIX)
--with-mpfr=$(TEMP_PREFIX)
--with-mpc=$(TEMP_PREFIX)&&
$(MAKE) LD_IBRARY_ATH=
$(pwd)/$(../../gcc-4.5.0/config.guess)/libgcc&&
$(MAKE) install
編譯安裝gdb,至此完成整個工具鏈的製作。
cross-gdb: gdb-$(GDB V)
mkdir -p build/gdb&&cd build/gdb&&
../../gdb-*/configure --prefix=$(SYSROOT)
--target=$(TARGET)--disable-werror&&
$(MAKE)-j$(PROCS)&&$(MAKE) install
「make clean」命令清除編譯生成的文件和創建解壓的文件夾
.PHONY:clean
dean:
rm -fr $(TEMP_PREFIX) build
binutils-$(BINUTIL,S_V) gcc-$(GCC_V)
glibc-$(NEWL.IB_V) gdb-$(GDB_V)
gmp-$(GMP_V) mpc-$(MPC_V) mpfr-$(MPFR_V)
工具鏈測試
命令行中輸入以下內容:
echo 'main(){}』>mmy.c
arm-linux-gcc -o mmy.exe mmy.c
file mmy.exe
運行正常的結果:
mmy.exe: ELF 32-bit LSB executable, ARM, version 1,for GNU/Linux 2.6.22, dynamically linked (uses shared libs),not stripped.
5. 如何編譯Android的kernel
1.准備工作: (ubuntu1110 32位)
ubuntu等linuxOS,下載好eclipse,安裝好JDK, 安裝好android的SDK, 在eclipse中成功打開android 手機模擬器即OK。
2.初始化編譯環境 :
關注該網頁上的「installing required packages」,其中有的軟體包因為版本問題而安裝不上,不用管它,之後遇到錯誤再單獨解決。
3.下載內核源碼:
android 2.3 內核 下載需要等待一段時間。
4.下載交叉編譯器:
該步驟有可能耗費大量時間,依據網速不同,幾個小時到幾天不等,或許可以嘗試git clone 後面的地址只下載prebuilt/linux-x86/toolchain
5.設置參數以及編譯:
$ export ARCH=arm
$ export SUBARCH=arm
$ export CROSS_COMPILE=arm-eabi-
$ cd goldfish // 進入下載的源代碼目錄
$ git checkout <commit_from_first_step> //這個步驟我沒有做,不知道幹嘛用的
$ make goldfish_defconfig
$ make
6.報錯信息:
若有報錯說找不到 (arm-eabi-gcc command not found)等等,嘗試使用採用另外一個交叉編譯器。
7.測試:
最後,測試一下剛才編譯的內核:emulator -avd myavd -kernel ~/goldfish/arch/arm/boot/zImageemulator若系統找不到,可以去android SDK中某文件夾找到,加入系統PATH即可。 -avd後面的參數 myavd即為模擬器的名字,這個我是在eclipse中的模擬器管理中新建的一個模擬器,用那個模擬器的名字即可。 -kernel後面的參數就找到剛才編譯出的內核的路徑。
若啟動模擬器失敗,可嘗試關閉後再啟動。第一次啟動模擬器時可能需要等待比較長的時間。
6. 「干貨」嵌入式Linux系統移植的四大步驟(上)
在學習系統移植的相關知識,在學習和調試過程中,發現了很多問題,也解決了很多問題,但總是對於我們的開發結果有一種莫名其妙的感覺,糾其原因,主要對於我們的開發環境沒有一個深刻的認識,有時候幾個簡單的命令就可以完成非常復雜的功能,可是我們有沒有想過,為什麼會有這樣的效果?
如果沒有去追問,只是機械地完成,並且看到實驗效果,這樣做其實並沒有真正的掌握系統移植的本質。
在做每一個步驟的時候, 首先問問自己,為什麼要這樣做,然後再問問自己正在做什麼? 搞明白這幾個問題,我覺得就差不多了,以後不管更換什麼平台,什麼晶元,什麼開發環境,你都不會迷糊,很快就會上手。對於嵌入式的學習方法,我個人方法就是:從宏觀上把握(解決為什麼的問題),微觀上研究(解決正在做什麼的問題),下面以自己學習的arm-cortex_a8開發板為目標,介紹下自己的學習方法和經驗。
嵌入式Linux系統移植主要由四大部分組成:
一、搭建交叉開發環境
二、bootloader的選擇和移植
三、kernel的配置、編譯、和移植
四、根文件系統的製作
第一部分:搭建交叉開發環境
先介紹第一分部的內容:搭建交叉開發環境,首先必須得思考兩個問題,什麼是交叉環境? 為什麼需要搭建交叉環境?
先回答第一個問題,在嵌入式開發中,交叉開發是很重要的一個概念,開發的第一個環節就是搭建環境,第一步不能完成,後面的步驟從無談起,這里所說的交叉開發環境主要指的是:在開發主機上(通常是我的pc機)開發出能夠在目標機(通常是我們的開發板)上運行的程序。嵌入式比較特殊的是不能在目標機上開發程序(狹義上來說),因為對於一個原始的開發板,在沒有任何程序的情況下它根本都跑不起來,為了讓它能夠跑起來,我們還必須要藉助pc機進行燒錄程序等相關工作,開發板才能跑起來,這里的pc機就是我們說的開發主機,想想如果沒有開發主機,我們的目標機基本上就是無法開發,這也就是電子行業的一句名言:搞電子,說白了,就是玩電腦!
然後回答第二個問題,為什麼需要交叉開發環境?主要原因有以下幾點:
原因 1: 嵌入式系統的硬體資源有很多限制,比如cpu主頻相對較低,內存容量較小等,想想讓幾百MHZ主頻的MCU去編譯一個Linux kernel會讓我們等的不耐煩,相對來說,pc機的速度更快,硬體資源更加豐富,因此利用pc機進行開發會提高開發效率。
原因2: 嵌入式系統MCU體系結構和指令集不同,因此需要安裝交叉編譯工具進行編譯,這樣編譯的目標程序才能夠在相應的平台上比如:ARM、MIPS、 POWEPC上正常運行。
交叉開發環境的硬體組成主要由以下幾大部分 :
1.開發主機
2.目標機(開發板)
3.二者的鏈接介質,常用的主要有3種方式:(1)串口線 (2)USB線 (3)網線
對應的硬體介質,還必須要有相應的軟體「介質」支持:
1.對於串口,通常用的有串口調試助手,putty工具等,工具很多,功能都差不多,會用一兩款就可以;
2.對於USB線,當然必須要有USB的驅動才可以,一般晶元公司會提供,比如對於三星的晶元,USB下載主要由DNW軟體來完成;
3.對於網線,則必須要有網路協議支持才可以, 常用的服務主要兩個
第一:tftp服務:
主要用於實現文件的下載,比如開發調試的過程中,主要用tftp把要測試的bootloader、kernel和文件系統直接下載到內存中運行,而不需要預先燒錄到Flash晶元中,一方面,在測試的過程中,往往需要頻繁的下載,如果每次把這些要測試的文件都燒錄到Flash中然後再運行也可以,但是缺點是:過程比較麻煩,而且Flash的擦寫次數是有限的;另外一方面:測試的目的就是把這些目標文件載入到內存中直接運行就可以了,而tftp就剛好能夠實現這樣的功能,因此,更沒有必要把這些文件都燒錄到Flash中去。
第二: nfs服務:
主要用於實現網路文件的掛載,實際上是實現網路文件的共享,在開發的過程中,通常在系統移植的最後一步會製作文件系統,那麼這是可以把製作好的文件系統放置在我們開發主機PC的相應位置,開發板通過nfs服務進行掛載,從而測試我們製作的文件系統是否正確,在整個過程中並不需要把文件系統燒錄到Flash中去,而且掛載是自動進行掛載的,bootload啟動後,kernel運行起來後會根據我們設置的啟動參數進行自動掛載,因此,對於開發測試來講,這種方式非常的方便,能夠提高開發效率。
另外,還有一個名字叫 samba 的服務也比較重要,主要用於文件的共享,這里說的共享和nfs的文件共享不是同一個概念,nfs的共享是實現網路文件的共享,而samba實現的是開發主機上 Windows主機和Linux虛擬機之間的文件共享,是一種跨平台的文件共享 ,方便的實現文件的傳輸。
以上這幾種開發的工具在嵌入式開發中是必備的工具,對於嵌入式開發的效率提高做出了偉大的貢獻,因此,要對這幾個工具熟練使用,這樣你的開發效率會提高很多。等測試完成以後,就會把相應的目標文件燒錄到Flash中去,也就是等發布產品的時候才做的事情,因此對於開發人員來說,所有的工作永遠是測試。
通過前面的工作,我們已經准備好了交叉開發環境的硬體部分和一部分軟體,最後還缺少交叉編譯器,讀者可能會有疑問,為什麼要用交叉編譯器?前面已經講過,交叉開發環境必然會用到交叉編譯工具,通俗地講就是在一種平台上編譯出能運行在體系結構不同的另一種平台上的程序,開發主機PC平台(X86 CPU)上編譯出能運行在以ARM為內核的CPU平台上的程序,編譯得到的程序在X86 CPU平台上是不能運行的,必須放到ARM CPU平台上才能運行,雖然兩個平台用的都是Linux系統。相對於交叉編譯,平常做的編譯叫本地編譯,也就是在當前平台編譯,編譯得到的程序也是在本地執行。用來編譯這種跨平台程序的編譯器就叫交叉編譯器,相對來說,用來做本地編譯的工具就叫本地編譯器。所以要生成在目標機上運行的程序,必須要用交叉編譯工具鏈來完成。
這里又有一個問題,不就是一個交叉編譯工具嗎?為什麼又叫交叉工具鏈呢?原因很簡單,程序不能光編譯一下就可以運行,還得進行匯編和鏈接等過程,同時還需要進行調試,對於一個很大工程,還需要進行工程管理等等,所以,這里 說的交叉編譯工具是一個由 編譯器、連接器和解釋器 組成的綜合開發環境,交叉編譯工具鏈主要由binutils(主要包括匯編程序as和鏈接程序ld)、gcc(為GNU系統提供C編譯器)和glibc(一些基本的C函數和其他函數的定義) 3個部分組成。有時為了減小libc庫的大小,也可以用別的 c 庫來代替 glibc,例如 uClibc、dietlibc 和 newlib。
那麼,如何得到一個交叉工具鏈呢?是從網上下載一個「程序」然後安裝就可以使用了嗎?回答這個問題之前先思考這樣一個問題,我們的交叉工具鏈顧名思義就是在PC機上編譯出能夠在我們目標開發平台比如ARM上運行的程序,這里就又有一個問題了,我們的ARM處理器型號非常多,難道有專門針對我們某一款的交叉工具鏈嗎?若果有的話,可以想一想,這么多處理器平台,每個平台專門定製一個交叉工具鏈放在網路上,然後供大家去下載,想想可能需要找很久才能找到適合你的編譯器,顯然這種做法不太合理,且浪費資源!因此,要得到一個交叉工具鏈,就像我們移植一個Linux內核一樣,我們只關心我們需要的東西,編譯我們需要的東西在我們的平台上運行,不需要的東西我們不選擇不編譯,所以,交叉工具鏈的製作方法和系統移植有著很多相似的地方,也就是說,交叉開發工具是一個支持很多平台的工具集的集合(類似於Linux源碼),然後我們只需從這些工具集中找出跟我們平台相關的工具就行了,那麼如何才能找到跟我們的平台相關的工具,這就是涉及到一個如何製作交叉工具鏈的問題了。
通常構建交叉工具鏈有如下三種方法:
方法一 : 分步編譯和安裝交叉編譯工具鏈所需要的庫和源代碼,最終生成交叉編譯工具鏈。該方法相對比較困難,適合想深入學習構建交叉工具鏈的讀者。如果只是想使用交叉工具鏈,建議使用下列的方法二構建交叉工具鏈。
方法二: 通過Crosstool-ng腳本工具來實現一次編譯,生成交叉編譯工具鏈,該方法相對於方法一要簡單許多,並且出錯的機會也非常少,建議大多數情況下使用該方法構建交叉編譯工具鏈。
方法三 : 直接通過網上下載已經製作好的交叉編譯工具鏈。該方法的優點不用多說,當然是簡單省事,但與此同時該方法有一定的弊端就是局限性太大,因為畢竟是別人構建好的,也就是固定的,沒有靈活性,所以構建所用的庫以及編譯器的版本也許並不適合你要編譯的程序,同時也許會在使用時出現許多莫名其妙的錯誤,建議讀者慎用此方法。
crosstool-ng是一個腳本工具,可以製作出適合不同平台的交叉編譯工具鏈,在進行製作之前要安裝一下軟體:
$ sudo apt-get install g++ libncurses5-dev bison flex texinfo automake libtool patch gcj cvs cvsd gawk
crosstool腳本工具可以在http://ymorin.is-a-geek.org/projects/crosstool下載到本地,然後解壓,接下來就是進行安裝配置了,這個配置優點類似內核的配置。主要的過程有以下幾點:
1. 設定源碼包路徑和交叉編譯器的安裝路徑
2. 修改交叉編譯器針對的構架
3. 增加編譯時的並行進程數,以增加運行效率,加快編譯,因為這個編譯會比較慢。
4. 關閉java編譯器 ,減少編譯時間
5. 編譯
6. 添加環境變數
7. 刷新環境變數。
8. 測試交叉工具鏈
到此,嵌入式Linux系統移植四大部分的第一部分工作全部完成,接下來可以進行後續的開發了。
第二部分:bootloader的選擇和移植
01 Boot Loader 概念
就是在操作系統內核運行之前運行的一段小程序。通過這段小程序,我們可以初始化硬體設備、建立內存空間的映射圖,從而將系統的軟硬體環境帶到一個合適的狀態,以便為最終調用操作系統內核准備好正確的環境,他就是所謂的引導載入程序(Boot Loader)。
02 為什麼系統移植之前要先移植BootLoader?
BootLoader的任務是引導操作系統,所謂引導操作系統,就是啟動內核,讓內核運行就是把內核載入到內存RAM中去運行,那先問兩個問題:第一個問題,是誰把內核搬到內存中去運行?第二個問題:我們說的內存是SDRAM,大家都知道,這種內存和SRAM不同,最大的不同就是SRAM只要系統上電就可以運行,而SDRAM需要軟體進行初始化才能運行,那麼在把內核搬運到內存運行之前必須要先初始化內存吧,那麼內存是由誰來初始化的呢?其實這兩件事情都是由bootloader來乾的,目的是為內核的運行准備好軟硬體環境,沒有bootloadr我們的系統當然不能跑起來。
03 bootloader的分類
首先更正一個錯誤的說法,很多人說bootloader就是U-boot,這種說法是錯誤的,確切來說是u-boot是bootloader的一種。也就是說bootloader具有很多種類,
由上圖可以看出,不同的bootloader具有不同的使用范圍,其中最令人矚目的就是有一個叫U-Boot的bootloader,是一個通用的引導程序,而且同時支持X86、ARM和PowerPC等多種處理器架構。U-Boot,全稱 Universal Boot Loader,是遵循GPL條款的開放源碼項目,是由德國DENX小組開發的用於多種嵌入式CPU的bootloader程序,對於Linux的開發,德國的u-boot做出了巨大的貢獻,而且是開源的。
u-boot具有以下特點:
① 開放源碼;
② 支持多種嵌入式操作系統內核,如Linux、NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS;
③ 支持多個處理器系列,如PowerPC、ARM、x86、MIPS、XScale;
④ 較高的可靠性和穩定性;
⑤ 高度靈活的功能設置,適合U-Boot調試、操作系統不同引導要求、產品發布等;
⑥ 豐富的設備驅動源碼,如串口、乙太網、SDRAM、FLASH、LCD、NVRAM、EEPROM、RTC、鍵盤等;
⑦ 較為豐富的開發調試文檔與強大的網路技術支持;
其實,把u-boot可以理解為是一個小型的操作系統。
04 u-boot的目錄結構
* board 目標板相關文件,主要包含SDRAM、FLASH驅動;
* common 獨立於處理器體系結構的通用代碼,如內存大小探測與故障檢測;
* cpu 與處理器相關的文件。如mpc8xx子目錄下含串口、網口、LCD驅動及中斷初始化等文件;
* driver 通用設備驅動,如CFI FLASH驅動(目前對INTEL FLASH支持較好)
* doc U-Boot的說明文檔;
* examples可在U-Boot下運行的示常式序;如hello_world.c,timer.c;
* include U-Boot頭文件;尤其configs子目錄下與目標板相關的配置頭文件是移植過程中經常要修改的文件;
* lib_xxx 處理器體系相關的文件,如lib_ppc, lib_arm目錄分別包含與PowerPC、ARM體系結構相關的文件;
* net 與網路功能相關的文件目錄,如bootp,nfs,tftp;
* post 上電自檢文件目錄。尚有待於進一步完善;
* rtc RTC驅動程序;
* tools 用於創建U-Boot S-RECORD和BIN鏡像文件的工具;
05 u-boot的工作模式
U-Boot的工作模式有 啟動載入模式和下載模式 。啟動載入模式是Bootloader的正常工作模式,嵌入式產品發布時,Bootloader必須工作在這種模式下,Bootloader將嵌入式操作系統從FLASH中載入到SDRAM中運行,整個過程是自動的。 下載模式 就是Bootloader通過某些通信手段將內核映像或根文件系統映像等從PC機中下載到目標板的SDRAM中運行,用戶可以利用Bootloader提供的一些令介面來完成自己想要的操作,這種模式主要用於測試和開發。
06 u-boot的啟動過程
大多數BootLoader都分為stage1和stage2兩大部分,U-boot也不例外。依賴於cpu體系結構的代碼(如設備初始化代碼等)通常都放在stage1且可以用匯編語言來實現,而stage2則通常用C語言來實現,這樣可以實現復雜的功能,而且有更好的可讀性和移植性。
1、 stage1(start.s代碼結構)
U-boot的stage1代碼通常放在start.s文件中,它用匯編語言寫成,其主要代碼部分如下:
(1) 定義入口。由於一個可執行的image必須有一個入口點,並且只能有一個全局入口,通常這個入口放在rom(Flash)的0x0地址,因此,必須通知編譯器以使其知道這個入口,該工作可通過修改連接器腳本來完成。
(2)設置異常向量(exception vector)。
(3)設置CPU的速度、時鍾頻率及中斷控制寄存器。
(4)初始化內存控制器 。
(5)將rom中的程序復制到ram中。
(6)初始化堆棧 。
(7)轉到ram中執行,該工作可使用指令ldrpc來完成。
2、 stage2(C語言代碼部分)
lib_arm/board.c中的start armboot是C語言開始的函數,也是整個啟動代碼中C語言的主函數,同時還是整個u-boot(armboot)的主函數,該函數主要完成如下操作:
(1)調用一系列的初始化函數。
(2)初始化flash設備。
(3)初始化系統內存分配函數。
(4)如果目標系統擁有nand設備,則初始化nand設備。
(5)如果目標系統有顯示設備,則初始化該類設備。
(6)初始化相關網路設備,填寫ip,c地址等。
(7)進入命令循環(即整個boot的工作循環),接受用戶從串口輸入的命令,然後進行相應的工作。
07 基於cortex-a8的s5pc100bootloader啟動過程分析
s5pc100支持兩種啟動方式,分別為USB啟動方式和NandFlash啟動方式:
1. S5PC100 USB啟動過程
[1] A8 reset, 執行iROM中的程序
[2] iROM中的程序根據S5PC100的配置管腳(SW1開關4,撥到4對面),判斷從哪裡啟動(USB)
[3] iROM中的程序會初始化USB,然後等待PC機下載程序
[4] 利用DNW程序,從PC機下載SDRAM的初始化程序到iRAM中運行,初始化SDRAM
[5] SDRAM初始化完畢,iROM中的程序繼續接管A8, 然後等待PC下載程序(BootLoader)
[6] PC利用DNW下載BootLoader到SDRAM
[7] 在SDRAM中運行BootLoader
2. S5PC100 Nandflash啟動過程
[1] A8 reset, 執行IROM中的程序
[2] iROM中的程序根據S5PC100的配置管腳(SW1開關4,撥到靠4那邊),判斷從哪裡啟動(Nandflash)
[3] iROM中的程序驅動Nandflash
[4] iROM中的程序會拷貝Nandflash前16k到iRAM
[5] 前16k的程序(BootLoader前半部分)初始化SDRAM,然後拷貝完整的BootLoader到SDRAM並運行
[6] BootLoader拷貝內核到SDRAM,並運行它
[7] 內核運行起來後,掛載rootfs,並且運行系統初始化腳本
08 u-boot移植(基於cortex_a8的s5pc100為例)
1.建立自己的平台
(1).下載源碼包2010.03版本,比較穩定
(2).解壓後添加我們自己的平台信息,以smdkc100為參考版,移植自己s5pc100的開發板
(3).修改相應目錄的文件名,和相應目錄的Makefile,指定交叉工具鏈。
(4).編譯
(5).針對我們的平台進行相應的移植,主要包括修改SDRAM的運行地址,從0x20000000
(6).「開關」相應的宏定義
(7).添加Nand和網卡的驅動代碼
(8).優化go命令
(9).重新編譯 make distclean(徹底刪除中間文件和配置文件) make s5pc100_config(配置我們的開發板) make(編譯出我們的u-boot.bin鏡像文件)
(10).設置環境變數,即啟動參數,把編譯好的u-boot下載到內存中運行,過程如下:
1. 配置開發板網路
ip地址配置:
$setenv ipaddr 192.168.0.6 配置ip地址到內存的環境變數
$saveenv 保存環境變數的值到nandflash的參數區
網路測試:
在開發開發板上ping虛擬機:
$ ping 192.168.0.157(虛擬機的ip地址)
如果網路測試失敗,從下面幾個方面檢查網路:
1. 網線連接好
2. 開發板和虛擬機的ip地址是否配置在同一個網段
3. 虛擬機網路一定要採用橋接(VM--Setting-->option)
4. 連接開發板時,虛擬機需要設置成 靜態ip地址
2. 在開發板上,配置tftp伺服器(虛擬機)的ip地址
$setenv serverip 192.168.0.157(虛擬機的ip地址)
$saveenv
3. 拷貝u-boot.bin到/tftpboot(虛擬機上的目錄)
4. 通過tftp下載u-boot.bin到開發板內存
$ tftp 20008000(內存地址即可) u-boot.bin(要下載的文件名)
如果上面的命令無法正常下載:
1. serverip配置是否正確
2. tftp服務啟動失敗,重啟tftp服務
#sudo service tftpd-hpa restart
5. 燒寫u-boot.bin到nandflash的0地址
$nand erase 0(起始地址) 40000(大小) 擦出nandflash 0 - 256k的區域
$nand write 20008000((緩存u-boot.bin的內存地址) 0(nandflash上u-boot的位置) 40000(燒寫大小)
6. 切換開發板的啟動方式到nandflash
1. 關閉開發板
2. 把SW1的開關4撥到4的那邊
3. 啟動開發板,它就從nandflash啟動
7. 關於Mac上交叉編譯幾個小問題,求解答
我是打算編譯給模擬器脊喊悔用的庫喔。sysroot設置成simulator.platform相應的目錄了。但是還滲大是出櫻正現clang: warning: using sysroot for 'iPhoneSimulator' but targeting 'MacOSX'。雖然是warning但是不知道有沒影響。
8. 在linux中安裝交叉編譯器時的解包問題
具體操作步驟如下:
1. 下載
在GCC網站上( 3.3.1。可供下載的文件一般有兩種形式:gcc-3.3.1.tar.gz和 2,只是壓縮格式不一樣,內容完全一致,下載其中一種即可。
2. 解壓縮
根據壓縮格式,選擇下面相應的一種方式解包(以下的「%」表示命令行提示符):
% tar xzvf gcc-3.3.1.tar.gz
或者
% tar jxvf 2
新生成的gcc-3.3.1這個目錄被稱為源目錄,用${srcdir}表示它。以後在出現${srcdir}的地方,應該用真實的路徑來替換它。用pwd命令可以查看當前路徑。
在${srcdir}/INSTALL目錄下有詳細的GCC安裝說明,可用瀏覽器打開 ml閱讀。
3. 建立目標目錄
目標目錄(用${objdir}表示)是用來存放編譯結果的地方。GCC建議編譯後的文件不要放在源目錄${srcdir]中(雖然這樣做也可以),最好單獨存放在另外一個目錄中,而且不能是${srcdir}的子目錄。
例如,可以這樣建立一個叫 gcc-build 的目標目錄(與源目錄${srcdir}是同級目錄):
% mkdir gcc-build
% cd gcc-build
以下的操作主要是在目標目錄 ${objdir} 下進行。
4. 配置
配置的目的是決定將GCC編譯器安裝到什麼地方(${destdir}),支持什麼語言以及指定其它一些選項等。其中,${destdir}不能與${objdir}或${srcdir}目錄相同。
配置是通過執行${srcdir}下的configure來完成的。其命令格式為(記得用你的真實路徑替換${destdir}):
% ${srcdir}/configure --prefix=${destdir} [其它選項]
例如,如果想將GCC 3.3.1安裝到/usr/local/gcc-3.3.1目錄下,則${destdir}就表示這個路徑。
% ../gcc-3.3.1/configure --prefix=/usr/local/gcc-3.3.1 --enable-threads=posix --disable-checking --enable--long-long --host=i386-redhat-linux --with-system-zlib --enable-languages=c,c++,java
將GCC安裝在/usr/local/gcc-3.3.1目錄下,支持C/C++和JAVA語言,其它選項參見GCC提供的幫助說明。
5. 編譯
% make
這是一個漫長的過程。
6. 安裝
執行下面的命令將編譯好的庫文件等拷貝到${destdir}目錄中(根據你設定的路徑,可能需要管理員的許可權):
% make install
至此,GCC 3.3.1安裝過程就完成了。
6. 其它設置
GCC 3.3.1的所有文件,包括命令文件(如gcc、g++)、庫文件等都在${destdir}目錄下分別存放,如命令文件放在bin目錄下、庫文件在lib下、頭文件在include下等。由於命令文件和庫文件所在的目錄還沒有包含在相應的搜索路徑內,所以必須要作適當的設置之後編譯器才能順利地找到並使用它們。
6.1 gcc、g++、gcj的設置
要想使用GCC 3.3.1的gcc等命令,簡單的方法就是把它的路徑${destdir}/bin放在環境變數PATH中。我不用這種方式,而是用符號連接的方式實現,這樣做的好處是我仍然可以使用系統上原來的舊版本的GCC編譯器。
首先,查看原來的gcc所在的路徑:
% which gcc
在系統上,上述命令顯示:/usr/bin/gcc。因此,原來的gcc命令在/usr/bin目錄下。可以把GCC 3.3.1中的gcc、g++、gcj等命令在/usr/bin目錄下分別做一個符號連接:
% cd /usr/bin
% ln -s ${destdir}/bin/gcc gcc33
% ln -s ${destdir}/bin/g++ g++33
% ln -s ${destdir}/bin/gcj gcj33
這樣,就可以分別使用gcc33、g++33、gcj33來調用GCC 3.3.0的gcc、g++、gcj完成對C、C++、JAVA程序的編譯了。同時,仍然能夠使用舊版本的GCC編譯器中的gcc、g++等命令。
9. android驅動開發好了,怎麼調試
本文用《Android深度探索(卷1):HAL與驅動開發》的隨書源代碼為例詳細說明如何配置Android驅動開發和測試環境,並且如何使用源代碼中的build.sh腳本文件在各種平台(Ubuntu Linux、Android模擬器和S3C6410開發板)上編譯、安裝和測試Linux驅動。建議讀者使用Ubuntu Linux12.04或更高版本實驗本文的方法。最好用root賬號登錄Linux。
一、安裝交叉編譯器
如果只是在Ubuntu Linux上測試Linux驅動就不需要安裝交叉編譯器了,但要在Android模擬器或S3C6410開發板上進行測試,就必須安裝交叉編譯器。
首先下載交叉編譯器(分卷壓縮)
下載後解壓,會發現有兩個tgz文件,可以將這兩個文件放到/root/compilers目錄中,在Linux終端進入該目錄,執行如下命令安裝交叉編譯器。
[plain] view plain
# tar zxvf arm-linux-gcc-4.3.2.tgz -C /
# tar jxvf arm-none-linux-gnueabi-arm-2008q3-72-for-linux.tar.bz2 -C /
二、編譯和測試Linux內核
這里的Linux內核有兩個,一個是goldfish,也就是Android模擬器使用的Linux內核、另外一個是S3C6410開發板使用的Linux內核(Linux2.6.36)。讀者首先要下載這兩個Linux內核。
Android模擬器用的Linux內核源代碼(分卷壓縮)
用於S3C6410開發板的Linux內核源代碼(分卷壓縮)
分卷1
分卷2
由於隨書代碼中的word_count驅動已經在goldfish和linux2.6.36中分別建立了符號鏈接,以便在編譯linux內核時同時也會編譯word_count驅動,所以linux內核與源代碼目錄應與作者機器上的目錄相同。也就是兩個linux內核目錄與源代碼目錄如下:
linux內核目錄
/root/kernel/goldfish
/root/kernel/linux_kernel_2.6.36
源代碼目錄
/root/drivers
注意/root/drivers目錄下就直接是每一章的源代碼了,例如/root/drivers/ch06、/root/drivers/ch07
現在需要將/usr/local/arm/arm-none-linux-gnueabi/bin路徑加到Linux的PATH環境變數中(不會加的上網查,這是Linux的基本功)
最後進入/root/compilers/goldfish目錄,執行make命令編譯linux內核,如果完全編譯,大概20分鍾左右。編譯完成後,會在/root/kernel/goldfish/arch/arm/boot目錄中生成一個zImage文件,代碼1.7MB,這就是用於Android模擬器的Linux內核文件。
三、編譯Linux驅動
現在來編譯隨書光碟的驅動程序,這里以word_count驅動為例。在Linux終端進入/root/drivers/ch06/word_count目錄。先別忙著編譯。首先要設置打開/root/drivers/common.sh文件,修改第一行UBUNTU_KERNEL_PATH變數值為自己機器上安裝的Ubuntu Linux內核路徑,只要執行「ls /usr/src」命令即可查看當前機器可用的linux內核。如可以設置下面的路徑。
UBUNTU_KERNEL_PATH=/usr/src/linux-headers-3.2.0-23-generic
剩下的兩個(S3C6410_KERNEL_PATH和/root/kernel/goldfish)只要按著前面的路徑解壓Linux內核源代碼,就不用設置了。
在word_count目錄中執行「source build.sh」命令,會允許選擇在哪個平台上編譯驅動,直接按回車會在Ubuntu Linux上編譯。如果編譯成功,會發現當前目錄多一個word_count.ko文件(驅動文件)。
現在來編譯S3C6410上運行的word_count驅動。先別忙,在編譯之前,需要Android中的adb命令。因為build.sh足夠只能,在編譯完後,如果有多個Android設備連接到PC,會允許用戶選擇上傳到哪個設備裝載,這里需要選擇S3C6410開發板,然後會直接上傳到開發板上,如圖1所示。
可以直接使用adb shell命令進入開發板,也可以使用/root/drivers/shell.sh腳本完成同樣的工作,只是後者如果有多個android設備,會允許用選擇,而不是輸入相應的設備ID。使操作更方便。在/root/drivers目錄中提供了很多這樣的腳本(shell.sh、push.sh、pull.sh等),這些腳本都會允許用戶選擇操作的Android設備。
我們通常使用Android SDK中的adb命令,到官方網站下載裝載linux版本的Android SDK,然後將<AndroidSDK根目錄> /platform-tools加到PATH環境變數中。
現在再次執行「source build.sh」命令,選擇第2項(S3C6410開發板),如果系統沒找到開發板,需要將USB線拔下重插一下。然後就可以進入開發板的終端,輸入lsmod命令查看驅動的安裝情況了。
如果在模擬器上測試,選第3項。具體測試的方法請參見書中相應的章節。
四、測試Linux驅動
測試word_count驅動的方法很多,通過命令行測試的方法請參見書中相應的章節,在word_count目錄中有一個test_word_count程序,通過執行如下的命令可以測試word_count驅動,編譯test_word_count.c程序的方法書中已詳細描述。
test_word_count 「abc bb cc」
上面的命令會輸出單詞數為3。
如果要編譯Android HAL,需要Android源代碼。購買S3C6410開發板時商家通常會帶一些光碟,裡面有用於開發板的Android源代碼,如果商家沒給光碟,別忘了要哦!
10. Qt creator 可以編寫ARM linux的驅動嗎
QT主要是應用於上層應用軟體的開發,一般不能做驅動的開發,驅動層是跟操作系統內核早頌緊密關聯的。qmake是QT的編譯命令,make是GCC的編譯命令。做驅動用什麼還得看你是要給什麼操作信散系統添加設備。如果是windows就用WIN ddk吧,如果是Linux就用gcc,前者是一個類似於VC的集成開發環境,後者只是一個編陸坦鄭譯器。可以用任意的文本編輯器寫代碼,然後寫Makefile,編譯出驅動。