Ubuntu 12.04 搭建ndk编译环境

前端之家收集整理的这篇文章主要介绍了Ubuntu 12.04 搭建ndk编译环境前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

搭建ndk环境之前,请保证你能新建android项目并能在手机上正常运行

通过AS自动生成ndk环境

更新AS到较新的版本,通过File-setting-Androd SDK下载sdktools(这里不需要启动manager界面)
主要是这三项:cmake, lldb,ndk
待下载完成后,启动android studio,start a new project.
选中Include C++ Support,
如图
后续均可以默认,直到finish,等待自动生成

然而,实际运行总那么不尽人意。下面讲讲本人在配置环境是遇到的坑。

坑1:cmake 3.6.3155560 报错,GLIBCXX_2.4.18 required by cmake
可能ndk和cmake的版本不匹配吧,然后,我用AS自己的manager去下载两个新工具,还是报错,同样的错误!
查看GLIBCXX发现

好吧,却是没有!在没网没root权限的linux上,尝试去安装3.4.18这个库,遗憾的发现只有rpm包,ok下载安装包安装(本人推测是可行的)。
但在ubuntu下不能直接安装rpm包,需要使用alien工具(下载命令:sudo apt-get install alien)将rpm转换成deb包安装(本人推测也是可行的)。

$ alien ***.rpm
$ dpkg -i ****.deb

但在没root权限的linux中,就算将alien安装成功,执行alien 转换 rpm安装包也会失败,非root用户不能转换文件格式。
所以,放弃这个方法了。方案转换为:使用ndk 手动build工程,手动操作也有一个好处,你知道各个步骤怎么协调的(不要太依赖自动话工具,除非你已经懂了自动化构建的流程,那个时候,你需要节约时间,是完全没有问题的)。


直接使用ndk build

坑2:将java文件生成h头文件失败
命令:javah jni ***.***.***.ClassName
这个命令执行的路径需要注意:

  1. AS 在**/src/main/java 下执行javah 命令
    首先需要class文件,因此你需要先通过javac 编译这个java文件以便生成class文件
  2. 者在project/build/intermediates/classes/debug/目录下执行
    且class的名字一定要是全限定名称,即你的package+name(.class 注:参数是class文件,不是java文件,你可以通过AS工具栏上的build-MakeProject生成class文件,这个文件就在上述的classes/debug/目录下,且不需要后缀)

.h文件生成后,就开始写C(/C++)代码

此时,你已经能得到一个h文件,里面包含了你声明的public native method(只是看起来怪怪的,仔细看你就能看懂了)。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_lintan_jniapplication_JniJava */

#ifndef _Included_com_lintan_jniapplication_JniJava
#define _Included_com_lintan_jniapplication_JniJava
#ifdef __cplusplus
extern "C" {
#endif
/* * Class: com_lintan_jniapplication_JniJava * Method: max * Signature: (II)I */
JNIEXPORT jint JNICALL Java_com_lintan_jniapplication_JniJava_max
  (JNIEnv *,jobject,jint,jint);

/* * Class: com_lintan_jniapplication_JniJava * Method: strFromJni * Signature: ()Ljava/lang/String; */
JNIEXPORT jstring JNICALL Java_com_lintan_jniapplication_JniJava_strFromJni
  (JNIEnv *,jobject);

#ifdef __cplusplus
}
#endif
#endif

第15行末尾就是你的method名字,com开始就是你的包名类名等
而对应的我的java文件是这样的:

package com.lintan.jniapplication;

/** * Created by **** on 11/5/16. */
public class JniJava {
    /** * 返回两个整数中较大的一个 */
    public native int max(int a,int b);
    /** * 看看熟悉的Hello World */
    public native String strFromJni();
}

此时,你需要创建一个jni(cpp 也行)的文件夹,路径为”src/main/jni”
然后,你可以写你的C代码了,注意include的头文件
这是我的C文件

//
// Created by **** on 11/5/16.
//

#include <jni.h>
#include "com_lintan_jniapplication_JniJava.h"

JNIEXPORT jint JNICALL Java_com_lintan_jniapplication_JniJava_max
        (JNIEnv * env,jobject obj,jint a,jint b) {
    return (a > b) ? a : b;
}

JNIEXPORT jstring JNICALL Java_com_lintan_jniapplication_JniJava_strFromJni
        (JNIEnv * env,jobject obj) {
    return env->NewStringUTF("Hello World");

到这一步,代码写完了,怎么才能让java调用到这个max方法呢?

干货内容
在src/main/下执行ndk-build
报错,没有Android.mk文件!C语言的编译跟java不一样,so针对这段C代码需要用gcc 去编译,那么Android.mk文件写在哪儿?我觉得应该写到jni这个目录里。以后你也好看。

#以下两行代码必须,call my-dir 将返回Android.mk所在的目录
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# native这个单词要记住了,你以后添加的就是这个库
LOCAL_MODULE := "native"
# hello 这个是一个名字,可以随便起一个,此行代码也可以不要,注释而已
LOCAL_PACKAGE_NAME := hello

#这个就是C(CPP)文件了,里面是你的native方法的实现
LOCAL_SRC_FILES := CalculateTest.cpp
# 编译成共享库
include $(BUILD_SHARED_LIBRARY)

此时还没完,因为只告诉了需要编译,要编译出那些平台的呢,因此还需要在新建一个Application.mk的文件,编译出多个平台的so

#注意字别写错了,平台之间用空格隔开。
#就算ndk-build 没报错,在点击AS的Build是会报错,
#错误内容,大概是就setup.mk 说PROJECT_PATH NULL,这里注意。
#笔者当时将x86_64敲成了x86_62。。。
APP_ABI := x86_64 armeabi armeabi-v7a arm64-v8a x86 mips

然后ndk-build,成功后,你会发现在你的IDE工程窗口多一个libs目录,且里面就是你编译出来的so依赖库

好了,你可以用你的native方法了,笔者使用native方法代码为:

static {
        //加载你的so
        //libs文件夹下的so名字是添加了前缀的,不用管。
        System.loadLibrary("native");
    }
    // 这是包含native方法的类
    JniJava jniJava = new JniJava();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = (TextView) findViewById(R.id.test);
        //调用max方法
        String txt = jniJava.strFromJni() + " from Jni !";
        tv.setText(txt);
    }

保险起见,还是在app的build.gradle文件(不是project的build.gradle)里添加依赖

compile fileTree(dir: 'libs',include: ['*.jar','**/*.so'])

此时,你可以尝试AS的build,没问题。
Run,的时候发现,界面crash掉了,log发现,System.loadLibrary报错。。。。

找不到这个so,哦,AS在Run的时候,还是已gradle的方式编译+run,那么,我们ndk编译出来的so不认识吗?

因此要告诉gradle(在app build.gradle)defaultConfig下添加如下代码

ndk{
        moduleName "native"
        abiFilters("x86","x86_64","armeabi","armeabi-v7a","arm64-v8a","mips","mips64")
    }

到此,点击AS的熟悉Run绿色三角形箭头,success !

如果有讲得不对的地方,欢迎大家提出来,共同学习, 谢谢!

猜你在找的Ubuntu相关文章