简介:
最近,使用native进行开发的工作有不少。本文进行native编程实践,将整个步骤以及注意事项做一个笔记。本次实践不使用任何集成开发编译环境,而是用最原始的文本编辑器+命令行的方式进行。
实例说明:
实现一个简单的jni调用,模拟“通过jni打印log日志,日志由java层传递给c层”。
开发步骤:
分成两大步骤来演示,一, java代码的编辑,编译,以及c头文件的生成;二,c语言代码的编辑,编译。
1. java代码的编辑,编译,以及c头文件的生成:
1)java代码编辑:MyLog.java文件,内容如下:
public class MyLog {
//获取c代码的日志
native void outputLog(String str);
static { System.loadLibrary("clog");}
public static void main(String[] args) {
MyLog a = new MyLog();
a.outputLog("I from Java!!!");
}
}
2)编译生成.class文件:
用javac命令编译即可:
aibook@aibookdeMacBook-Pro java_call_c % javac MyLog.java
aibook@aibookdeMacBook-Pro java_call_c % ls
MyLog.class MyLog.java
MyLog.class,就是java字节码文件。
3)生成头文件(.h文件):
用javah命令:
aibook@aibookdeMacBook-Pro java_call_c % javah MyLog
aibook@aibookdeMacBook-Pro java_call_c % ls
MyLog.class MyLog.h MyLog.java
其中,MyLog.h文件的内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class MyLog */
#ifndef _Included_MyLog
#define _Included_MyLog
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: MyLog
* Method: outputLog
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_MyLog_outputLog
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
2. c语言代码的编辑,编译:
1)c语言代码:
新建立一个MyLog.c文件,内容如下:
#include "MyLog.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_MyLog_outputLog
(JNIEnv *env, jobject obj,jstring str)
{
const char *cStr = (*env)->GetStringUTFChars(env, str, 0);
printf("%s!\n", cStr);
return;
}
2)编译:编译c代码,用gcc命令将.c文件编译成一个.o:
gcc -I . -c MyLog.c
注意,可能出现如下问题:
fatal error: 'jni.h' file not found
#include <jni.h>
^~~~~~~
1 error generated.
显然,是找不到jni头文件的问题。我的解决办法是:
把jni相关的文件copy到自己当前目录,即和代码放在同一个目录下。
jni相关文件的来源:
/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/include/jni.h
/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/include/darwin/jni_md.h
运行完gcc -I . -c MyLog.c 命令后的目录文件:
MyLog.c MyLog.h MyLog.o jni.h jni_md.h
MyLog.class MyLog.java
3)链接:再将.o链接成一个lib库:
gcc -dynamiclib -o libclog.jnilib MyLog.o
libclog.jnilib就是最后生成的nativelib库文件。
运行:
最后,运行结果如下:
MacBook-Pro java_call_c % java MyLog
I from Java!!!!
运行的时候,有可能出现如下错误:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no clog in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
at MyLog.<clinit>(MyLog.java:6)
这是因为虽然库都有了,但是path没有指定。
我的解决方式是:直接在环境变量中指定,如下:
直接修改.bash_profile文件,在PATH环境变量中加入自己的编译目录。
PATH=$ndk:$JAVA_HOME/bin:$PATH:/Users/aaa/work/stu/c_stu/java_call_c
总结一下整个步骤:
1.编写java代码--> 2. javac编译成字节码 --> 3. javah生成c头文件-->
4.编写c代码--> 5.gcc编译c代码为.o文件 --> 6.gcc链接成lib库 -->
7. java运行