Как скомпилировать Haskell в статическую библиотеку?

Эй, я изучаю Haskell, и мне интересно использовать его для создания статических библиотек для использования в Python и, возможно, C. После некоторого поиска в Google я узнал, как заставить GHC выводить общий объект, но это динамически зависит от GHC` библиотеки. Полученный в результате компиляции в GHC файл ELF динамически зависит только от C-библиотек и имеет размер чуть меньше МБ - он был статически связан с библиотеками GHC. Как и если это может быть достигнуто для общих объектов?

Пример текущего состояния:

$ ghc --make -dynamic -shared -fPIC foo.hs -o libfoo.so
$ ldd libfoo.so
    linux-vdso.so.1 =>  (0x00007fff125ff000)
    libHSbase-4.2.0.2-ghc6.12.3.so => /usr/lib/ghc-6.12.3/base-4.2.0.2/libHSbase-4.2.0.2-ghc6.12.3.so (0x00007f7d5fcbe000)
    libHSinteger-gmp-0.2.0.1-ghc6.12.3.so => /usr/lib/ghc-6.12.3/integer-gmp-0.2.0.1/libHSinteger-gmp-0.2.0.1-ghc6.12.3.so (0x00007f7d5faac000)
    libgmp.so.10 => /usr/lib/libgmp.so.10 (0x00007f7d5f816000)
    libHSghc-prim-0.2.0.0-ghc6.12.3.so => /usr/lib/ghc-6.12.3/ghc-prim-0.2.0.0/libHSghc-prim-0.2.0.0-ghc6.12.3.so (0x00007f7d5f591000)
    libHSffi-ghc6.12.3.so => /usr/lib/ghc-6.12.3/libHSffi-ghc6.12.3.so (0x00007f7d5f383000)
    libc.so.6 => /lib/libc.so.6 (0x00007f7d5f022000)
    /lib/ld-linux-x86-64.so.2 (0x00007f7d60661000)

$ ghc foo.hs
$ ldd foo
    linux-vdso.so.1 =>  (0x00007fff2d3ff000)
    libgmp.so.10 => /usr/lib/libgmp.so.10 (0x00007f50014ec000)
    libm.so.6 => /lib/libm.so.6 (0x00007f5001269000)
    librt.so.1 => /lib/librt.so.1 (0x00007f5001061000)
    libdl.so.2 => /lib/libdl.so.2 (0x00007f5000e5d000)
    libc.so.6 => /lib/libc.so.6 (0x00007f5000afc000)
    libpthread.so.0 => /lib/libpthread.so.0 (0x00007f50008df000)
    /lib/ld-linux-x86-64.so.2 (0x00007f5001759000)

Если я попытаюсь скомпилировать его с помощью (без '-dynamic'):

$ ghc --make -shared -fPIC foo.hs -o libfoo.so
Linking libfoo.so ...
/usr/bin/ld: foo.o: relocation R_X86_64_32S against `stg_CAF_BLACKHOLE_info' can not be used when making a shared object; recompile with -fPIC
foo.o: could not read symbols: Bad value
collect2: ld returned 1 exit status

При поиске в Google я нашел кое-что обо всей этой проблеме - что это может происходить из-за того, что GHC скомпилирован особым образом (динамический/статический?), и поэтому статическая компоновка невозможна. Если это правда, как возможно, что двоичный файл ELF статически связан?

В любом случае, я надеюсь, что кто-то может пролить свет на это, так как огромное количество поисков в Google оставило у меня больше вопросов, чем я начал.

Огромное спасибо.


