在Scala中使用Linux共享对象

时间:2014-03-17 15:18:56

标签: scala ffi shared-libraries

如何在Scala中访问* .so对象及其方法?以下是一个Python示例:https://github.com/soulseekah/py-libgfshare/blob/master/gfshare.py其中ctypes库用于与libgfshare.so进行交互。在Scala中我需要使用哪些工具来实现相同的功能?

2 个答案:

答案 0 :(得分:3)

如果您想与不支持JNI (Java Native Interface)的本地库进行交互(即,不是专为与Java VM交互而设计的),请尝试JNA (Java Native Access)。 Google Code上还有Scala Native Access项目,它似乎提供了更多" scala-friendly" API,但似乎无效(最后一次提交是在2010年)。

答案 1 :(得分:1)

之前的答案是正确的,JNI是要走的路,但要让它全部工作需要一点点坚持不懈。可以找到真实世界本地库的多平台Scala接口的示例here。总结一下,您需要采取的步骤详述如下。

首先,定义要用于访问本机库的Scala接口。 Scala中的本机接口声明示例如下:

package foo.bar

object NativeAPI {
  @native def test(data: Array[Byte]): Long
}

使用scalac编译此文件,然后使用javah为JNI本机存根输出合适的C / C ++头文件。需要将javah标头生成器(Java SDK的一部分)调用为

javah -classpath <path-to-scala-libs> foo.bar.NativeAPI$

请注意,Scala编译器会将$添加到Scala对象中。从JVM调用API时,将调用此标头中生成的函数。对于此示例,此函数的javah生成的C头的声明将如下所示:

JNIEXPORT jlong JNICALL Java_foo_bar_NativeAPI_00024_test(JNIEnv *, jobject, jbyteArray);

此时,您需要创建一个C文件,然后将此函数从JVM api映射到您打算使用的本机库。生成的C文件需要编译到共享库(Linux中的.so),该库引用您要调用的本机库。进入JVM的C接口描述为here

对于此示例,我们调用此库libjni-native.so并假设它引用名为libfoo.so.0的第三方库。如果这两个库在操作系统的动态库搜索路径中都可用,那么您需要指示JVM加载库并按如下方式调用该函数:

System.loadLibrary("libjni-native.so")
val data = new Array[Byte](100)
// Populate 'data'
NativeAPI.test(data)

在Linux和OSX计算机上,动态链接器将知道libfoo.so.0(OSX的.dylib)是libjni-native.so的依赖项,并将自动加载它。您现在可以从Scala调用test函数。您现在应该能够调用foo.bar.Native.test()并执行本机功能。

在现实世界中,您可能需要将.so库捆绑到JAR文件中以进行分发。为此,您可以将共享库放在项目的resources目录中的合适目录中。这些库需要在运行时从JAR文件复制到临时目录,然后使用System.load("/tmppath/libjni-native.so")加载。来自LibLoaderexample显示了如何实现这一目标。