自己动手编译C程序并运行于Android系统

自己动手编译C程序并运行于Android系统

  • 准备工作
    • 搭建交叉编译环境
  • 搭建代码架构
  • 编译运行

准备工作

很多半路出家的安卓开发工程师并不了解怎么样在Android Studio上搭建交叉编译环境;不过没关系,不懂我们可以学习,了解底层的运行原理对于我们成为更为高级的工程师或者架构师很有帮助;

工欲善其事必先利其器,首先我们把环境搭建一下;

搭建交叉编译环境

从androidStudio2.2版本开始,可以用cmake方式创建jni工程,到目前为止,大家基本都是用的2.2以上版本,所以这里只讲Cmake做ndk开发;

打开androidStudio之后按照以下步骤:

  1. File-New-New Project , 注意勾选支持c++。然后一路next一直到finish页面。在最后的页面需要选择ndk的版本,还有其他的一些可选项,在这里我只开发最简单的helloworld C程序,所以我们选择默认就好;自己动手编译C程序并运行于Android系统_第1张图片自己动手编译C程序并运行于Android系统_第2张图片
  2. 如果已经配置好了NDK没有多余的提示直接跳过这一步;在这个过程中可能会有提示下载ndk,如果你的电脑上没有配置ndk的话,配置ndk这里不赘述,大家自行google即可;

搭建代码架构

新建工程后默认显示Android方式,我们需要切换一下,以project的方式显示工程,然后Main目录下新建jni文件夹:自己动手编译C程序并运行于Android系统_第3张图片
然后我们在 jni文件夹下新建test_hello_world.cpp,里面写一些简单的代码,这个我相信大家都看得懂,大家都是高材生;自己动手编译C程序并运行于Android系统_第4张图片
然后我们在jni下新建文件 Android.mk,这个是用来编译c代码的规则文件,它遵循Makefile文件规范,想要了解更多的可以参考我以前写的一篇文章《Build入门》(这篇文章还没写完,有空完善一下)
Android.mk文件详细:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_CFLAGS += -pie -fPIE
LOCAL_LDFLAGS += -pie -fPIE

LOCAL_MODULE := test_hello_world
LOCAL_SRC_FILES =: test_hello_world.cpp
include $(BUILD_EXECUTABLE)

PIE这个安全机制从4.1引入,但是Android L之前的系统版本并不会去检验可执行文件是否基于PIE编译出的。因此不会报
error: only position independent executables (PIE) are supported.
但是Android L已经开启验证,如果调用的可执行文件不是基于PIE方式编译的,则无法运行。解决办法非常简单,在Android.mk中加入如下flag就行。

LOCAL_CFLAGS += -pie -fPIE
LOCAL_LDFLAGS += -pie -fPIE

然后jni文件夹下新建Application.mk文件,作用在于支持c++共享库:

APP_STL := gnustl_static

原方案使用的是共享库,这不一定都支持所有的机型,改用静态库gnustl_static 问题解决。
其中,APP_STL 可用值:
system 系统默认
stlport_static - 使用STLport作为静态库
stlport_shared - 使用STLport 作为共享库
gnustl_static - 使用GNU libstdc++ 作为静态库
gnustl_shared - 使用GNU libstdc++ 作为共享库

确保ndk配置正确,注意观察project下的local.properties文件,我这里是这样的:

ndk.dir=D\:\\Android\\sdk\\ndk-bundle
sdk.dir=D\:\\Android\\sdk

修改project下的gradle.properties文件,增加配置android.useDeprecatedNdk=true,其作用在于告诉系统使用ndk编译:

org.gradle.jvmargs=-Xmx1536m
android.useDeprecatedNdk=true

修改app目录下的build.gradle文件,增加配置:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        ...
        ndk{
            abiFilters "armeabi-v7a"
        }
    }
    sourceSets{
        main{
            jni.srcDir=[]
            jniLibs.srcDirs = ['src/main/libs']
        }
    }
   ...
}

ndk的abiFilters配置作用在于限定生成的cpu/abi。
jni.srcDirs = [] 表示禁止as自动ndk编译,采用手动ndk-build。
jniLibs.srcDirs = [‘src/main/libs’] 表示经过ndk-build编译后的so路径。

jni文件夹下新建Cmd script,make_arm.cmd,用于手动ndk-build,内容如下(其实就是一句命令行操作执行ndk编译):

D:\Android\sdk\ndk-bundle\ndk-build.cmd APP_ABI="armeabi-v7a"

编译运行

然后我们可以在对应的目录下看到我们编译好的c程序可执行文件,我们把这个文件push到安卓设备,并赋予可执行权限:
自己动手编译C程序并运行于Android系统_第5张图片

静态库没有.so文件扩展名

添加当前路径为so库文件查找路径命令,防止elf文件运行阶段找不到so库的问题,LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/data/local/tmp

在这里插入图片描述

你可能感兴趣的:(Android)