江蘇省徐州市建設(shè)銀行網(wǎng)站a站
1. 交叉編譯是什么?
交叉編譯簡單說來,就是編譯成果物的地兒不是你運行這個成果物的地兒。最常見的場景,就是我們要編譯一個 ARM版本
的可執(zhí)行程序,但我們編譯這個 ARM版本
可執(zhí)行程序的地方,是在一個 x86_x64
的平臺上。
2. 為什么需要交叉編譯?
絕大部分的原因,是目標(biāo)平臺不具備編譯成果物的算力。具體說來,就是ARM平臺早期是 并沒有
編譯代碼所需的 算力
和 相關(guān)空間
的。所以,不得不借助性能更高的平臺來輔助進行編譯成果物,然后ARM平臺僅負責(zé)運行成果物即可。
3. 交叉編譯只能在目標(biāo)平臺同一系統(tǒng)上嗎?
雖然絕大多數(shù)的 ARM Linux系統(tǒng)中編譯的成果物是在對應(yīng)的 x86_x64平臺的Linux系統(tǒng)中進行的,所以大多數(shù)時候使用Windows平臺電腦需要安裝一個虛擬機或者連接到某個x86_x64平臺的Linux編譯服務(wù)器中,但實際上這種搭配大多數(shù)情況是為了方便,也為了讓編譯者熟悉Linux環(huán)境,但這種搭配并不是唯一的解決方案。
ARM官網(wǎng) 上就能直接下載各種平臺( Linux
、Windows
)的編譯工具鏈,另外一個很常見的第三方工具鏈制作商,linaro也是對外直接提供可用版本的工具鏈,但不支持全平臺, linaro gnu。
如果上述兩個網(wǎng)站你都覺得不是很符合自己的開發(fā)板,那么你也可以自己動手做一個鏈子,符合目標(biāo)平臺的交叉編譯鏈制作及簡單分析。 這里主要使用crosstool-ng
這個工具進行的制作,自己做鏈子的好處是你可以自己按需選擇對應(yīng)的gcc版本,以及glibc版本和一些其他重要基礎(chǔ)庫的版本。而上面現(xiàn)成的鏈子可能并不剛好是你需要的版本搭配。
4. 如何編譯一個第三方開源庫?
以下編譯前提均假設(shè)編譯人員已經(jīng)獲得了一個可以使用的交叉編譯工具鏈,并且已經(jīng)將編譯工具鏈的可執(zhí)行程序設(shè)置進環(huán)境變量。
4.1 最常見也是最簡單的編譯方式
大多數(shù)的簡單第三方庫,均可以嘗試以下的方式。這里的簡單,值得是不額外依賴一些其他第三方庫的庫。
configure --host=arm-linux-gnueabi --prefix=${PWD}/build
make
make install
一般驗證自己是不是編譯的正確的主要檢查步驟就是,在make的時候查看對應(yīng)輸出打印,如果開頭的的編譯的確是對應(yīng)編譯工具鏈名稱的開頭,那么至少配置是對的,這里給個例子:
/bin/sh ../libtool --tag=CXX --mode=compile arm-at91-linux-gnueabi-g++ -std=gnu++11 -DHAVE_CONFIG_H -I. -I.. -I/data1/xiaoyanyi/work/snmp++/snmp++-3.5.0/include -pthread -I/data1/xiaoyanyi/work/openssllll/include -D_GNU_SOURCE -g -O2 -pthread -MT asn1.lo -MD -MP -MF .deps/asn1.Tpo -c -o asn1.lo asn1.cpp
libtool: compile: arm-at91-linux-gnueabi-g++ -std=gnu++11 -DHAVE_CONFIG_H -I. -I.. -I/data1/xiaoyanyi/work/snmp++/snmp++-3.5.0/include -pthread -I/data1/xiaoyanyi/work/openssllll/include -D_GNU_SOURCE -g -O2 -pthread -MT asn1.lo -MD -MP -MF .deps/asn1.Tpo -c asn1.cpp -fPIC -DPIC -o .libs/asn1.o
libtool: compile: arm-at91-linux-gnueabi-g++ -std=gnu++11 -DHAVE_CONFIG_H -I. -I.. -I/data1/xiaoyanyi/work/snmp++/snmp++-3.5.0/include -pthread -I/data1/xiaoyanyi/work/openssllll/include -D_GNU_SOURCE -g -O2 -pthread -MT asn1.lo -MD -MP -MF .deps/asn1.Tpo -c asn1.cpp -o asn1.o >/dev/null 2>&1
make的過程中,輸出的打印里的確是以我們指定的host開頭的,那么這步驟至少是沒問題的了。
4.2.1 簡單解釋一下configure里面常見通用參數(shù)的含義
先簡單的介紹一下 configure
make
make install
三部曲每部分是做了什么,然后在展開介紹configure的通用參數(shù)。
configure
: 通過配置生成makefile文件
make
:使用configure生成的Makefile文件進行編譯工作
make install
:將make生成的成果物文件按照prefix的路徑進行復(fù)制,有時候也會動態(tài)生成一些說明文檔
所以大多數(shù)時候,configure
配置對了,后面兩步就一定能走通,99%的編譯不過問題基本都是configure
的時候配置不對。以下重點講解configure
相關(guān)的參數(shù)。
4.2.1.1 prefix
這里prefix中文解釋就是安裝路徑,也就是make install的時候,最終這些庫會放到哪里去。一般對于交叉編譯而言,是需要指定的,因為默認的路徑是 /usr/local/
,但這路徑實際上對于交叉編譯而言一定是不行的。因為這個路徑通常放的是本身系統(tǒng)的庫,如果交叉編譯的庫放進去后,本身系統(tǒng)也會去檢索這個路徑下的庫,名字雖然匹配上了,但是用不起來,后續(xù)會造成極大的麻煩。
這里還有一點需要額外注意的,后文會重新展開這個問題。這里先說結(jié)論:
如果你需要編譯的庫ABC依賴DEF,那么你先編譯DEF的時候,最好把prefix設(shè)置成自己交叉編譯鏈的
sysroot/usr
中。
4.2.1.2 host
簡單解釋一下,交叉編譯和普通的編譯第三方庫差異主要在于需要指定host這個變量。這里貼一段標(biāo)準(zhǔn)解釋:
System types:--build=BUILD configure for building on BUILD [guessed]--host=HOST cross-compile to build programs to run on HOST [BUILD]
這里僅需要額外強調(diào)一點,host這個參數(shù)的指定邏輯和使用的目標(biāo)編譯工具鏈名稱有關(guān),假設(shè)你的編譯工具鏈的gcc名字叫 arm-at91-linux-gnueabi-gcc
,那么這里的host名字就是 arm-at91-linux-gnueabi
。具體的邏輯就是把對應(yīng)鏈子的 -gcc
部分拆掉就是host的名字。其實configure腳本的邏輯也就是對應(yīng)的反向在host后拼接一個 -gcc
而已。
4.2.1.3 enable-xxxxx disable-xxxxx
這兩個參數(shù)一般是在編譯的時候,可配置的打開某些功能或者關(guān)閉某些功能的時候,會使用到。每個第三方庫的特色不一樣,這里推薦遇到編譯不過的問題,首先就去看看:
./configure --help
有時候發(fā)現(xiàn)你編譯的第三方庫依賴了過多的其他庫,而且這些功能對你并不需要的時候,可以盡可能的--disable-xxxxx
和 --without-xxxx
。這樣,在后續(xù)make的時候,就不會出現(xiàn)某些依賴庫找不到的報錯了。
4.2.1.4 CXX CC CFLAGS
這些shell環(huán)境變量也會產(chǎn)生一定的效果,有時候你百度一些博客教程的時候,會搜到交叉編譯的某些指導(dǎo)文檔會這么寫:
./configure CC=arm-linux-gnueabi-gcc --prefix=${PWD}/build
make
make install
或者寫成這樣:
export CC=arm-linux-gnueabi-gcc
./configure --prefix=${PWD}/build
make
make instal
這兩種手法的思路一致的,都是利用./configure 腳本是可以閱讀當(dāng)前shell環(huán)境變量中的CC
,并且將這個環(huán)境變量替換到腳本里,從而實現(xiàn)CC
替換成對應(yīng)鏈子的目的。相關(guān)解釋同樣可以在--help
中看到
Some influential environment variables:CC C compiler commandCFLAGS C compiler flagsLDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in anonstandard directory <lib dir>
但需要注意的一點是:這種方法有一些隱患,主要在于在很多時候,交叉編譯并不是把gcc
變成arm-linux-gnueabi-gcc
一切就完事了。我們可以在Makefile中和交叉編譯鏈的bin
路徑中看到如下打印:
(base) xiaoyanyi@snmp++-3.5.0$ls ~/cross-tool/arm-at91-linux-gnueabi/bin
arm-at91-linux-gnueabi-addr2line arm-at91-linux-gnueabi-gcc-4.9.2 arm-at91-linux-gnueabi-nm
arm-at91-linux-gnueabi-ar arm-at91-linux-gnueabi-gcc-ar arm-at91-linux-gnueabi-objcopy
arm-at91-linux-gnueabi-as arm-at91-linux-gnueabi-gcc-nm arm-at91-linux-gnueabi-objdump
arm-at91-linux-gnueabi-c++ arm-at91-linux-gnueabi-gcc-ranlib arm-at91-linux-gnueabi-populate
arm-at91-linux-gnueabi-cc arm-at91-linux-gnueabi-gcov arm-at91-linux-gnueabi-ranlib
arm-at91-linux-gnueabi-c++filt arm-at91-linux-gnueabi-gdb arm-at91-linux-gnueabi-readelf
arm-at91-linux-gnueabi-cpp arm-at91-linux-gnueabi-gprof arm-at91-linux-gnueabi-size
arm-at91-linux-gnueabi-ct-ng.config arm-at91-linux-gnueabi-ld arm-at91-linux-gnueabi-strings
arm-at91-linux-gnueabi-elfedit arm-at91-linux-gnueabi-ld.bfd arm-at91-linux-gnueabi-strip
arm-at91-linux-gnueabi-g++ arm-at91-linux-gnueabi-ldd
arm-at91-linux-gnueabi-gcc arm-at91-linux-gnueabi-ld.gold
有些Makefile生成的環(huán)境中還需要使用AR
,NM
,RANLIB
等等,這些東西也需要使用對應(yīng)的交叉編譯工具鏈版本的程序。而上述的CC
手法僅僅替換了一個。所以為什么是存在風(fēng)險和后續(xù)還會遇到問題的。
這里推薦,如果能用host,就優(yōu)先使用host指定,這種方式相當(dāng)于自動幫你設(shè)置了上述每一個需要替換的變量。
在極少數(shù)的時候,host不被confiugre支持,那么能用的方法只有這種了,但同時也是最不同推薦的。
4.2.2 對于編譯自依賴的第三方庫族的推薦方法
有時候,我們使用的第三方庫有兩層甚至多層,底層他們自己開發(fā)了一個基礎(chǔ)庫,然后在自己的基礎(chǔ)庫上,封了一層應(yīng)用。例如protobuf和grpc,snmp++和agent++。這個時候,我們需要先編譯基礎(chǔ)庫,然后在編譯應(yīng)用庫。這一點很容易理解,從下到上,但對于交叉編譯來說,又有一點需要注意的。主要和 prefix
有關(guān)。
當(dāng)我們編譯完基礎(chǔ)庫之后,一般make install
之后,成果物大多情況是這樣的[假設(shè)我們安裝到了一個build目錄]:
(base) xiaoyanyi@build$ls
bin include lib
bin
: 目錄一般是這個庫的一些demo樣例或者一些可執(zhí)行程序。
include
:目錄一般就是這個第三方庫的頭文件
lib
:目錄一般就是這個第三方庫的靜態(tài)、動態(tài)庫文件
那么在編譯上層應(yīng)用庫的時候,有些教程會推薦按照configure
中的指定底層庫路徑宏變量的方式,去顯式指定對應(yīng)路徑。
例如agent++
這個庫,依賴snmp++
,其中agent++的confiugre文件里有這樣一個變量:
Some influential environment variables:PKG_CONFIG path to pkg-config utilityPKG_CONFIG_PATHdirectories to add to pkg-config's search pathPKG_CONFIG_LIBDIRpath overriding pkg-config's built-in search pathCXXCPP C++ preprocessorsnmp_CFLAGS C compiler flags for snmp, overriding pkg-configsnmp_LIBS linker flags for snmp, overriding pkg-configLT_SYS_LIBRARY_PATHUser-defined run-time library search path.
這里可以通過snmp_LIB
這個變量顯式指定去libsnmp++.so
的位置。這種方式在表面上是能夠通過編譯并且不會出現(xiàn)什么太大問題的。但會買下一個隱患在于后續(xù)使用庫或者維護的時候會出現(xiàn)問題。這里需要講解造成這個隱患問題的另外兩個文件。
4.2.2.1 *.la
一般編譯完成的第三方庫的lib文件夾下面,會有一個對應(yīng)擴展名為la的文件。
例如:
(base) xiaoyanyi@lib$ls
libsnmp++.a libsnmp++.la libsnmp++.so libsnmp++.so.35 libsnmp++.so.35.0.0 pkgconfig
這個la文件實際上并不是一個靜/動態(tài)庫程序,而是一個配置文件,我們可以直接vim打開:
# libsnmp++.la - a libtool library file
# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-14
#
# Please DO NOT delete this file!
# It is necessary for linking the library.# The name that we can dlopen(3).
dlname='libsnmp++.so.35'# Names of this library.
library_names='libsnmp++.so.35.0.0 libsnmp++.so.35 libsnmp++.so'# The name of the static archive.
old_library='libsnmp++.a'# Linker flags that cannot go in dependency_libs.
inherited_linker_flags=' -pthread'# Libraries that this one depends upon.
dependency_libs=' -lssl -lcrypto
/data1/xiaoyanyi/cross-tool/arm-at91-linux-gnueabi/arm-at91-linux-gnueabi/lib/libstdc++.la'# Names of additional weak libraries provided by this library
weak_library_names=''# Version information for libsnmp++.
current=35
age=0
revision=0# Is this an already installed library?
installed=yes# Should we warn about portability when linking against -modules?
shouldnotlink=no# Files to dlopen/dlpreopen
dlopen=''
dlpreopen=''# Directory that this library needs to be installed in:
libdir='/data1/xiaoyanyi/work/snmp++/snmp++-3.5.0/build/lib'
關(guān)鍵的問題就在最后的
libdir
里,這個路徑指明了這個動態(tài)庫的安裝路徑,在連接的過程中,如果有動態(tài)庫依賴動態(tài)庫的情況,gcc的連接應(yīng)用會順著路徑去查找隨影目標(biāo)文件。而如果我們安裝的時候,就隨意選一個build目錄。最后即便是把這個路徑放到了sysroot里去之后,這個la文件里面的內(nèi)容依舊不會變,導(dǎo)致最后就找不到了。
4.2.2.2 pkgconfig *.pc
大多數(shù)庫編完之后,除了上述的la,其實大家也可以在lib里面找到有一個pkgconfig文件夾,里面會有一個對應(yīng)的pc文件。
這個文件和la文件的作用極為相似,也是一個配置文件,我們可以打開看看。
prefix=/data1/xiaoyanyi/work/snmp++/snmp++-3.5.0/build
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
modules=Name: snmp++
Version: 3.5.0
Description: SNMP C++ framework version 3
Requires:
Libs: -L${libdir} -lsnmp++
Libs.private: -lssl -lcrypto
Cflags: -I${includedir}
這里造成錯誤的原因是因為prefix這個變量也是會因為隨意指定從而即便pc文件的位置移動也無法正確索引。pc文件主要是pkg-config這個應(yīng)用為了編譯的時候自動指定FLAGS和自動找?guī)煊玫摹?/p>
4.2.2.3 那么應(yīng)該安裝在哪里比較合適呢?
這里推薦的路徑是安裝在編譯工具鏈的sysroot中。
一般用crosstool-ng做的交叉工具鏈,對應(yīng)的sysroot是在
${host}/${host}/sysroot/
對于其他的鏈子,基本也都有一個sysroot,可以自行查找。而我們安裝一般的第三方庫,一般推薦放在sysroot中的usr中,因為不是系統(tǒng)庫,而是用戶自己制作的。
這個路徑下的,例如我做了一個鏈子,host是 arm-at91-linux-gnueabi
,那么對應(yīng)的sysroot/usr路徑是:
arm-at91-linux-gnueabi/arm-at91-linux-gnueabi/sysroot/usr/
所以絕大部分的時候,將第三方庫的prefix指定為上述路徑,可以直接將第三方庫安裝到編譯工具鏈中,從而達到后續(xù)編譯其他庫的時候,鏈子會自動索引已經(jīng)安裝過的庫,不需要顯示指定對應(yīng)路徑的目的。
但這里同樣有一個風(fēng)險點:如果對應(yīng)第三方庫的更新較為頻繁,那么就可能存在要編譯的新庫但sysroot里有個老庫的場景。這里推薦是更新較為頻繁的庫不要放到sysroot里去。
4.2 一些不常見但是常用的第三方庫可能的編譯方式
4.1里介紹的手法基本上能處理絕大多數(shù)的第三方庫,但仍舊有某些庫的configure
寫的比較奇特,按照常規(guī)三部曲無法解決的。一般通用的處理思路還是好好閱讀configure --help
,同時這里重點解釋兩個場景。
4.2.1 常見開源加密算法庫OpenSSL
這個動態(tài)庫的交叉編譯就不合適上述的情況,configure
中并沒有指定host
的能力,這里推薦的建議是這樣,先說結(jié)果:
./Configure linux-armv4 no-asm shared
這個庫為什么會這么輸入,我們又是如何知道的呢?其實還是看configure --help
就能發(fā)現(xiàn)端倪。
(base) xiaoyanyi@openssl-1.0.2t$./Configure --help
Configuring for
Usage: Configure [no-<cipher> ...] [enable-<cipher> ...] [experimental-<cipher> ...] [-Dxxx] [-lxxx] [-Lxxx] [-fxxx] [-Kxxx] [no-hw-xxx|no-hw] [[no-]threads] [[no-]shared] [[no-]zlib|zlib-dynamic] [no-asm] [no-dso] [no-krb5] [sctp] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] [--with-xxx[=vvv]] [--test-sanity] os/compiler[:flags]pick os/compiler from:
BC-32 BS2000-OSD BSD-generic32 BSD-generic64 BSD-ia64 BSD-sparc64 BSD-sparcv8
BSD-x86 BSD-x86-elf BSD-x86_64 Cygwin Cygwin-x86_64 DJGPP MPE/iX-gcc OS2-EMX
OS390-Unix QNX6 QNX6-i386 ReliantUNIX SINIX SINIX-N UWIN VC-CE VC-WIN32
VC-WIN64A VC-WIN64I aix-cc aix-gcc aix3-cc aix64-cc aix64-gcc android
android-armv7 android-mips android-x86 android64-aarch64 aux3-gcc
beos-x86-bone beos-x86-r5 bsdi-elf-gcc cc cray-j90 cray-t3e darwin-i386-cc
darwin-ppc-cc darwin64-ppc-cc darwin64-x86_64-cc dgux-R3-gcc dgux-R4-gcc
dgux-R4-x86-gcc dist gcc hpux-cc hpux-gcc hpux-ia64-cc hpux-ia64-gcc
hpux-parisc-cc hpux-parisc-cc-o4 hpux-parisc-gcc hpux-parisc1_1-cc
hpux-parisc1_1-gcc hpux-parisc2-cc hpux-parisc2-gcc hpux64-ia64-cc
hpux64-ia64-gcc hpux64-parisc2-cc hpux64-parisc2-gcc hurd-x86 iphoneos-cross
irix-cc irix-gcc irix-mips3-cc irix-mips3-gcc irix64-mips4-cc irix64-mips4-gcc
linux-aarch64 linux-alpha+bwx-ccc linux-alpha+bwx-gcc linux-alpha-ccc
linux-alpha-gcc linux-aout linux-armv4 linux-elf linux-generic32
linux-generic64 linux-ia32-icc linux-ia64 linux-ia64-icc linux-mips32
linux-mips64 linux-ppc linux-ppc64 linux-ppc64le linux-sparcv8 linux-sparcv9
linux-x32 linux-x86_64 linux-x86_64-clang linux-x86_64-icc linux32-s390x
linux64-mips64 linux64-s390x linux64-sparcv9 mingw mingw64 ncr-scde
netware-clib netware-clib-bsdsock netware-clib-bsdsock-gcc netware-clib-gcc
netware-libc netware-libc-bsdsock netware-libc-bsdsock-gcc netware-libc-gcc
newsos4-gcc nextstep nextstep3.3 osf1-alpha-cc osf1-alpha-gcc purify qnx4
rhapsody-ppc-cc sco5-cc sco5-gcc solaris-sparcv7-cc solaris-sparcv7-gcc
solaris-sparcv8-cc solaris-sparcv8-gcc solaris-sparcv9-cc solaris-sparcv9-gcc
solaris-x86-cc solaris-x86-gcc solaris64-sparcv9-cc solaris64-sparcv9-gcc
solaris64-x86_64-cc solaris64-x86_64-gcc sunos-gcc tandem-c89 tru64-alpha-cc
uClinux-dist uClinux-dist64 ultrix-cc ultrix-gcc unixware-2.0 unixware-2.1
unixware-7 unixware-7-gcc vos-gcc vxworks-mips vxworks-ppc405 vxworks-ppc60x
vxworks-ppc750 vxworks-ppc750-debug vxworks-ppc860 vxworks-ppcgen
vxworks-simlinux debug debug-BSD-x86-elf debug-VC-WIN32 debug-VC-WIN64A
debug-VC-WIN64I debug-ben debug-ben-darwin64 debug-ben-debug
debug-ben-debug-64 debug-ben-debug-64-clang debug-ben-macos
debug-ben-macos-gcc46 debug-ben-no-opt debug-ben-openbsd
debug-ben-openbsd-debug debug-ben-strict debug-bodo debug-darwin-i386-cc
debug-darwin-ppc-cc debug-darwin64-x86_64-cc debug-geoff32 debug-geoff64
debug-levitte-linux-elf debug-levitte-linux-elf-extreme
debug-levitte-linux-noasm debug-levitte-linux-noasm-extreme debug-linux-elf
debug-linux-elf-noefence debug-linux-generic32 debug-linux-generic64
debug-linux-ia32-aes debug-linux-pentium debug-linux-ppro debug-linux-x86_64
debug-linux-x86_64-clang debug-rse debug-solaris-sparcv8-cc
debug-solaris-sparcv8-gcc debug-solaris-sparcv9-cc debug-solaris-sparcv9-gcc
debug-steve-opt debug-steve32 debug-steve64 debug-vos-gccNOTE: If in doubt, on Unix-ish systems use './config'.
這個庫顯式指定了所有它能支持的平臺種類,所以我們只能按照這個指定了。這樣指定完之后,需要把生成的Makefile中對應(yīng)宏定義進行顯式修改,包括但不限于CC
、AR
、NM
、RANLIB
、CXX
等等。
4.2.2 有些庫壓根就沒有configure,需要用cmake
有些開源庫就沒給configure,但是能看到cmakelist的文件,那么這個時候,把cmakelist當(dāng)做configure就好,但是它的指定寫法會稍顯不同。一般需要提供一個對應(yīng)的cmake配置,對于我們交叉編譯來說,需要指定對應(yīng)的host系統(tǒng)名稱CMAKE_SYSTEM_NAME
和處理器名稱CMAKE_SYSTEM_PROCESSOR
,然后需要指定對應(yīng)的編譯鏈路徑CMAKE_C_COMPILER
和CMAKE_CXX_COMPILER
。
這里給出一個樣例:
#arm.cmakeset(CMAKE_SYSTEM_NAME Linux)set(CMAKE_SYSTEM_PROCESSOR arm)set(tools /data1/xiaoyanyi/cross-tool/arm-imx6ul-linux-gnueabihf/bin/arm-imx6ul-linux-gnueabihf-)set(CMAKE_C_COMPILER ${tools}gcc)set(CMAKE_CXX_COMPILER ${tools}g++)
cmake文件準(zhǔn)備好后,就可以直接cmake了,機理是和configure一樣的:
cmake CMakeLists.txt -DCMAKE_TOOLCHAIN_FILE=./arm.cmake
上述命令執(zhí)行完后,最終會生成一個Makefile文件,接著make
,make install
就好了。
5. 總結(jié)
-
絕大多數(shù)場景,交叉編譯的時候
configure
,make
,make install
三部曲就好,與普通編譯不一樣的是需要指定host
-
自依賴第三方庫在不頻繁迭代更新的條件下,建議安裝到交叉編譯鏈的sysroot目錄中
-
如果怎么編譯都有點問題,建議仔細閱讀
configure --help
或者README
分析查找端倪