NDK編譯基礎示例

2021-07-23 07:43:50 字數 4925 閱讀 9638

本篇博文參考了非蟲大大的android軟體安全與逆向分析,這真的是一本好書,裡面涵蓋的內容比較全也比較基礎。下面開始我們的學習。

android為了提高效率、安全性等,提供了ndk(原生開發套件),現在我們來看看如何編譯原生程式。

原生程式的編譯有三種方法:

1、使用gcc手動編譯

2、使用ndk-build手動編譯

3、使用eclipse自動編譯

我們分別使用這三種方式來分別編譯看看。

準備工作:

我的路徑為f:\android\android-ndk-r11b,那麼工具鏈的完整路徑為f:\android\android-ndk-r11b\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\bin,大家可以看到該目錄有很多字首為arm-linux-androideabi-的exe檔案,代表它們使用與arm架構的android程式開發。

現在,就開始動手啦。

首先,新建hello.c程式,**如下:

#includeint main(int argc, int** argv)
工具路徑為f:\android\android-ndk-r11b\prebuilt\windows-x86_64\bin,將該路徑新增到環境變數中,注意與adb路徑用分號隔開。

現在,我們開始編寫我們的makefile檔案。新建makefile檔案,無字尾名,內容如下:

ndk_root=f:\android\android-ndk-r11b

toolchains_root=$(ndk_root)\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64

toolchains_prefix=$(toolchains_root)\bin\arm-linux-androideabi

toolchains_include=$(toolchains_root)\lib\gcc\arm-linux-androideabi\4.9\include-fixed

platform_root=$(ndk_root)\platforms\android-23\arch-arm

platform_include=$(platform_root)\usr\include

platform_lib=$(platform_root)\usr\lib

module_name=hello

build_type=c

path_android=/data/local/tmp/

rm=del

flags=-i$(toolchains_include) \

-i$(platform_include) \

-l$(platform_lib) \

-nostdlib \

-lgcc \

-bdynamic \

-lc \

-pie -fpie

objs=$(module_name).o \

$(platform_lib)\crtbegin_dynamic.o \

$(platform_lib)\crtend_android.o

all:

$(toolchains_prefix)-gcc $(flags) -c $(module_name).$(build_type) -o $(module_name).o

$(toolchains_prefix)-gcc $(flags) -s $(module_name).$(build_type) -o $(module_name).s

$(toolchains_prefix)-gcc $(flags) $(objs) -o $(module_name)

clean:

$(rm) *.o

install:

adb push $(module_name) $(path_android)

adb shell chmod 755 $(path_android)$(module_name)

adb shell $(path_android)$(module_name)

makefile檔案說明:

1、如果仔細看的話,就會發現這個檔案定義了一系列的變數,然後又使用拼接的方式將值賦給另乙個變數。

2、前六行定義了路徑變數,$(ndk_root)就是取該變數值,在這裡可能需要對應版本修改你的對應路徑。

3、module_name這個變數定義了我們編譯完成的名稱為hello

4、flags變數增加了一些標頭檔案和庫檔案的搜尋路徑和編譯選項。在這裡我們主要提兩個選項,第乙個是-nostdlib,android沒有採用glibc作為c庫,而是採用google自己開發的bionic c庫,因此需要加入該選項;第二個是-pie -fpie,在android4.4之後新增了新的保護機制,可執行檔案必須是採用pie編譯的,我們加入該行引數,就可以避免報錯。

5、all便簽指定了編譯程式時需要執行的命令。

6、clean標籤用於清理生成的目標檔案。

7、install標籤將我們生成的最終檔案安裝到手機上,就可以看到c程式輸出的結果了。(該標籤下的命令就是我們為什麼要設定adb環境變數,方便在makefile中編寫該命令)

將我們的makefile檔案與hello.c放到同一目錄下,開啟命令列,進入該目錄,依次執行以下命令:

make

make install

此時,可以看到控制台輸出"hello arm!"。

