如何将Haskell编译为静态库?

时间:2011-02-27 03:09:43

标签: haskell static-libraries static-linking ghc

嘿 我正在学习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二进制文件可能是静态链接的吗?

无论如何,我希望有人可以对此有所了解,因为大量的谷歌搜索给我留下了比我开始时更多的问题。

非常感谢。

2 个答案:

答案 0 :(得分:4)

规范方式是:

  1. 导出功能(通过FFI)以通过外部程序初始化RTS(运行时系统)
  2. 导出您希望在Haskell中实现的实际功能
  3. 以下手册部分对此进行了描述:[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/

答案 1 :(得分:0)

这使得ghc静态编译(注意pthread在optl-static之前): ghc --make -static -optl-pthread -optl-static test.hs

编辑:但静态编译似乎有点冒险。大多数时候都存在一些错误。在我的x64 fedora上它根本不起作用。生成的二进制文件也很大,main = putStrLn "hello world"

为1.5M