java 如何调用一个已经存在的静态库,并输入和获取参数! 例如:静态库中已经存在函数 ret=ys_tpcall(aa);
发布网友
发布时间:2022-04-25 14:03
我来回答
共1个回答
热心网友
时间:2023-10-06 06:26
给出一个windows下dll的实例。linux下.a的静态库只是头文件和编译有所不同,另外需要将编译后的动态库文件放入/usr/lib下,使用ldconfig载入。
一 先制作一个系统中有的DLL文件(cpp给出的sdk接口)
既然是测试我们就把我们这个dll叫做testDll吧,为了简单其间,我只写一个add方法,就是简单的2个数字相加,对于真正的开发中我们肯定会遇到其他类型,java到c/cpp中类型需要转换,具体类型转换对应关系g一下就能得到,我也不在列举。c/cpp中一个class一般包含2个文件,一个头文件定义(*.h),一个文件主体(*.c/*.cpp)。啰嗦了这么多还是直接动手吧,先在vs2008中建立一个工程(当然你也可以直接编写不用这些IDE工具,gcc g++的命令自己g。下同,不在注释不在废话),选取win32工程
键入工程名字testDll,点击next选取DLL,然后点击完成
打开我们的testdll.cpp,添加进我们的add方法
C++代码
1.int add(int a,int b){
2. return a+b;
3.}
int add(int a,int b){
return a+b;
}
注意到文件列表里并没有testDll.h,因为我们要给出调用者一个接口,如果不给头文件,人家就没办法调用,所以我们就必须添加一个头文件testDll.h。
C++代码
1.#ifdef TEST_DLL
2.#define TEST_API __declspec(dllexport)
3.#else
4.#define TEST_API __declspec(dllimport)
5.#endif
6.
7./* Set up for C function definitions, even when using C++ */
8.#ifdef __cplusplus
9.extern "C" {
10.#endif
11.
12.TEST_API int add(int,int);
13.
14./* Ends C function definitions when using C++ */
15.#ifdef __cplusplus
16.}
17.#endif
#ifdef TEST_DLL
#define TEST_API __declspec(dllexport)
#else
#define TEST_API __declspec(dllimport)
#endif
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
TEST_API int add(int,int);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
在这个头文件中我们把我们的add方法给定义了进去。注意到testdll.cpp中#include "stdafx.h",所以我们就把这个testDll.h include进stdafx.h里面。
按道理说我们的这个dll已经完成了,但是一般c/cpp给接口SDK的时候大都给.h和.lib,为了一步生成dll和lib,我们添加进一个testDll.def,有了这个文件就可以一步生成dll和lib。在source file里右键add new item ,选择Mole-Definition File
键入testDll,OK了,我们可以直接build了。生成testDll.dll和testDll.lib。
把testDll.dll扔到system32目录里等待我们高大威猛的java jni调用。
二 JNI
2.1 编写java文件
为了显示我们的与众相同,我们就把我们的这个java文件命名为Demo.java顺便直接带上包名
,因为我们知道人家给我们的接口里有个add方法,所以我们就直接来个调用吧。
Java代码
1.package com.testJni.testDemo;
2.
3.public class Demo {
4. static
5. {
6. //System.out.println(System.getProperty("java.library.path"));
7. System.loadLibrary("testDll");
8. System.loadLibrary("jniDll");
9. }
10. public native static int add(int a,int b);
11.
12.}
package com.testJni.testDemo;
public class Demo {
static
{
//System.out.println(System.getProperty("java.library.path"));
System.loadLibrary("testDll");
System.loadLibrary("jniDll");
}
public native static int add(int a,int b);
}
demo.java代码暂时如此,我们把将要生成的jni的dll叫做jniDll,有童鞋讲,我不想用你这个烂名字jniDll多俗啊,没关系,你可以换,随你换,生成文件后你再换也可以,现在换也可以。
2.2 生成.h头文件
javah命令,不多讲。生成的文件com_testJni_testDemo_Demo.h这个文件的命名规则我就不多讲了,一目了然。
C++代码
1./* DO NOT EDIT THIS FILE - it is machine generated */
2.#include <jni.h>
3./* Header for class com_testJni_testDemo_Demo */
4.
5.#ifndef _Included_com_testJni_testDemo_Demo
6.#define _Included_com_testJni_testDemo_Demo
7.#ifdef __cplusplus
8.extern "C" {
9.#endif
10./*
11. * Class: com_testJni_testDemo_Demo
12. * Method: add
13. * Signature: (II)I
14. */
15.JNIEXPORT jint JNICALL Java_com_testJni_testDemo_Demo_add
16. (JNIEnv *, jclass, jint, jint);
17.
18.#ifdef __cplusplus
19.}
20.#endif
21.#endif
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_testJni_testDemo_Demo */
#ifndef _Included_com_testJni_testDemo_Demo
#define _Included_com_testJni_testDemo_Demo
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_testJni_testDemo_Demo
* Method: add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_testJni_testDemo_Demo_add
(JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
2.3 用c/cpp实现这个头文件
c/cpp中已经实现了这个add方法,我们只需要调用就可以啦。所以直接vs2008中建立一个dll工程,工程名我们就叫jniDll,具体过程不再多讲,方法同上面testDll的建立一样。在这个工程里kimmking把需要引用的包、文件等已经讲的很清楚了。打开jniDll.cpp,添加下面代码
C++代码
1.JNIEXPORT jint JNICALL Java_com_testJni_testDemo_Demo_add
2.(JNIEnv *env,jclass jobject,jint a,jint b){
3.
4. return add(a,b);
5.}
JNIEXPORT jint JNICALL Java_com_testJni_testDemo_Demo_add
(JNIEnv *env,jclass jobject,jint a,jint b){
return add(a,b);
}因为int对应的类型就刚好是jint,所以就不需要转换,其他需要转换的类型自己g对应关系转换,注意释放。
这个工程里我们还需要打开 stdafx.h添加
C++代码
1.#include <jni.h>
2.
3.#include "testDll.h"
4.#include "com_testJni_testDemo_Demo.h"
#include <jni.h>
#include "testDll.h"
#include "com_testJni_testDemo_Demo.h"
在编译这个jniDll工程的时候需要引入testDll.h,com_testJni_testDemo_Demo.h,另外添加testDll.lib这个依赖。
好了做好这些后,build下,生成了我们期待已久的jniDll.dll,把这个dll同样扔到system32下。
三 测试
本人特懒,不想写多余的class,所以直接修改Demo.java 这也是刚才为什么讲暂时如此的原因
Java代码
1.package com.testJni.testDemo;
2.
3.public class Demo {
4. static
5. {
6. //System.out.println(System.getProperty("java.library.path"));
7. System.loadLibrary("testDll");
8. System.loadLibrary("jniDll");
9. }
10. public native static int add(int a,int b);
11. public static void main(String[] args) {
12. System.out.println(add(7,2));
13. }
14.}
package com.testJni.testDemo;
public class Demo {
static
{
//System.out.println(System.getProperty("java.library.path"));
System.loadLibrary("testDll");
System.loadLibrary("jniDll");
}
public native static int add(int a,int b);
public static void main(String[] args) {
System.out.println(add(7,2));
}
}
四 最后补充
如果系统已经加载过c/cpp的dll,我们就不用再System.loadLibrary("testDll")了,加载一遍就可以了,因为我们刚才写的testDll系统没有加载,所以我就加载了一下。对于多个dll可以写多个System.loadLibrary去加载,修改static{}里面的内容不需要重新生成dll,除非你多加了一个调用方法,如果你看清楚规则,就不用javah命令就可以直接编写头文件,用javah太麻烦了。追问谢谢!按照你的说法,假设.a是别人提供的库,如果我要调用 的话,是不是还需要修改.a文件?重新编译?
追答.a一般是别人提供好的链接文件,你要将你java对应的.c和.a一起编译成.so。