Java使用JNI导入使用第三方功能(Python.h)的C共享库
我在使用JNI整合“lib.so”时遇到了问题,这个“lib.so”是从“lib.c”编译而来的,代码大概是这样的:
#include <jni.h>
#include "messageService.h"
#include <Python.h>
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;
JNIEXPORT jboolean JNICALL Java_Test_test
(JNIEnv * pEnv, jclass clazz)
{
Py_Initialize();
pName = PyString_FromString("mylib");
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule,"test");
if (pFunc && PyCallable_Check(pFunc)) {
PyObject_CallObject(pFunc, NULL);
Py_DECREF(pFunc);
if (PyErr_Occurred()){
PyErr_Print();
jclass exc = (*pEnv)->FindClass( pEnv, "java/lang/Exception" );
if ( exc != NULL )
(*pEnv)->ThrowNew( pEnv, exc, "in C code; Error while executing \"test\"" );
return (jboolean) 0;
}
return (jboolean) 1;
}
else {
if (PyErr_Occurred())
PyErr_Print();
jclass exc = (*pEnv)->FindClass( pEnv, "java/lang/Exception" );
if ( exc != NULL )
(*pEnv)->ThrowNew( pEnv, exc, "in C code; Cannot find function \"test\"" );
return (jboolean) 0;
}
Py_XDECREF(pFunc);
return (jboolean) 0;
}
else {
PyErr_Print();
jclass exc = (*pEnv)->FindClass( pEnv, "java/lang/Exception" );
if ( exc != NULL )
(*pEnv)->ThrowNew( pEnv, exc, "in C code; Failed to load \"mylib\"" );
}
return (jboolean) 0;
}
而且我用javah -jni ...生成了头文件。
创建lib.so文件的过程很顺利。我的Java程序是:
public class Test {
static{
System.load("/pathtomyso/lib.so")
}
public static native boolean test();
public static void main(String[] args){
boolean result = false;
try{
result = Test.test();
System.out.println(result);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
}
当我运行我的程序时,出现了这样的结果:
主线程出现异常 "main" java.lang.UnsatisfiedLinkError: /pathtomyso/lib.so: /pathtomyso/lib.so: 未定义的符号: Py_Initialize
你知道为什么Python.h中的功能Py_Initialize会变得未知吗?
编辑:1
我在网上查了一下,似乎得到了错误的答案。
现在我使用的是:
cc lib.c -o lib.so -I/usr/lib/jvm/java-7-openjdk-i386/include/ -I /usr/include/python2.7 -lpython2.7 -shared -lc
但我仍然遇到了一些错误。我的Python模块使用了蓝牙栈blueZ的Python封装。但是不知为何,它无法导入这个模块中集成的共享库:
File "/usr/local/lib/python2.7/dist-packages/mylib.egg/mylib/test.py", line 10, in <module>
import bluetooth
File "/usr/local/lib/python2.7/dist-packages/bluetooth/__init__.py", line 34, in <module>
from bluez import *
File "/usr/local/lib/python2.7/dist-packages/bluetooth/bluez.py", line 6, in <module>
import _bluetooth as _bt
/usr/local/lib/python2.7/dist-packages/bluetooth/_bluetooth.so: undefined symbol: PyExc_ValueError
1 个回答
0
我遇到过类似的问题,并且解决了。我的问题和解决方案是这样的:我在Java中通过JNA调用liba.so,liba.so又调用libb.so,libb.so再调用一个Python脚本。在liba.so中,你需要在dlopen的时候使用RTLD_NOW | RTLD_GLOBAL。这就是全部内容。