在Android平台使用SNPE應鏈接libc++庫


在Android平台使用SNPE庫以前都沒什么太大問題,最近因為要使用userBuffer,編譯時報鏈接錯誤:

undefined reference to `zdl::DlSystem::TensorShape::TensorShape(std::vector<unsigned long, std::allocator<unsigned long> >)

因為是鏈接錯誤,而且查看了頭文件,TensorShape有對應的重載構造函數,所以懷疑SNPE的庫文件libSNPE.so不對。懷疑高通提供的庫文件不對,好像這也不太可能,一時間陷入了困境。

開始從高通的客服那邊沒有得到太有用的信息,只能自己想辦法。用objdump從庫文件dump出符號表看看有沒有對應的函數。但是高通release庫肯定是把符號表去掉了的,只能通過objdump -T出來動態符號。從動態符號中篩選出和TensorShape相關的,然后找一些看着可能像的符號,用c++filt還原出函數名。

先在x86_64平台的libSNPE.so找到了

c++filt _ZN3zdl8DlSystem11TensorShapeC1ESt6vectorImSaImEE zdl::DlSystem::TensorShape::TensorShape(std::vector<unsigned long, std::allocator<unsigned long> >)

這和我們需要的函數是一樣的,也就是說x86_64平台的libSNPE.so肯定是包含這個重載的函數實現的。那android平台的不應該沒有啊?繼續在android平台的libSNPE.so里找,終於找到

c++filt _ZN3zdl8DlSystem11TensorShapeC2ENSt6__ndk16vectorImNS2_9allocatorImEEEE zdl::DlSystem::TensorShape::TensorShape(std::__ndk1::vector<unsigned long, std::__ndk1::allocator<unsigned long> >)

看着像,但是和平常見到的是不太一樣,vector的定義是std::__ndk1::vector。這說明SNPE鏈接的是LLVM的標准libc++庫。這樣原因清楚了。我們編譯使用的是cmake,最開始在build.gradle文件中並沒有指定ANDROID_STL變量,編譯使用的應該不是libc++庫,導致了鏈接錯誤。(按照NDK文檔的說法,ANDROID_STL默認的是c++_static,這是libc++的靜態庫。按理是能夠鏈接通過的,實際也試過了,ANDROID_STL指定c++_static是能夠編譯通過的。但是不指定,就會出現上面的undefined reference錯誤。我懷疑默認使用的是GNU的庫)

因為還使用了opencv的庫(用的是opencv3的版本),如果改用libc++,會出現鏈接opencv出錯。查找opencv的文檔,opencv4.0.0開始使用c++11庫,因此改用opencv4。在build.gradle文件中加上ANDROID_STL定義,編譯通過。

android { defaultConfig { externalNativeBuild { cmake { arguments '-DANDROID_STL=c++_shared' } } } }

按NDK的文檔,從NDK r18開始,libc++成為NDK中唯一可用的STL。因為我們使用的NDK版本還比較低,所以開始並沒有出錯。隨着NDK升級,不僅r18開始libc++是唯一的STL,而且gcc也不再支持,只能使用clang。還是慢慢轉過去了,以免出現一些莫名其妙的問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM