⑴ 在哪可以看到NDK下gnu-libstdc++庫的源代碼
概括來說主要分為以下幾種情況: 1. 代碼的保護,由於apk的java層代碼很容易被反編譯,而C/C++庫反匯難度較大。 2. 在NDK中調用第三方C/C++庫,因為大部分的開源庫都是用C/C++代碼編寫的。 3. 便於移植,用C/C++寫的庫可以方便在其他的嵌入式平
⑵ linux android下編譯c++,不識別iostream,string等標准頭文件
你是否使用Android的 NDK 進行編譯,你需要設置NDK的路徑才行。
⑶ 如何調試android NDK 交叉編譯的cpp文件
主要講一下具體的步驟,具體的ndk指令我就不說了,貼的文章都有:
首先是寫一個.java文件,本例中是HprofDumper.java
具體如下:
public class HprofDumper {
public native boolean hprofDumper(String filename, String outname);
}
然後用命令javac HprofDumper.java 生成.class文件
再用javah HprofDumper 生成相應的.h文件
生成的.h文件如下
#include
#ifndef _Included_HprofDumper
#define _Included_HprofDumper
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jboolean JNICALL Java_HprofDumper_hprofDumper
(JNIEnv *, jobject, jstring, jstring);
#ifdef __cplusplus
}
#endif
#endif
然後只需要在對應的.cpp文件完成相應函數即可,核心代碼如下:
#include "HprofDumper.h"
#include "hprof.h"
JNIEXPORT jboolean JNICALL Java_HprofDumper_hprofDumper
(JNIEnv *env, jobject obj, jstring in_file, jstring out_file)
{
const char *filename = env->GetStringUTFChars(in_file, 0);
const char *outname = env->GetStringUTFChars(out_file, 0);
return hprof_mp(filename, outname);
}
其中hprof_mp是純c++代碼,引入即可。
有一點需要注意,標紅了已經,就是生成的.h文件函數並沒具體形參名字,只有形參類型,在.cpp文件中要加入相應的形參名字,本例為env、 obj、 in_file和out_file。
還有一點c和c++的區別,就是env的使用。
本例中C++為env->GetStringUTFChars(in_file, 0);
如果是C就應該改為(env)->GetStringUTFChars(env,in_file, 0);
調用Java類型 : C中調用Java中的String類型為 jstring;
C語言方法名規則 : Java_完整包名類名_方法名(JNIEnv *env, jobject thiz), 注意完整的類名包名中包名的點要用 _ 代替;
參數介紹 : C語言方法中有兩個重要的參數, JNIEnv *env, jobject thiz ;
-- JNIEnv參數 : 該參數代表Java環境, 通過這個環境可以調用Java中的方法;
-- jobject參數 : 該參數代表調用jni方法的類,;
調用jni.h中的NewStringUTF方法 : 該方法的作用是在C語言中創建一個Java語言中的String類型對象, jni.h中是這樣定義的 jstring (*NewStringUTF)(JNIEnv*, const char*), JNIEnv 結構體中包含了 NewStringUTF 函數指針, 通過 JNIEnv 就可以調用這個方法;
完成代碼編寫後,在當前目錄下完成Android.mk和Application.mk的編寫
首先是Android.mk
本例中為:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hprof-mper
LOCAL_C_INCLUDES += external/stlport/stlport
LOCAL_C_INCLUDES += bionic
LOCAL_C_INCLUDES += bionic/libstdc++/include
LOCAL_SRC_FILES := HprofDumper.cpp \
xx.cpp \
xx.cpp \
xx.cpp \
xx.cpp \
xx.cpp \
xx.cpp \
xxx.cpp
LOCAL_SHARED_LIBRARIES := libstlport
include $(BUILD_SHARED_LIBRARY)
注意標紅的是最關鍵的,LOCAL_C_INCLUDES 顧名思義是需要的頭文件的所在的目錄,那三個參數主要為了引入STL,最重要!!LOCAL_SHARED_LIBRARIES 我一直生成失敗就是沒加這個參數,不光要引入頭文件,還要引入具體的lib,這就是這個欄位的作用。
具體欄位的作用:
-- LOCAL_PATH : 代表mk文件所在的目錄;
-- include $(CLEAR_VARS) : 編譯工具函數, 通過該函數可以進行一些初始化操作;
-- LOCAL_MODULE : 編譯後的 .so 後綴文件叫什麼名字;
-- LOCAL_SRC_FILES: 指定編譯的源文件名稱;
-- include $(BUILD_SHARED_LIBRARY) : 告訴編譯器需要生成動態庫;
Applicaion.mk中就一行
APP_STL = stlport_static
表示使用stl靜態庫。
注意:我用了STL,大家沒有用STL的當然不用引入這些啦~
⑷ 為什麼使用ndk編譯時出現如下錯誤
1.dr@drBox:~/workspace/JniTest/jni$ ~/android-ndk-r6/ndk-build Compile++ thumb : Test <= JniTest.cpp /bin/sh: /home/dr/android-ndk-r6/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-g++: not found make: *** [/home/dr/workspace/JniTest/obj/local/armeabi/objs/Test/JniTest.o] Error 127
這個錯誤是說找不到arm-linux-androideabi-g++,確實找不到,我從ndk r6中發現根本就沒有linux-x86/文件夾,只有darwin-x86 gdbserver這兩個文件夾,所以下載了最新的ndk r7b,幸好這裡面有linux-x86文件夾,編譯成功了。
dr@drBox:~/workspace/JniTest/jni$ ~/android-ndk-r7b/ndk-build Compile++ thumb : Test <= JniTest.cpp StaticLibrary : libstdc++.a SharedLibrary : libTest.so Install : libTest.so => libs/armeabi/libTest.so
⑸ android ndk編譯C源碼~ld提示mblen()無法鏈接怎麼辦undefined reference to 'mblen'
不制動啊,這個唯難題是我不懂的
⑹ 求助,NDK編譯時so遇到的問題
1.dr@drBox:~/workspace/JniTest/jni$ ~/android-ndk-r6/ndk-build Compile++ thumb : Test <= JniTest.cpp /bin/sh: /home/dr/android-ndk-r6/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-g++: not found make: *** [/home/dr/workspace/JniTest/obj/local/armeabi/objs/Test/JniTest.o] Error 127
這個錯誤是說找不到arm-linux-androideabi-g++,確實找不到,我從ndk r6中發現根本就沒有linux-x86/文件夾,只有darwin-x86 gdbserver這兩個文件夾,所以下載了最新的ndk r7b,幸好這裡面有linux-x86文件夾,編譯成功了。
dr@drBox:~/workspace/JniTest/jni$ ~/android-ndk-r7b/ndk-build Compile++ thumb : Test <= JniTest.cpp StaticLibrary : libstdc++.a SharedLibrary : libTest.so Install : libTest.so => libs/armeabi/libTest.so
2.當只改動Android.mk文件後需要編譯,這時mm執行後會報如下提示:
============================================ make: Entering directory `/home/dr/android4.0.3' make: Nothing to be done for `all_moles'. make: Leaving directory `/home/dr/android4.0.3'
說明沒有文件改動,拒絕編譯。
那麼解決辦法可以是去稍微改動一下cpp等文件,加個空格也行。但是還有一種方便的方式就是
給cpp文件加時間戳:touch *.cpp
這樣就可以繼續編譯了,所有cpp文件的時間都更新為最新了。
⑺ 如何使用android的ndk編譯器 編譯c++的庫
1. 概述 首先回顧一下 Android NDK 開發中,Android.mk 和 Application.mk 各自的職責。 Android.mk,負責配置如下內容: (1) 模塊名(LOCAL_MODULE) (2) 需要編譯的源文件(LOCAL_SRC_FILES) (3) 依賴的第三方庫(LOCAL_STATIC_LIBRARIES,LOCAL_SHARED_LIBRARIES) (4) 編譯/鏈接選項(LOCAL_LDLIBS、LOCAL_CFLAGS) Application.mk,負責配置如下內容: (1) 目標平台的ABI類型(默認值:armeabi)(APP_ABI) (2) Toolchains(默認值:GCC 4.8) (3) C++標准庫類型(默認值:system)(APP_STL) (4) release/debug模式(默認值:release) 由此我們可以看到,本文所涉及的編譯選項在Android.mk和Application.mk中均有出現,下面我們將一個個詳細介紹。 2. APP_ABI ABI全稱是:Application binary interface,即:應用程序二進制介面,它定義了一套規則,允許編譯好的二進制目標代碼在所有兼容該ABI的操作系統和硬體平台中無需改動就能運行。(具體的定義請參考 網路 或者 維基網路 ) 由上述定義可以判斷,ABI定義了規則,而具體的實現則是由編譯器、CPU、操作系統共同來完成的。不同的CPU晶元(如:ARM、Intel x86、MIPS)支持不同的ABI架構,常見的ABI類型包括:armeabi,armeabi-v7a,x86,x86_64,mips,mips64,arm64-v8a等。 這就是為什麼我們編譯出來的可以運行於Windows的二進製程序不能運行於Mac OS/Linux/Android平台了,因為CPU晶元和操作系統均不相同,支持的ABI類型也不一樣,因此無法識別對方的二進製程序。 而我們所說的「交叉編譯」的核心原理也跟這些密切相關,交叉編譯,就是使用交叉編譯工具,在一個平台上編譯生成另一個平台上的二進制可執行程序,為什麼可以做到?因為交叉編譯工具實現了另一個平台所定義的ABI規則。我們在Windows/Linux平台使用Android NDK交叉編譯工具來編譯出Android平台的庫也是這個道理。 這里給出最新 Android NDK 所支持的ABI類型及區別: 那麼,如何指定ABI類型呢?在 Application.mk 文件中添加一行即可: APP_ABI := armeabi-v7a //只編譯armeabi-v7a版本 APP_ABI := armeabi armeabi-v7a //同時編譯armeabi,armeabi-v7a版本 APP_ABI := all //編譯所有版本 3. LOCAL_LDLIBS Android NDK 除了提供了Bionic libc庫,還提供了一些其他的庫,可以在 Android.mk 文件中通過如下方式添加依賴: LOCAL_LDLIBS := -lfoo 其中,如下幾個庫在 Android NDK 編譯時就默認鏈接了,不需要額外添加在 LOCAL_LDLIBS 中: (1) Bionic libc庫 (2) pthread庫(-lpthread) (3) math(-lmath) (4) C++ support library (-lstdc++) 下面我列了一個表,給出了可以添加到「LOCAL_LDLIBS」中的不同版本的Android NDK所支持的庫: 下面是我總結的一些常用的CFLAGS編譯選項: (1)通用的編譯選項 -O2 編譯優化選項,一般選擇O2,兼顧了優化程度與目標大小 -Wall 打開所有編譯過程中的Warning -fPIC 編譯位置無關的代碼,一般用於編譯動態庫 -shared 編譯動態庫 -fopenmp 打開多核並行計算, -Idir 配置頭文件搜索路徑,如果有多個-I選項,則路徑的搜索先後順序是從左到右的,即在前面的路徑會被選搜索 -nostdinc 該選項指示不要標准路徑下的搜索頭文件,而只搜索-I選項指定的路徑和當前路徑。 --sysroot=dir 用dir作為頭文件和庫文件的邏輯根目錄,例如,正常情況下,如果編譯器在/usr/include搜索頭文件,在/usr/lib下搜索庫文件,它將用dir/usr/include和dir/usr/lib替代原來的相應路徑。 -llibrary 查找名為library的庫進行鏈接 -Ldir 增加-l選項指定的庫文件的搜索路徑,即編譯器會到dir路徑下搜索-l指定的庫文件。 -nostdlib 該選項指示鏈接的時候不要使用標准路徑下的庫文件 (2) ARM平台相關的編譯選項 -marm -mthumb 二選一,指定編譯thumb指令集還是arm指令集 -march=name 指定特定的ARM架構,常用的包括:-march=armv6, -march=armv7-a -mfpu=name 給出目標平台的浮點運算處理器類型,常用的包括:-mfpu=neon,-mfpu=vfpv3-d16 -mfloat-abi=name 給出目標平台的浮點預算ABI,支持的參數包括:「soft」, 「softfp」 and 「hard」
⑻ android ndk 用什麼工具
首先需要確定目標機器的指令集。
如果是 x86 的機器,用 x86-4.4.3 版本的工具鏈;如果是 arm 指令的,用 arm-linux-androideabi-4.4.3 版本 (x86-4.4.3 和 arm-linux-androideabi-4.4.3 位於ndk目錄中)
1、gcc 的sysroot 選項
sysroot 選項設定 gcc 在編譯源碼的時候,尋找頭文件和庫文件的根目錄。可以這樣調用 gcc --sysroot=/tmp/gcc-arm (及其他選項)。NDK 根目錄下的 platforms 目錄中的各個子目錄的路徑都可以直接傳給 gcc --sysroot=<dir>。為了簡化操作,可以在linux系統的命令終端執行以下命令,設置SYSROOT環境變數,$NDK是ndk的根目錄。
$ SYSROOT=$NDK/platforms/android-8/arch-arm
2、調用 NDK gcc(第1種方法)。 設置 SYSROOT之後,要把它傳給 gcc 的 --sysroot 選項。由於unix/linux自帶的gcc並非交叉編譯工具,而我們需要使用的是ndk中提供的交叉編譯工具(也是gcc),所以需要想辦法讓編譯腳本找到ndk中的gcc,而不要去尋找系統中的gcc。而 unix/linux 系統的編譯腳本常常會用 CC 環境變數來引用編譯器,所以通過把 CC 設置為ndk中的gcc的路徑,就能幫助編譯腳本找到正確的gcc(我們還能順便加上--sysroot選項)。
將CC 按如下設置
$ export CC="$NDK/toolchains/<name>/prebuilt/<host-system>/bin/<prefix>gcc --sysroot=$SYSROOT"
$ $CC -o foo.o -c foo.c (不必執行這一行,這條命令是調用gcc編譯程序)
上面第1行之後之後,再去執行./configure 就可以編譯出arm程序了。不過還需要考慮共享庫的鏈接問題,要確保該程序沒有鏈接ndk未提供的共享庫。該方法的缺陷就是,不能使用 C++ STL(STLport 或 GNU libstdc++ ),也不能使用異常機制和RTTI。
3、調用NDK編譯器(第2種方法,更簡單)
android ndk 提供腳本,允許自己定製一套工具鏈。例如:
$NDK/build/tools/make-standalone-toolchain.sh --platform=android-5 --install-dir=/tmp/my-android-toolchain [ --arch=x86 ]
將會在/tmp/my-android-toolchain 中創建 sysroot 環境和 工具鏈。--arch 選項選擇目標程序的指令架構,默認是為 arm。
如果不加 --install-dir 選項,則會創建 /tmp/ndk/<toolchain-name>.tar.bz2。
(執行 make-standalone-toolchain.sh --help 查看幫助。)
運行之後,這樣使用:
$ export PATH=/tmp/my-android-toolchain/bin:$PATH
$ export CC=arm-linux-androideabi-gcc
$ export CXX=arm-linux-androideabi-g++
$ export CXXFLAGS="-lstdc++"
執行完以上設置環境變數的命令之後,就可以直接編譯了(例如,執行 ./configure 然後 make 得到的就是 arm 程序了)。不用再設定 sysroot, CC 了。而且,可以使用 STL,異常,RTTI。
4、ABI 兼容性
ndk 同時支持 arm5 和 arm7,一般只用 arm5就好了。arm7是高端一點的,NDK 默認也是 arm5 。
推薦加上 -mthumb 選項給gcc,來生成 16-bit Thumb-1 指令。
如果要用 arm7,可以設定 CFLAGS='-march=armv7-a -mfloat-abi=softfp', 使用 Thumb-2 指令,且這兩個選項不能分開!
5、警告 & 限制
5.1 Windows支持
Windows 上的NDK 工具鏈不依賴 Cygwin,因而速度比用 Cygwin 快一點,但是這些工具不能理解
Cygwin 的路徑名(例如, /cygdrive/c/foo/bar)。只能理解 C: /cygdrive/c/foo/bar 這類路徑
不過,NDK 提供的build工具能夠很好地應對上述問題(ndk-build)
5.2 wchar_t 支持
wchar_t 類型僅從 Android 2.3 開始支持。
在 android-9 上, wchar_t 是 4位元組。 並且 C語言庫提供支持寬字元的函數
(例外:multi-byte 編碼/解碼 函數 和 wsprintf/wsscanf )
在android-9 以前的平台上,wchar_t 是1位元組,而且寬字元函數不起作用。
建議不使用 wchar_t,提供 wchar_t 支持是為了方便移植以前的代碼。
5.3 異常, RTTI 和 STL
NDK 工具鏈默認支持C++異常和RTTI(Run Time Type Information),可以用 -fno-exception 和 -fno-rtti 關閉(生成的機器碼更小)
注意: 如果要用這兩個特性,需要顯式鏈接 libsupc++。例如: arm-linux-androideabi-g++ .... -lsupc++
NDK 提供了 libstdc++,因而可以用 STL,但需要顯式鏈接 libstdc++ ( gcc ... -lstdc++)。不過在將來可以不用手動指定這個鏈接參數。