Swig 创建的 Java 包的 Jython 导入失败 link
Jython import of Java package created by Swig fails to link
我正在开发具有用多种语言编写的组件的应用程序。我正在尝试获得在 Jython 中工作的 Java 中正常工作的功能。有一些 native/C++ 功能 Java 通过 JNI 访问并由 SWIG 包装。
每当我尝试在项目中导入所有 类 时,我都会收到无法 linked 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[=13=](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
每当我们调用 jython 时,第 15 行的东西就会出现,我们一直忽略它。
我们可以让 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。
我还尝试修复本机可执行文件,以便 link 可以针对 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?
任何能让我跳过 link 或正确 link 的东西都会被接受。
在 Java class 之一的 BinaryLoader 上,有一个名为 void load_binary() 的方法,该方法在 class:
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 在加载 class 时调用此方法。当 class 为 'touched' 时,我们的 JRuby 代码调用了它,仅使用常量的名称,即 class 的名称,调用了静态部分。在这里澄清的是我们文档中的示例和执行此操作的实时 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 足以使所有 Native 符号和 Java classes 在 Ruby 中可用并且二进制文件直到最后一行才加载,这只是解析为 class 的名称并将静态部分强制为 运行 的表达式。实际的方法调用看起来像:PROJECT::BinaryLoader.load_binaries
在 Jython 中,即使在 BinaryLoader 上调用其他静态方法时,也从未调用静态部分 class。我强制它通过导入最小的 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 开发人员添加可能无法在 Python.
中加载的内容
我正在开发具有用多种语言编写的组件的应用程序。我正在尝试获得在 Jython 中工作的 Java 中正常工作的功能。有一些 native/C++ 功能 Java 通过 JNI 访问并由 SWIG 包装。
每当我尝试在项目中导入所有 类 时,我都会收到无法 linked 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[=13=](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
每当我们调用 jython 时,第 15 行的东西就会出现,我们一直忽略它。
我们可以让 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。
我还尝试修复本机可执行文件,以便 link 可以针对 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?
任何能让我跳过 link 或正确 link 的东西都会被接受。
在 Java class 之一的 BinaryLoader 上,有一个名为 void load_binary() 的方法,该方法在 class:
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 在加载 class 时调用此方法。当 class 为 'touched' 时,我们的 JRuby 代码调用了它,仅使用常量的名称,即 class 的名称,调用了静态部分。在这里澄清的是我们文档中的示例和执行此操作的实时 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 足以使所有 Native 符号和 Java classes 在 Ruby 中可用并且二进制文件直到最后一行才加载,这只是解析为 class 的名称并将静态部分强制为 运行 的表达式。实际的方法调用看起来像:PROJECT::BinaryLoader.load_binaries
在 Jython 中,即使在 BinaryLoader 上调用其他静态方法时,也从未调用静态部分 class。我强制它通过导入最小的 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 开发人员添加可能无法在 Python.
中加载的内容