這兩天需要把一個CDVS的工程代碼從Linux 平台上移植到ARM平台上,花了兩天才搞定,之前很早申請的博客,到現在還沒有技術文章會,以后決定凡是花兩三天才搞定的東西都會把解決過程發到這里,很多東西靠百度什么的不太好使,必要的時候確實Google更好用。想想也是,在百度上搜,很多都是迄今為止中國程序員碰到過的問題,在Google上搜就是全世界程序員碰到過的問題。廢話不多說了,切入正題。
由於原工程已經在PC-Linux上跑通,所以只需要修改configure的配置參數即可。這里我通過linux下的build.sh來對configure傳入腳本。
下面試build.sh的腳本內容:
1 #!/bin/sh 2 # build the CDVS Test Model 3 # with full optimizations and multithreading: 4 CFLAGS="-march=armv7-a -O2 -DNDEBUG -fopenmp -pipe" 5 export PATH=$PATH:/usr/local/arm/arm-hik_v7a-linux-uclibcgnueabi/bin 6 # run configure with optimization flags and prepending "tm-" to all binaries (e.g. tm-extract, tm-match, etc.) 7 mkdir -p build 8 cd build 9 CC=arm-hik_v7a-linux-uclibcgnueabi-gcc CXX=arm-hik_v7a-linux-uclibcgnueabi-c++ LD=arm-hik_v7a-linux-uclibcgnueabi-ld AR=arm-hik_v7a-linux-uclibcgnueabi-ar AS=arm-hik_v7a-linux-uclibcgnueabi-as NM=arm-hik_v7a-linux-uclibcgnueabi-nm STRIP= RANLIB=arm-hik_v7a-linux-uclibcgnueabi-strip OBJDUMP=arm-hik_v7a-linux-uclibcgnueabi-objdump ../configure --build=i386-pc-linux-gnu --host=arm-hik_v7a-linux-uclibcgnueabi --target=arm-hik_v7a-linux-uclibcgnueabi --cache-file=arm-hik_v7a-linux-uclibcgnueabi.cache prefix=$HOME/cdvs_bin_for_arm --program-prefix="tm-" CFLAGS="${CFLAGS}" CXXFLAGS="${CFLAGS}" 10 # build all binaries 11 make 12 # install all binaries in $HOME/bin (no need of admin priviledges) 13 make install
對腳本的內容進行分析:
首先是CFLAGS,里面定義了需要傳入到configure的參數這里的-march變量是目標機的系統架構也就是architecture,由於我們的目標機上平台是armv7-a,所以此處賦值armv7-a。此處要留心,我一開始沒有改,依然是native,那么configure會自動的用本機的arch值傳入,這樣就會編譯失敗。我一開始也不清楚這個地方具體應該填什么。這樣我們可以查看編譯器支持的芯片類型。
我的編譯器的前綴是arm-hik_v7a-linux-uclibcgnueabi,所以這是這個編譯器下所有工具的前綴。
由於交叉編譯器已經安裝在/usr/local/arm目錄下,並且已經把/uar/local/arm/arm-hik_v7a-linux-uclibcgnueabi/bin目錄添加到/etc/profile文件中,所以在控制台中可以直接調用編譯器。
在控制台中我們輸入arm-hik_v7a-linux-uclibcgnueabi-gcc -v 此命令會輸出該編譯器的版本信息
在輸出圖片中我們可以看到變量--with-arch=armv7-a,一開始輸成了ARMv7-A,各種亂試,確實需要從根源下手,直接查看編譯器版本信息。OK,接下來進入下一步。
可以看到腳本中還有一句PATH=$PATH:/usr/local/arm/arm-hik_v7a-linux-uclibcgnueabi/bin 這是對當前腳本執行的環境加上環境變量,不知道為什么在系統中添加環境變量后還是腳本運行時不能檢索到編譯器位置,一直報錯,可以看config.log的輸出日志。
PATH: /usr/local/sbin PATH: /usr/local/bin PATH: /usr/sbin PATH: /usr/bin PATH: /sbin PATH: /bin
在這里並沒有將我們環境變量的值給讀進來,
而我打開終端中直接打印PATH,發現值已經在里面了。此處不太明白,所以我在build.sh里又中添加了export語句在臨時追加環境變量。
louyihang@ubuntu:~$ echo $PATH /home/louyihang/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/arm/arm-hik_v7a-linux-uclibcgnueabi/bin:/usr/local/arm/arm-hik_v7a-linux-uclibcgnueabi/bin
接着我們在當前目錄下用mkdir 創建build文件夾,整個編譯過程中的各種輸出文件都將會在這里除了最后的exe。
在下面可以看到我定義了一堆變量,用來指定編譯器
CC=arm-hik_v7a-linux-uclibcgnueabi-gcc CXX=arm-hik_v7a-linux-uclibcgnueabi-c++ LD=arm-hik_v7a-linux-uclibcgnueabi-ld AR=arm-hik_v7a-linux-uclibcgnueabi-ar AS=arm-hik_v7a-linux-uclibcgnueabi-as NM=arm-hik_v7a-linux-uclibcgnueabi-nm STRIP= RANLIB=arm-hik_v7a-linux-uclibcgnueabi-strip OBJDUMP=arm-hik_v7a-linux-uclibcgnueabi-objdump ../configure --build=i386-pc-linux-gnu --host=arm-hik_v7a-linux-uclibcgnueabi --target=arm-hik_v7a-linux-uclibcgnueabi --cache-file=arm-hik_v7a-linux-uclibcgnueabi.cache prefix=$HOME/cdvs_bin_for_arm --program-prefix="tm-" CFLAGS="${CFLAGS}" CXXFLAGS="${CFLAGS}"
CC變量指定的是gcc編譯器,可以在configure文件中得知這個變量來告訴configure關於交叉編譯器gcc的信息,同理CXX 指的是C++,只要前綴不變,所以接下來依樣畫葫蘆把所需要用到的編譯器直接定義在 configure語句執行之前。
CC=arm-hik_v7a-linux-uclibcgnueabi-gcc CXX=arm-hik_v7a-linux-uclibcgnueabi-c++ LD=arm-hik_v7a-linux-uclibcgnueabi-ld AR=arm-hik_v7a-linux-uclibcgnueabi-ar AS=arm-hik_v7a-linux-uclibcgnueabi-as NM=arm-hik_v7a-linux-uclibcgnueabi-nm STRIP= RANLIB=arm-hik_v7a-linux-uclibcgnueabi-strip OBJDUMP=arm-hik_v7a-linux-uclibcgnueabi-objdump
需要注意的是其實你這些語句總共是4行,其實這里是沒有回車的,因為這整個一長串都是一條語句,只不過在configure的的編譯器參數需要再configure之前被設置。
OK這里弄完。接着看我們configure之后的參數。
--build參數指定的是編譯器完成整個build的工程的機器結構在這里我們輸入i386-pc-linux-gnu
--host參數指定最終生成可執行文件的運行環境 arm-hik_v7a-linux-uclibcgnueabi (也就是我們用的交叉編譯器工具的前綴——即編譯器的文件夾的名字 )這些都是一致的
--target參數目標機的環境等同host。
--cache-file在這里指定緩存文件的名字,在該文件中我們可以看到編譯過程中的整個測試過程的結果和反饋。
--prefix=$Home/cdvs_bin_for_arm 這里是最終生成可執行文件的安裝目錄也就是exe的存放目錄。可以根據自己的需要調整。
后面的--program-prefix CFLAGS CXXFLAGS的參數與linux PC機上一樣不用調整。
OK最后在最后跟上make make install 完成整個configure的配置。
當然什么事情都不會跟教程一樣順利,接下來的問題總是不斷。
在終端中輸入 sudo ./build.sh | more
看輸出內容
可以看到出現了 checking whether the C compiler works ...no 后面還出現了error。
看來 交叉編譯器並沒有開始工作。所以轉入到build 文件夾下 打開config.log的輸出日志。
看到一條語句 arm-hik_v7a-linux-uclibcgnueabi-gcc-raw: libgomp.spec: No such file or directory
很明顯這是由於庫里少了一個文件,沒有被編譯器找到,所以需要再庫里面添加進liggomp.spec這個文件。
當時把我迷糊了好久,上哪里去整個這個文件,上百度也百度不到,上google也不好使。
想到他畢竟是個gcc的編譯器,庫里面的東西大概都差不多吧,所以我去找了標准的arm-linux-gcc的庫文件,記得當時的百度雲里還有一份stm32的資料,整了一個下來。
打開這個arm-linux-gcc-4.4.3.tgz直接在壓縮包里面檢索關鍵字libgomp
果然在這個編譯器同樣的lib下有了一堆跟libgomp相關的文件,所以把這些文件拷入到我們所需要的arm-hik_v7a-linux-uclibcgnueabi的編譯器庫下面
OK再運行一次configure
咦,居然還是不過,再次看config.log文件
看到中間有一句 lib/libgomp.so: file not recognized: treating as linker script 和下面 lib/libgomp.so:1: syntax error。 不識別,這文件應該是不需要的被引入了,所以在Lib中將其刪除。再次運行
OK 大功告成,可以看到whether the C compiler works .... yes 接下來一堆文件的測試,並且在指定目錄生成了exe。
整個過程花了差不多2天時間,第一次弄交叉編譯,確實是有點費勁的,也發現了一些自己的不足,之前沒有看log文件的習慣,后來發現這個東西是非常好的,非常有助於我們分析問題的原因。第一次寫blog,寫的比較亂,希望能幫到碰到同樣問題的你!