Подтвердить что ты не робот

Вызов Haskell из Java с C между ними

Это, наверное, похоже на кошмар, но я бы очень хотел, чтобы это работало. Я использую этот пример по большей части: Вызов C из Haskell, и я пытаюсь заставить это работать на ubuntu.

Я запускаю это в java:

package test;

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

this в c после создания файла .h с помощью javah: (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: перемещение R_X86_64_PC32 против undefined символ `fibonacci_hs 'не может использоваться при создании общего объект; перекомпилировать с -fPIC/usr/bin/ld: окончательная ссылка не удалась: Плохая стоимость collect2: ld возвращен 1 статус выхода

Я не эксперт по какому-либо средству и не знаю, что с этим делать. Я пытался скомпилировать различные способы с помощью -fPIC, но я продолжал получать ту же ошибку. Любая идея, что я могу делать неправильно?

Спасибо!

4b9b3361

Ответ 1

Хотя я довольно много ответил на этот вопрос здесь: Связь между Java и Haskell, так как эта проблема больше связана с самой ошибкой, я буду добавлять детали для этого здесь. Проблема связана с тем, что Haskell очень хорошо поддерживает общие библиотеки, а Java требует их. Плагины зданий как общие библиотеки Haskell дают нам эту проницательность и обход:

В принципе вы можете использовать -shared без -динамического в шаге ссылки. Это означало бы статически связать rts все базовые библиотеки с вашей новой общей библиотекой. Это создаст очень большую, но автономную общую библиотеку. Однако для этого потребуется, чтобы все статические библиотеки были созданы с -fPIC, чтобы код был подходящим для включения в общую библиотеку, и мы не делаем этого в данный момент.

Если мы снова используем ldd, чтобы посмотреть на libfoo.so, что мы сделали, мы заметим, что он не имеет зависимости от библиотеки rts. Это проблема, которую нам еще предстоит разобраться, поэтому на данный момент мы можем просто добавить зависимость самостоятельно:

$ 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 в садовом разнообразии и использовать для этого одну из многих фреймворков/протоколов:

Буферы протокола из Google

Сбережение от Facebook

Avro (ну это в основном проводной протокол)

Из того, что вы пытаетесь сделать, Thrift может быть вашим лучшим выбором, поскольку он описывает полный клиентский/серверный пакет RPC, но я уверен, что любой из них будет в значительной степени работать над простым сокетом.