我正在开发具有多种语言编写的组件的应用程序。我试图获得在Jython中工作的Java工作正常的功能。 Java可以通过JNI访问一些本机/ C ++功能,并由SWIG包装。
每当我尝试导入项目中的所有类时,我都会收到PROJECTJNI无法链接的错误。这是我生产的最小案例:
import sys
sys.path.append('PROJECT.jar')
from com.whatever.project import *
以下是执行此操作时的错误消息:
$ jython Bootstrap.py
"my" variable $jythonHome masks earlier declaration in same scope at /usr/bin/jython line 15.
Traceback (most recent call last):
File "Bootstrap.py", line 9, in <module>
from com.whatever.project import *
java.lang.UnsatisfiedLinkError: com.whatever.project.PROJECTJNI.swig_module_init()V
at com.whatever.project.PROJECTJNI.swig_module_init(Native Method)
at com.whatever.project.PROJECTJNI.<clinit>(PROJECTJNI.java:974)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:278)
at org.python.core.Py.loadAndInitClass(Py.java:909)
at org.python.core.Py.findClassInternal(Py.java:844)
at org.python.core.Py.findClass(Py.java:869)
at org.python.core.packagecache.PackageManager.basicDoDir(PackageManager.java:107)
at org.python.core.packagecache.SysPackageManager.doDir(SysPackageManager.java:138)
at org.python.core.PyJavaPackage.fillDir(PyJavaPackage.java:123)
at org.python.core.imp.importAll(imp.java:1051)
at org.python.core.imp.importAll(imp.java:1039)
at org.python.pycode._pyx0.f$0(Bootstrap.py:9)
at org.python.pycode._pyx0.call_function(Bootstrap.py)
at org.python.core.PyTableCode.call(PyTableCode.java:165)
at org.python.core.PyCode.call(PyCode.java:18)
at org.python.core.Py.runCode(Py.java:1275)
at org.python.util.PythonInterpreter.execfile(PythonInterpreter.java:235)
at org.python.util.jython.run(jython.java:247)
at org.python.util.jython.main(jython.java:129)
java.lang.UnsatisfiedLinkError: java.lang.UnsatisfiedLinkError: com.whatever.project.PROJECTJNI.swig_module_init()V
第15行出现在我们调用jython的任何时候,我们一直忽略它。
我们可以通过简单地一次加载一个来从Java项目中获取类:
com.whatever.project import Class1
com.whatever.project import Class2
...
com.whatever.project import Class50
这非常不切实际,因为即使是短的python脚本,我们也可能需要十几个类。其中许多是我们捕获的具有独特类型的例外。因此,任何可靠地处理错误的东西都可能需要大量的类。
根据jython documentation我应该能够隐藏PROJECTJNI,因此不会通过这样做来加载它,但我发现文档不太清楚。以下是我的尝试:
import com.whatever.project
__all__ = dir(com.whatever.project)
__all__.remove('PROJECTJNI')
from com.whatever.project import *
但是这会失败并且仍然显然正在尝试加载PROJECTJNI。
我还尝试修复本机可执行文件,以便它可以与correctl链接。我学习了另一个使用JRuby的组没有包括所有内容的问题,所以我决定检查源和二进制文件。我在Swig创建的Project_wrap.cpp文件中找到了void swig_module_init()。它被隐藏在一个宏后面,但它就在那里,并且objdump证实了:
$objdump libPROJECT.so -t |grep PROJECTJNI |grep init
000000000051a900 l O .data 00000000000009d0 _ZZ59Java_com_whatever_project_PROJECTJNI_swig_1module_1initE7methods
0000000000263f66 g F .text 00000000000000d1 Java_com_whatever_project_PROJECTJNI_swig_1module_1init
我是否在执行任何故障排除步骤时出错?是Jython中的一个错误吗?是否有简单的Python解决方法使其跳过加载PROJECTJNI?
任何让我跳过链接或正确链接的内容都将被接受。
答案 0 :(得分:0)
在其中一个Java类BinaryLoader上,有一个名为void load_binary()的方法在该类的静态部分中调用:
public class BinaryLoader
{
static
{ load_binaries(); }
public static void load_binaries()
{
// Deep inside here is a call to actually load the shared library. Using
load_shared_library_from_jar("PROJECT");
}
... // more details here
}
我们的Java代码使用本机API调用此方法作为类加载。我们的JRuby代码在课程被触及时调用了这个,只是使用Constant的名称,类的名称,调用静态部分。这里要澄清的是我们的文档和实时Ruby脚本中的示例:
# Tells Jruby to load the Java Interopability layer.
require 'java'
# Loads the PROJECT Java tools.
require 'PROJECT.jar'
# Shorten the PROJECT tool names from their obnoxiously long Java name.
module PROJECT
include_package "com.whatever.project"
end
# Let Ruby know the BinaryLoader exists and it will have PROJECT load all the system binaries.
PROJECT::BinaryLoader
显然需要JarFile足以使Ruby中的所有Native符号和Java类都可用,并且二进制文件不会被加载,直到最后一行只是一个表达式解析为类的名称并强制执行要运行的静态部分。实际的方法调用看起来像:PROJECT :: BinaryLoader.load_binaries
在Jython中,即使在BinaryLoader类上调用其他静态方法时,也从未调用静态部分。我强制它通过导入最少的Java和Native符号手动调用方法来调用方法:
# Tells Jython to load the python system Interopability tools.
import sys
# When searching for python symbols, this Java jar should be search also.
sys.path.append('PROJECT.jar')
# Load just enough the have the JVM Know how to load the native PROJECT libraries
from com.whatever.project import PROJECT
from com.whatever.project import BinaryLoader
# Load any native binaries that are required
BinaryLoader.load_binaries()
# After this line is run in any given script then PROJECT can be used.
from com.whatever.project import *
显然,原始二进制文件根本没有被加载。加载这些的任何东西都是可以接受的解决方案。
这可以通过尽可能早地完成它应该具有的工作来解决Jython不调用静态部分的问题。这似乎是Jython中的一个错误,但可能是在Java中没有强制执行静态加载顺序的保证。无论哪种方式,因为这种不兼容性,我们可能会删除静态部分,以防止未来的Java广告Ruby Devs添加可能无法在Python中加载的内容。