person kuratkull    schedule 27.02.2011    source источник
comment
Какую систему вы используете? Похоже, это x86_64 Linux. Версия GHC также важна, так как это может быть ошибка, которая с тех пор была исправлена. Динамическое связывание имело некоторые ошибки в прошлом, и это может быть одной из них.   -  person Tener    schedule 02.03.2011
comment
@Тенер | Компилятор Glasgow Haskell, версия 6.12.3, для Haskell 98, этап 2, загруженный GHC версии 6.12.1 | Может быть, мне стоит попробовать GHC 7, чтобы посмотреть, решает ли он эту проблему.   -  person kuratkull    schedule 03.03.2011
comment
@Тенер. Я установил GHC7, и он все еще не работает, хотя выдает немного другую ошибку. =››› --> ghc --make -shared -fPIC bwt.hs -o libbwt.so [1 of 1] Compiling Main ( bwt.hs, bwt.o ) Linking libbwt.so ... /usr/bin/ld: /usr/lib/ghc-7.0.2/base-4.3.1.0/libHSbase-4.3.1.0.a(Base__90.o): relocation R_X86_64_32S against "stg_upd_frame_info" can not be used when making a shared object; recompile with -fPIC /usr/lib/ghc-7.0.2/base-4.3.1.0/libHSbase-4.3.1.0.a: could not read symbols: Bad value collect2: ld returned 1 exit status   -  person kuratkull    schedule 15.03.2011
comment
@kuratkull Нет новостей об этой проблеме? У меня такое же желание.   -  person Stéphane Laurent    schedule 20.03.2017


Ответы (2)


Канонический способ таков:

  1. Экспорт функций (через FFI) для инициализации RTS (системы выполнения) сторонней программой
  2. Экспортируйте фактические функции, которые вы хотели бы реализовать в Haskell.

Это описано в следующих разделах руководства: [1] [2]

С другой стороны, вы можете попробовать технику, описанную в этом блоге (кстати, мою):

http://mostlycode.wordpress.com/2010/01/03/shared-haskell-so-library-with-ghc-6-10-4-and-cabal/

Это сводится к созданию небольшого файла C, который вызывается автоматически сразу после загрузки библиотеки. Он должен быть связан вместе с библиотекой.

#define CAT(a,b) XCAT(a,b)
#define XCAT(a,b) a ## b
#define STR(a) XSTR(a)
#define XSTR(a) #a

#include

extern void CAT (__stginit_, MODULE) (void);

static void library_init (void) __attribute__ ((constructor));
static void
library_init (void)
{
      /* This seems to be a no-op, but it makes the GHCRTS envvar work. */
      static char *argv[] = { STR (MODULE) ".so", 0 }, **argv_ = argv;
      static int argc = 1;

      hs_init (&argc, &argv_);
      hs_add_root (CAT (__stginit_, MODULE));
}

static void library_exit (void) __attribute__ ((destructor));
static void
library_exit (void)
{
    hs_exit ();
}

Редактировать: Исходное сообщение в блоге, описывающее этот метод, выглядит следующим образом: http://weblog.haskell.cz/pivnik/building-a-shared-library-in-haskell/

person Tener    schedule 18.03.2011
comment
Спасибо, но ни один из этих методов не работает (те же ошибки), и, вероятно, это связано с этим (найдено в одной из предоставленных вами ссылок): Однако на большинстве платформ для этого потребуется, чтобы все статические библиотеки были собраны с -fPIC, чтобы код подходит для включения в разделяемую библиотеку, и в настоящее время мы этого не делаем. Я могу предположить, что мне пришлось бы перекомпилировать GHC с -fPIC вручную, чтобы решить мою проблему - иначе это просто невозможно. Я отмечу ваш ответ как правильный, так как все это должно работать после перекомпиляции GHC. Большое спасибо :) - person kuratkull; 20.03.2011

Это заставляет ghc компилироваться статически (обратите внимание, что pthread предшествует optl-static): ghc --make -static -optl-pthread -optl-static test.hs

Изменить: Но статическая компиляция кажется немного рискованной. В большинстве случаев есть какие-то ошибки. А на моей х64 федоре вообще не работает. Полученный двоичный файл также довольно большой, 1,5M для main = putStrLn "hello world".

person Masse    schedule 27.02.2011
comment
Но это делает исполняемые файлы статическими, я хочу иметь статические библиотеки (.so/.a). Я пытался использовать там флаг '-shared', но получил: __DTOR_END__' нельзя использовать при создании общего объекта; перекомпилировать с -fPIC /usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/crtbeginTo: не удалось прочитать символы: неверное значение. Похоже, что создание статических библиотек может оказаться не таким уж простым делом. Или я что-то не так делаю? - person kuratkull; 28.02.2011