最近在阅读有关jni的文档,想在Ubuntu下尝试一下文档中的简单例子,结果出现一些编译错误等一系列问题。这里将整个流程以及遇到的问题共享给大家。
1.配置java环境
其实我们只要从官网下载java JDK ,之后解压便成。例如这里我是从如下网址下载的 jdk1.7 :
http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html
Linux x64 | 91.85 MB | ![]() |
具体下载什么版本,要看您的系统是什么样的,我的是linux 64 位的,故下载该版本。
下载完后解压它,就算环境已经ok了。接下来我们开始以一个简单的例子进行编译。
2. 定义本地方法
编写如下代码,以HelloWorld.java 命名,该代码中包含一个本地方法“private native void print();"
class HelloWorld {
private native void print(); //本地方法
public static void main(String[] args) {
new HelloWorld().print(); //调用本地方法
}
static {
System.loadLibrary("HelloWorld"); //导入动态库
}
}
3.编译HelloWorld类
这里假设JDK 包同源码都放置在~/JNI 目录,解压后在该目录中将看到 一个“jdk1.7.0_25” 目录,这个就是我们的java 环境。这样我们执行如下命令,将生成HelloWorld.class文件。
~/JNI$ ./jdk1.7.0_25/bin/javac HelloWorld.java
4.创建本地方法头文件HelloWorld.h
执行如下命令:
~/JNI$ ./jdk1.7.0_25/bin/javah -jni HelloWorld
HelloWold.h 内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: print
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_print
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
5. 实现本地方法HelloWorld.c
具体内容如下:
#include <jni.h>
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
printf("Hello World!\n");
return;
}
6.编译本地方法生成so 库
执行如下命令生成so库:
~/JNI$ gcc -shared -I ./jdk1.7.0_25/include -I ./jdk1.7.0_25/include/linux -I /usr/include HelloWorld.c -o libHelloWorld.so
执行以上命令之后出现如下的错误:
/usr/bin/ld: /tmp/cch0Ohfg.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
/tmp/cch0Ohfg.o: could not read symbols: Bad value
collect2: ld returned 1 exit status
我们加入-fPIC 选项重新编译:
~/JNI$ gcc -fpic -shared -I ./jdk1.7.0_25/include -I ./jdk1.7.0_25/include/linux -I /usr/include HelloWorld.c -o libHelloWorld.so
编译成功。
执行ls 查看结果如下:
HelloWorld.c HelloWorld.class HelloWorld.h HelloWorld.java jdk1.7.0_25 libHelloWorld.so
7.运行程序
~/JNI$ ./jdk1.7.0_25/bin/java HelloWorld
Exception in thread "main" java.lang.UnsatisfiedLinkError: no HelloWorld in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1878)
at java.lang.Runtime.loadLibrary0(Runtime.java:849)
at java.lang.System.loadLibrary(System.java:1087)
at HelloWorld.<clinit>(HelloWorld.java:11)
出现找不到so库的错误。
这里我们将libHelloWorld.so 移到/usr/lib 目录.
~/JNI$ sudo mv libHelloWorld.so /usr/lib
之后再运行程序:
~/JNI$ ./jdk1.7.0_25/bin/java HelloWorld
Hello World! //结果出来了
到此就算成功了。
8.总结
这里只是在Ubuntu 环境下,标准的jni编译过程,对于Android jni 编程来说,有另一套编译机制,在以后的文章中将会论及。