Как скомпилировать Haskell в статическую библиотеку?
Эй,
Я изучаю Haskell, и я заинтересован в использовании его для создания статических библиотек для использования в Python и, возможно, C. После некоторого поиска в Google я узнал, как получить GHC для вывода общего объекта, но он динамически зависит от библиотек GHC,
Получающийся ELF от компиляции в GHC динамически зависит и только от C libs, и он немного под MB по размеру - он был статически связан с библиотеками 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
Когда googling я нашел что-то по всей этой проблеме, это может быть связано с тем, что GHC скомпилирован определенным образом (dynamic/static?), и поэтому статическая привязка невозможна. Если это так, то как возможно, что бинарный файл ELF статически связан?
В любом случае, я надеюсь, что кто-то может пролить свет на это, так как огромное количество googling оставили мне больше вопросов, чем я начал.
Огромное спасибо.
Ответы
Ответ 1
Канонический способ:
- Экспорт функций (через FFI) для инициализации RTS (система времени выполнения) по внешней программе
- Экспорт фактических функций, которые вы хотели бы реализовать в 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/
Ответ 2
Это делает ghc-компиляцию статически (обратите внимание, что pthread до optl-static):
ghc --make -static -optl-pthread -optl-static test.hs
Изменить: Но статическая компиляция кажется немного рискованной. В большинстве случаев есть некоторые ошибки. И на моей x64 Fedora это не работает вообще. Получившийся двоичный файл также довольно большой, 1,5 М для main = putStrLn "hello world"