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.

中加载的内容