【转载】NDK编译基础

本篇博文参考了非虫大大的Android软件安全与逆向分析,这真的是一本好书,里面涵盖的内容比较全也比较基础。下面开始我们的学习。

Android为了提高效率、安全性等,提供了NDK(原生开发套件),现在我们来看看如何编译原生程序。

原生程序的编译有三种方法:

1、使用gcc手动编译

2、使用ndk-build手动编译

3、使用eclipse自动编译

我们分别使用这三种方式来分别编译看看。

准备工作:

1、下载对应版本的ndk,我所使用的平台是windows,解压到指定位置即可。ndk下载链接:https://developer.android.com/ndk/downloads/index.html

我的路径为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程序,代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include<stdio.h>  
  2. int main(int argc, int** argv[]){  
  3.     printf("Hello ARM!\n");  
  4.     return 0;  
  5. }  

1、gcc手动编译

使用这种方式需要首先编写makefile文件。为了之后的方便,我们先将adb 和make工具加入环境变量,环境变量设置方式这里就不细说了。不知道的可以参考这篇文章: http://jingyan.baidu.com/article/17bd8e52f514d985ab2bb800.html,make.exe工具路径为F:\android\android-ndk-r11b\prebuilt\windows-x86_64\bin,将该路径添加到环境变量中,注意与adb路径用分号隔开。
现在,我们开始编写我们的makefile文件。新建makefile文件,无后缀名,内容如下:
[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. NDK_ROOT=F:\android\android-ndk-r11b  
  2. TOOLCHAINS_ROOT=$(NDK_ROOT)\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64  
  3. TOOLCHAINS_PREFIX=$(TOOLCHAINS_ROOT)\bin\arm-linux-androideabi  
  4. TOOLCHAINS_INCLUDE=$(TOOLCHAINS_ROOT)\lib\gcc\arm-linux-androideabi\4.9\include-fixed  
  5. PLATFORM_ROOT=$(NDK_ROOT)\platforms\android-23\arch-arm  
  6. PLATFORM_INCLUDE=$(PLATFORM_ROOT)\usr\include  
  7. PLATFORM_LIB=$(PLATFORM_ROOT)\usr\lib  
  8.   
  9. MODULE_NAME=hello  
  10. BUILD_TYPE=c  
  11. PATH_ANDROID=/data/local/tmp/  
  12.   
  13. RM=del  
  14.   
  15. FLAGS=-I$(TOOLCHAINS_INCLUDE) \  
  16.         -I$(PLATFORM_INCLUDE) \  
  17.         -L$(PLATFORM_LIB) \  
  18.         -nostdlib \  
  19.         -lgcc \  
  20.         -Bdynamic \  
  21.         -lc \  
  22.         -pie -fPIE  
  23.   
  24. OBJS=$(MODULE_NAME).o \  
  25.         $(PLATFORM_LIB)\crtbegin_dynamic.o \  
  26.         $(PLATFORM_LIB)\crtend_android.o  
  27.   
  28. all:  
  29.           
  30.     $(TOOLCHAINS_PREFIX)-gcc $(FLAGS) -c $(MODULE_NAME).$(BUILD_TYPE) -o $(MODULE_NAME).o  
  31.     $(TOOLCHAINS_PREFIX)-gcc $(FLAGS) -S $(MODULE_NAME).$(BUILD_TYPE) -o $(MODULE_NAME).S  
  32.     $(TOOLCHAINS_PREFIX)-gcc $(FLAGS) $(OBJS) -o $(MODULE_NAME)       
  33. clean:  
  34.         $(RM) *.o  
  35. install:  
  36.     adb push $(MODULE_NAME) $(PATH_ANDROID)  
  37.     adb shell chmod 755 $(PATH_ANDROID)$(MODULE_NAME)  
  38.     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放到同一目录下,打开命令行,进入该目录,依次执行以下命令:
[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. make  
  2. make install   
此时,可以看到控制台输出"Hello ARM!"。

同时,我们打开刚才的目录,可以看到里面生成了一些.o和.S文件。假设我们想删除其中后缀为.o的文件,执行make clean命令,再打开目录就会看到.o文件已经被删除。。如果想修改删除规则,修改makefile中clean标签内容即可。

2、ndk-build编译

首先,我们先将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目录下执行以下命令:
[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. android list  
执行这条命令后,会列出很多个SDK版本,在这里选择其中一个版本作为我们建立项目的版本号,记住该版本的id
接下来创建Android工程,执行以下命令:
[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. android create project -n hello2 -p hello2 -t 9 -k com.droider.hello2 -a MyActivity  
命令行说明:-n 指定工程名称,-t 指定平台版本号,这里可以输入刚才选择版本号的id,-k 指定工程包名,-a 指定默认Actitivy名称。
执行完以上命令后,会看到tools目录下生成了hello2的工程。
下一步,进入工程根目录,新建jni文件夹,并将我们最开始编写的hello.c文件复制进去。接着编写ndk-build所需要的脚本文件,主要是Android.mk与Application.mk两个脚本,Application.mk可选,我们暂时不使用,这里我们只使用Android.mk文件,该文件是工程的编译脚本,描述了编译原生程序所需的编译选项,头文件,源文件及依赖库等。
新建Android.mk,文件内容如下:
[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. LOCAL_PATH := $(call my-dir)  
  2. include $(CLEAR_VARS)  
  3. LOCAL_ARM_MODE := arm  
  4. LOCAL_MODULE := hello  
  5. LOCAL_SRC_FILES := hello.c  
  6. 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手动编译。其实主要也就是以下三条命令即可:
[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. adb push hello /data/local/tmp  
  2. adb shell chmod 755 /data/local/tmp/hello  
  3. adb shell /data/local/tmp/hello  
说明:1、adb需要配置环境变量。
    2、传入的hello必须修改权限为可执行文件
此时,可以看到,控制台命令行输出"Hello ARM!"。

3、Eclipse创建工程并自动编译

使用eclipse自动编译原生程序的原理依然是使用ndk-build工具。
1、打开eclilpse,新建Android工程,取名为hello3。
2、新建Build,当代码修改保存后,eclipse会自动编译生成原生程序,新建Build流程如下:
在hello3工程上右键选择Properties,点击Builders选项,再点击右侧New按钮,然后双击Program打开Edit Configuration,在对话框的Name一栏中设置Builder名称,Location输入ndk-build命令路径,Working Drrectory右侧的Browser Workspace选择hello3工程,点击Apply按钮。点击Refresh标签,勾选“Refresh resource upon completion”复选框。点击Build Options标签,勾选“During auto builds”和"Specify working set of relevant resources"复选框。点击“Specify Resources”按钮,勾选hello3工程的jni目录,点击finish按钮,点击Ok关闭Edit Configuration对话框。点击OK关闭Properties对话框。
3、此时hello3自动编译,并在libs/armeabi目录下省hello可执行文件。
结果如下:


以后在Eclipse中对jni目录下任何文件进行修改保存操作,都会触发JNI_Builder执行来重新编译工程。
至此,我们已经将三种编译方式完全讲述完毕。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值