2016-10-31 47 views
4

我在嘗試編譯Android代碼時遇到了一個奇怪的問題。我的代碼與兩個第三方庫(libcurl和WebRTC)進行交互,當它進入鏈接階段(鏈接到已編譯的共享對象文件)時,它會報告WebRTC中有未定義的函數引用,但libcurl函數沒有問題。那我收到未定義錯誤的例子有:Android NDK共享對象未定義參考錯誤

WS.cpp:208: error: undefined reference to 'buzz::XmlElement::AddAttr(buzz::QName const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)' 

ThirdPartyLibs/WebRTC/src/third_party/android_tools/ndk/sources/cxx-stl/llvm-libc++/libcxx/include/memory:1636: error: undefined reference to 'buzz::QN_MESSAGE' 

當我運行nm -C上的WebRTC庫文件,然後grep結果的功能,該功能被清​​楚地顯示存在和定義(文部分)。

nm -C Android/libs/armv7/libWebRTC.so | grep "AddAttr" 
000753e5 t buzz::XmlElement::AddAttr(buzz::QName const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) 
0007541d t buzz::XmlElement::AddAttr(buzz::QName const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int) 

nm -C kino/Android/libs/armv7/libWebRTC.so | grep "QN_MESSAGE" 
000bfd10 d buzz::QN_MESSAGE 

當我說我是鏈接到的已編譯的WebRTC共享庫,我應該注意的是,共享庫正在使用或者忍者編譯靜態庫文件或目標文件編譯。我使用如下的編譯:

GCC_armv7=$projectDir/ThirdPartyLibs/WebRTC/src/third_party/android_tools/ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc 

OBJS_armv7="…list of static libraries or object files…」 

LDFLAGS="-lc -ldl -lm -fPIC 
--sysroot=$projectDir/ThirdPartyLibs/WebRTC/src/third_party/android_tools/ndk/platforms/android-16/arch-arm 
-L$projectDir/ThirdPartyLibs/WebRTC/src/third_party/android_tools/ndk/platforms/android-16/arch-arm/usr/lib/" 

$GCC_armv7 -v -shared $LDFLAGS -o libWebRTC.so -Wl,-soname=webrtc $OBJS_armv7 

當我將代碼直接對忍者編譯靜態庫文件,或編譯的忍者目標文件鏈接,我沒有得到同樣的錯誤。既然它有效,那麼只要鏈接到其中任何一個都會很好。但是,Java Android開發人員告訴我,雖然Java接受靜態庫,但Android不支持。我無法想象Java或Android會針對對象文件進行編譯。

我還必須強制引用Android.mk文件中的LOCAL_LDLIBS參數中的文件,而不是使用LOCAL_SHARED_LIBRARIES或LOCAL_STATIC_LIBRARIES參數。

當我嘗試使用前一種方法時,ndk-build永遠不會找到合適的庫文件。相反,它似乎使用libcurl和libopenssl庫的系統版本。

就像完整性檢查一樣,我對目標文件和靜態庫文件運行相同的nm | grep命令,並將它們與共享目標文件的結果進行比較。下面是靜態/對象文件和編譯後的文件之間nm –C | grep結果的比較。

static/object - 
00000001 T buzz::XmlElement::AddAttr(buzz::QName const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) 

shared object - 
000753e5 t buzz::XmlElement::AddAttr(buzz::QName const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) 

從我已經能夠收集的nm輸出,有「T」和「t」之間沒有什麼區別,但我不明白爲什麼它會在兩組之間切換。

我應該注意到,正在使用的gcc(或g ++)編譯器是WebRTC下載(commit hash: aad6780e5c25b1622904ef83659461706f6a25db)提供的相應體系結構的特定gcc/g ++二進制文件。對於ndk-build(ing),我也使用WebRTC下載(src/chromium/src/third_party/android_tools/ndk/ndk-build)附帶的ndk-build二進制文件。

我的問題:我在做什麼錯誤,這樣鏈接對象文件將編譯ndk-build Android.mk文件,但鏈接到共享對象文件將失敗,其中一些函數被定義,另一個不是界定?

更新:我剛剛嘗試使用ndk-build和一個Android.mk文件而不是gcc/g ++編譯這樣的文件,並且我得到相同的錯誤。

回答

0

我想出了一個解決這個問題的方法。我沒有試圖爲WebRTC構建單獨的共享對象文件,而是沿着直接鏈接到編譯對象文件的路線返回。這樣做會迫使ndk-build將這些對象包含在我的代碼的編譯共享對象文件中。因此,我的最終庫.so文件顯着大於計劃。但這並不重要,因爲它擁有我們正在使用的所有WebRTC庫。對於那些遇到類似問題的用戶,請注意./libs/<arch>/文件夾中已編譯的庫文件被剝離了符號。所以如果你nm | grep他們,你會得到一個錯誤。如果您需要使用該命令進行任何形式的理智檢查,請改用./obj/local/<arch>中的已編譯庫。

我不會接受這個答案,以防其他人出現並且能夠在沒有解決問題的情況下真正解決問題。