Android ndk-build编译jni动态库

作者: 千山万水迷了鹿 | 来源:发表于2018-05-22 17:52 被阅读48次

    目的

    能快速,简单(主要是指脱离AndroidStudio)的把c/c++ 源码进行交叉编译成Android上的动态库,静态库,或者可执行文件。从而为逆向分析构建demo节省时间。

    编译环境配置

    电脑:Mac OS 10.13.4
    NDK:官网下载,目前最新的好像android-ndk-r17 我用的是 android-ndk-r14b,ndk不需要安装官网下载后解压就行。
    测试机: 华为EVA-AL00 Android7.0

    配置环境变量

    为了方便使用ndk的命令行工具,我们配置环境变量
    ~/.bash_profile 文件中添加如下配置

    export ANDROID_NDK_HOME=/Users/user01/Development/android-ndk-r14b
    export PATH=${PATH}:${ANDROID_NDK_HOME}:${ANDROID_NDK_HOME}/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin
    

    然后命令行运行如下命令:

    $ source ~/.bash_profile

    然后命令行运行:

    $ ndk-build -h

    如果能打印出 ndk-build 这个工具的帮助文档说明环境变量配置成功

    测试简单的例子

    创建如下目录结构(注意jni这层目录很重要,名字不要随便取):

    ~/Desktop/test/
    └── jni/
        ├── Android.mk
        ├── Application.mk
        └── test.c
    

    主要有三个文件,其中Android.mk和Application.mk 是辅助ndk-build进行编译的,test.c是我们的c测试用例

    1. Application.mk

    主要指定生成哪些cpu架构的动态库,这里只生成armeabi 和armeabi-v7a架构的库

    APP_ABI      := armeabi armeabi-v7a
    APP_PLATFORM := android-14
    
    1. Android.mk

    具体Android.mk的更详细的配置自行Google

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    # 生成的so库的名字为libdemo.so
    LOCAL_MODULE    := demo
    # 用于编译的c文件
    LOCAL_SRC_FILES := test.c
    # 生成库的类型,是动态库,静态库还是可执行文件,这里先来生成一个动态库
    include $(BUILD_SHARED_LIBRARY)
    # 下面这么写是生成可执行文件
    #include $(BUILD_EXECUTABLE)
    
    1. test.c

    很简单就是打印一句 hello world!

    #include <stdio.h>
    
    int main(const int argc,const char* args[]){
    
    const char* str  = "hello world!";
    printf("%s\n",str);
    return 0;
    
    }
    

    然后命令行进入到test目录下面:

    $ cd ~/Desktop/test

    $ ndk-build -C ./jni

    然后会生成如下目录结构,obj目录下是生成动态库的中间文件,libs里面是最终生成的不同CPU架构的动态库:

    test
    ├── jni
    │   ├── Android.mk
    │   ├── Application.mk
    │   └── test.c
    ├── libs
    │   ├── armeabi
    │   │   └── libdemo.so
    │   └── armeabi-v7a
    │       └── libdemo.so
    └── obj
        └── local
            ├── armeabi
            │   ├── libdemo.so
            │   └── objs
            │       └── demo
            │           ├── test.o
            │           └── test.o.d
            └── armeabi-v7a
                ├── libdemo.so
                └── objs
                    └── demo
                        ├── test.o
                        └── test.o.d
    

    为什么非要有jni那一层目录

    约定优于配置,没有不行吗?行,但是要改点东西。去掉jni那层目录再编译一次,当前目录结构如下:

    test/
    ├── Android.mk
    ├── Application.mk
    └── test.c
    

    命令行执行

    1. $ cd ~/Desktop/test
    2. $ ndk-build

    结果报错如下:

    Android NDK: Could not find application project directory !
    Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
    

    错误日志上说什么路径找不到错误,需要定义一个xx变量,我们只需要把编译命令改成如下就可以了:

    ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk NDK_APPLICATION_MK=./Application.mk
    

    编译一个可以允许的文件

    修改Android.mk 文件如下:

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    LOCAL_MODULE    := demo
    LOCAL_SRC_FILES := test.c
    #include $(BUILD_SHARED_LIBRARY)
    
    # Android4.4 以后 调用的可执行文件不是基于PIE方式编译的,则无法运行
    LOCAL_CFLAGS += -pie -fPIE
    LOCAL_LDFLAGS += -pie -fPIE
    # 编译一个可执行文件
    include $(BUILD_EXECUTABLE)
    

    这个可执行文件在电脑上是没法执行的,只能放到手机里面执行,执行如下命令,我们把刚生成的文件放到手机上:

    1. push 文件到手机
      $ adb push libs/armeabi-v7a/demo /data/local/tmp
    2. 为手机中的demo文件添加可执行权限(为了方便直接给予所有权限了)
      $ adb shell 'chmod 777 /data/local/tmp/demo'
    3. 用手机环境运行demo这个文件
      $ adb shell '/data/local/tmp/demo'

    运行结果会打印一行
    hello world!

    相关文章

      网友评论

        本文标题:Android ndk-build编译jni动态库

        本文链接:https://www.haomeiwen.com/subject/ssohjftx.html