用C作为中间层,从Java调用Haskell

18

这可能听起来像一场噩梦,但我真的很想让它工作。我主要使用这个例子:从Haskell调用C,并尝试在Ubuntu上使其工作。

我正在Java中运行此代码:

package test;

public class JniTest {
    public native int fib(int x);
}

在使用 javah 创建 .h 文件后,这是 C 语言中的代码(test_JniTest.c):

#include "test_JniTest.h"
#include "Safe_stub.h"

JNIEXPORT jint JNICALL Java_test_JniTest_fib(JNIEnv * e, jobject o, jint f)
{
  return fibonacci_hs(f);
}

然后在Haskell中用作参考(在存根之前):(Safe.hs)

module Safe where

import Foreign.C.Types

fibonacci :: Int -> Int
fibonacci n = fibs !! n
    where fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

fibonacci_hs :: CInt -> CInt
fibonacci_hs = fromIntegral . fibonacci . fromIntegral

foreign export ccall fibonacci_hs :: CInt -> CInt

这是我正在尝试编译的内容:

ghc -c -O Safe.hs

接着是:

ghc -shared -o libTest.jnilib -optc-O test_JniTest.c -I/usr/lib/jvm/java-6-sun-1.6.0.26/include -I/usr/lib/jvm/java-6-sun-1.6.0.26/include/linux

但是我遇到了这个错误:

/usr/bin/ld: test_JniTest.o: relocation R_X86_64_PC32 against undefined symbol `fibonacci_hs' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: final link failed: Bad value collect2: ld returned 1 exit status

我并不是一个C语言专家,对此毫无头绪。我尝试以各种方式使用-fPIC编译,但仍然遇到相同的错误。你有任何想法我可能做错了什么吗?

谢谢!


C代码难道不需要在某处启动Haskell运行时吗?我认为你需要将其放入代码中的某个地方,无论是在C侧还是Java侧。 - Theo Belaire
你有没有考虑使用JNA(https://github.com/twall/jna#readme)代替JNI? - Landei
1
我在这里回答了这个问题:https://dev59.com/32kv5IYBdhLWcg3wwTdm#10370902 - Samuel Audet
@SamuelAudet 嗨,你能把那个作为答案添加吗?如果你发布它,我很乐意接受。 - Charles Durham
2个回答

3
尽管我已经在这里回答了这个问题:Java和Haskell之间的通信,但由于这个问题更多地涉及错误本身,因此我将在此添加详细信息。该问题源于Haskell不太支持共享库,而Java则需要它们。使用Haskell共享库构建插件提供了这种洞见和解决方法:

In principle you can use -shared without -dynamic in the link step. That would mean to statically link the rts all the base libraries into your new shared library. This would make a very big, but standalone shared library. However that would require all the static libraries to have been built with -fPIC so that the code is suitable to include into a shared library and we don't do that at the moment.

If we use ldd again to look at the libfoo.so that we've made we will notice that it is missing a dependency on the rts library. This is problem that we've yet to sort out, so for the moment we can just add the dependency ourselves:

$ ghc --make -dynamic -shared -fPIC Foo.hs -o libfoo.so \
 -lHSrts-ghc6.11 -optl-Wl,-rpath,/opt/ghc/lib/ghc-6.11/
这是一种解决方法,因为它要求我们在构建时知道 rts 库的版本。

2
如果您的目标是实际完成某些任务(而不仅仅是玩弄JNI),我建议将其视为常规RPC问题,并利用其中的一个框架/协议:
1. Google的协议缓冲区 2. Facebook的Thrift 3. Avro(主要是一种线路协议) 从您尝试做的事情来看,Thrift可能是您最好的选择,因为它描述了一个完整的客户端/服务器RPC堆栈,但我相信它们中的任何一个都可以在简单的套接字上运行。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接