使用MinGW gcc 创建DDL和调用DDL
使用 gcc 编译生成 ddl 文件所会使用到的 gcc 命令
选项 | 解释 |
---|---|
-Wall | 生成所有警告信息 |
-o FILENAME | 生成指定的输出文件,用在生成可执行文件时。 |
-shared | 生成共享目标文件。通常用在建立共享库时。 |
-c | 只激活预处理,编译,和汇编,也就是他只把程序做成obj文件,会生成 .0 文件 |
-S | 只激活预处理和编译,就是指把文件编译成为汇编代码,会生成 .s 文件 |
创建动态链接库(.ddl文件)
隐式调用法
1.先创建一个测试文件夹
2.在测试文件夹中创建一个 <20171426.h>
/*
* author : snowflake
* date : 2019/09/04
*/
#ifndef _20171426_H_
#define _20171426_H_
#ifdef __cplusplus
extern "C" {
#endif
extern __declspec (dllexport) void sayHello();
#ifdef __cplusplus
}
#endif
#endif // ~_MY_DLL_H_
3.在测试文件夹中创建一个 <20171426.c>
#include <stdio.h>
void sayHello() {
printf("%s", "小颖最可爱啦!!!");
}
4.创建一个测试文件 <test.c>
#include <stdio.h>
#include "20171426.h"
int main() {
sayHello();
return 0;
}
5.目录结构如下
按住 shift 键,右击鼠标会出现 在此处打Powershell 窗口
执行
gcc -Wall -shared 20171426.c -o 20171426.dll
或者
gcc --shared 20171426.c -o 20171426.dll
会生成一个 20171426.dll 文件
接着编译 test.c 文件
/*
* gcc 是一个工具,小颖可以理解为 javac 进行编译
* test.c 是测试源文件
* 20171426.dll 是动态链接库文件,代表编译 test.c 文件时要用到 20171426.dll 链接库
* -o 暂时不知道
* test 生成的可执行文件名
*/
gcc test.c 20171426.dll -o test
会生成一个 test.exe 可执行文件
然后在控制台输入 .\test 即可执行
动态链接库
Java 调用动态链接库
- 工具:IDEA
- C语言编译工具:MinGW GCC
- JDK 版本:1.8
创建 Java 工程
创建 JNI.java 文件
package xyz.snowflake.jni;
import org.junit.Test;
/**
* @author snowflake
* @create-date 2019-09-04 12:07
*/
public class JNI {
public native void sayHello();
}
构建工程,为了生成 out 文件夹
使用如下命令
javac
-h
$ContentRoot$\jni
-d
$ContentRoot$\out\production\$ModuleName$
$FileDir$\$FileName$
执行后,会生成 <全类名(包名+类名)> + “.h” 头文件
本例中
javac
-h E:\Learning-records\大三上学期\计算机操作系统\dll\jni
-d E:\Learning-records\大三上学期\计算机操作系统\dll\out\production\dll
E:\Learning-records\大三上学期\计算机操作系统\dll\src\xyz\snowflake\jni\JNI.java
现在项目结构如下
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class xyz_snowflake_jni_JNI */
#ifndef _Included_xyz_snowflake_jni_JNI
#define _Included_xyz_snowflake_jni_JNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: xyz_snowflake_jni_JNI
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_xyz_snowflake_jni_JNI_sayHello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
然后实现头文件中定义的方法
JNI.c
#include <jni.h>
#include <stdio.h>
#include "xyz_snowflake_jni_JNI.h"
JNIEXPORT void JNICALL Java_xyz_snowflake_jni_JNI_sayHello(JNIEnv *env, jobject thisObj) {
printf("%s", "Hello World!\n");
return;
}
执行
gcc
-Wl,--kill-at
-I "$JDKPath$\include"
-I "$JDKPath$\include\win32"
-shared
$ContentRoot$\jni\$FileNameWithoutAllExtensions$.c
-o
$ContentRoot$\lib\$FileNameWithoutAllExtensions$.dll
本例中是
D:\MinGW\bin\gcc.exe
-Wl,--kill-at
-I "C:\Program Files\Java\jdk-10.0.2\include"
-I "C:\Program Files\Java\jdk-10.0.2\include\win32"
-shared E:\Learning-records\大三上学期\计算机操作系统\dll\jni\JNI.c
-o E:\Learning-records\大三上学期\计算机操作系统\dll\lib\JNI.dll
生成 JNI.dll 文件后的目录结构
然后创建测试类
package xyz.snowflake.jni;
/**
* @author snowflake
* @create-date 2019-09-05 21:15
*/
public class JNITest {
static {
System.loadLibrary("JNI");
}
public static void main(String[] args) {
JNI jni = new JNI();
jni.sayHello();
}
}
此时项目结构如下
进行测试
会报如下错误
java.lang.UnsatisfiedLinkError: no JNI in java.library.path: [...]
at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2654)
at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:876)
at java.base/java.lang.System.loadLibrary(System.java:1875)
at xyz.snowflake.jni.JNITest.<clinit>(JNITest.java:10)
Exception in thread "main"
解决方法
编辑配置,配置 VM
-Djava.library.path=<lib文件夹路径名,也就是 dll 文件所在的文件夹>
但是运行由会报如下的错误
java.lang.UnsatisfiedLinkError: E:\Learning-records\大三上学期\计算机操作系统\dll\lib\JNI.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform
at java.base/java.lang.ClassLoader$NativeLibrary.load0(Native Method)
at java.base/java.lang.ClassLoader$NativeLibrary.load(ClassLoader.java:2424)
at java.base/java.lang.ClassLoader$NativeLibrary.loadLibrary(ClassLoader.java:2481)
at java.base/java.lang.ClassLoader.loadLibrary0(ClassLoader.java:2678)
at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2643)
at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:876)
at java.base/java.lang.System.loadLibrary(System.java:1875)
at xyz.snowflake.jni.JNITest.<clinit>(JNITest.java:10)
Exception in thread "main"
解决方案,使用 X86 版本 的 JDK
我将 JDK 版本更换为 JDK1.8 X86 版本后,运行结果正常
结果如下
自己遇到的其他的错误
错误
����: �Ҳ��������������� semester
ԭ��: java.lang.ClassNotFoundException: semester
不知道什么原因
错误
����: �Ҳ��������������� semester
不知道什么原因
错误
Exception in thread "main" java.lang.UnsupportedClassVersionError: xyz/snowflake/jni/JNI has been compiled by a more recent version of the Java Runtime (class file version 54.0), this version of the Java Runtime only recognizes class file versions up to 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at com.intellij.junit4.JUnit4TestRunnerUtil.loadTestClass(JUnit4TestRunnerUtil.java:316)
at com.intellij.junit4.JUnit4TestRunnerUtil.buildRequest(JUnit4TestRunnerUtil.java:147)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:46)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
解决方法
更换 JDK 版本一致
参考文章
https://www.cnblogs.com/lichmama/p/4126323.html
https://www.xuebuyuan.com/1528987.html