如何將Haskell編譯為靜態庫?




static-libraries static-linking (2)

嘿,我正在學習Haskell並且我有興趣使用它來製作靜態庫以便在Python和C中使用。經過一些谷歌搜索後我發現如何讓GHC輸出一個共享對象,但它動態地依賴於GHC。的圖書館。 在GHC中編譯得到的ELF動態依賴於C libs,並且它的大小不到MB - 它與GHC的libs靜態鏈接。 如何以及如果能夠實現共享對象?

當前狀態示例:

$ 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

當谷歌搜索時,我發現了一些關於整個問題的事情 - 它可能來自GHC以特定方式(動態/靜態?)編譯的事實,因此靜態鏈接是不可能的。 如果這是真的,那麼ELF二進製文件可能是靜態鏈接的嗎?

無論如何,我希望有人可以對此有所了解,因為大量的谷歌搜索給我留下了比我開始時更多的問題。

非常感謝。


規範的方法是這樣的:

  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/http://weblog.haskell.cz/pivnik/building-a-shared-library-in-haskell/


這使得ghc靜態編譯(注意pthread在optl-static之前): ghc --make -static -optl-pthread -optl-static test.hs

編輯:但靜態編譯似乎有點冒險。 大多數時候都存在一些錯誤。 在我的x64 fedora上它根本不起作用。 得到的二進製文件也相當大,1.5M for main = putStrLn "hello world"





ghc