同時,我們開啟剛才的目錄,可以看到裡面生成了一些.o和.s檔案。假設我們想刪除其中字尾為.o的檔案,執行make clean命令,再開啟目錄就會看到.o檔案已經被刪除。。如果想修改刪除規則,修改makefile中clean標籤內容即可。

首先,我們先將ndk-build命令加入環境變數,該命令一般位於ndk安裝目錄下,我安在f:\android下,因此我的ndk-build命令路徑為f:\android\android-ndk-r11b,參考gcc編譯方式中的adb環境變數設定,將此路徑加入到android變數中即可,注意用分號隔開。

使用ndk-build工具,必須先有乙個android工程。我們可以使用sdk開發包中的tools目錄下的android指令碼來生成。首先我們列出android sdk中所有已經按照的sdk平台版本。在sdk\toos目錄下執行以下命令:

android list
執行這條命令後,會列出很多個sdk版本,在這裡選擇其中乙個版本作為我們建立專案的版本號,記住該版本的id

接下來建立android工程,執行以下命令:

android create project -n hello2 -p hello2 -t 9 -k com.droider.hello2 -a myactivity
命令列說明:-n 指定工程名稱,-t 指定平台版本號,這裡可以輸入剛才選擇版本號的id,-k 指定工程包名,-a 指定預設actitivy名稱。

執行完以上命令後,會看到tools目錄下生成了hello2的工程。

新建android.mk,檔案內容如下:

local_path := $(call my-dir)

include $(clear_vars)

local_arm_mode := arm

local_module := hello

local_src_files := hello.c

include $(build_executable)

android.mk檔案說明:

1、local_path:定義本地原始碼路徑

2、clear_vars:讓編譯系統清除掉一些已經定義過的巨集

3、local_arm_mode:指定生成的原生程式使勇的arm指定模式

4、local_module:指定模組名稱,即原生程式生成後的檔名

5、local_src_files:指定c或c++源列表。示例中使用的只有乙個hello.c檔案。

6、build_executable:指定生成可執行檔案。

android.mk檔案編寫完後,將它與hello.c一同放在jni目錄下,然後進入命令列切換到hello2根目錄,執行ndk-build命令,執行效果如下:

此時,我們看執行結果的最後一行即我們生成檔案的位置。因此,我們進入hello2目錄下的libs/armeabi下,將hello檔案複製到模擬器或手機中,執行過程參考gcc手動編譯。其實主要也就是以下三條命令即可:

adb push hello /data/local/tmp

adb shell chmod 755 /data/local/tmp/hello

adb shell /data/local/tmp/hello

說明:1、adb需要配置環境變數。

2、傳入的hello必須修改許可權為可執行檔案

此時,可以看到,控制台命令列輸出"hello arm!"。

使用eclipse自動編譯原生程式的原理依然是使用ndk-build工具。

1、開啟eclilpse,新建android工程,取名為hello3。

2、新建build,當**修改儲存後,eclipse會自動編譯生成原生程式,新建build流程如下:

3、此時hello3自動編譯,並在libs/armeabi目錄下省hello可執行檔案。

結果如下:

以後在eclipse中對jni目錄下任何檔案進行修改儲存操作,都會觸發jni_builder執行來重新編譯工程。

至此,我們已經將三種編譯方式完全講述完畢。

NDK編譯引數

local cflags 編譯c或c 時傳遞給編譯器的選項,如定義巨集,local cflags dsk software float 和 define sk software float功能相同。local cppflags 編譯c 時傳遞給編譯器的選項,如定義巨集,local cflags ds...

使用NDK編譯mono

2.匯出ndk目錄到環境變數 export ndk var data android ndk r10e 3.執行ndk的工具鏈 ndk build tools make standalone toolchain.sh platform android 18 install dir tmp my an...

使用NDK編譯ffmpeg

slibname with major slibname libmajor lib install extra cmd ranlib libdir libname slib install name slibname with version slib install links slibname ...