2011-02-27 92 views
26

嘿, 我正在学习Haskell,我有兴趣使用它来制作静态库,以便在Python和C中使用。经过一些Google搜索后,我发现如何让GHC输出共享对象,但它动态地依赖于在GHC的图书馆。 在GHC中编译生成的ELF只能动态地依赖于C库,并且它的大小略低于MB - 它已经与GHC的libs静态链接。如何以及如果这可以实现共享对象?当前状态的如何将Haskell编译为静态库?

例子:

$ 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二进制文件如何可能静态链接?

无论如何,我希望有人能够说明这一点,因为大量的谷歌搜索给我留下了比我更多的问题。

非常感谢。

+0

你用什么系统?看来它是x86_64 Linux。 GHC版本也很重要,因为它可能实际上是一个已经修复的bug。动态链接在过去有一些缺陷,它可能是其中之一。 – Tener 2011-03-01 22:45:43

+0

@Tener | Glasgow Haskell编译器版本6.12.3,适用于Haskell 98,第2阶段由GHC版本6.12.1引导|也许我应该尝试GHC 7,看看它是否覆盖了这个问题。 – kuratkull 2011-03-02 23:09:11

+0

@Tener。我开始安装GHC7,但它仍然无法正常工作,虽然它给了我一些不同的错误。 = >>> ' - > ghc --make -shared -fPIC bwt.hs -o libbwt.so [1 of 1]编译Main(bwt.hs,bwt.o) 链接libbwt.so .. 。 的/ usr /斌/ LD:/usr/lib/ghc-7.0.2/base-4.3.1.0/libHSbase-4.3.1.0.a(Base__90.o):针对 “stg_upd_frame_info” 重定位R_X86_64_32S不能使用时制作一个共享对象;使用-fPIC重新编译 /usr/lib/ghc-7.0.2/base-4.3.1.0/libHSbase-4.3.1.0.a:无法读取符号:错误值 collect2:ld返回1退出状态# – kuratkull 2011-03-15 19:46:21

回答

4

的是这种情况的典型方式:

  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/

+3

谢谢,但这些方法都没有工作(同样的错误),它可能是由于这种(以您所提供的链接之一找到):“在大多数平台但将要求所有已建有-fPIC静态库,以便该代码适合包含到共享库中,而我们目前不这样做。“我可以假设我将不得不用手动重新编译GHC来解决我的问题 - 否则这是不可能的。我会将你的答案标记为正确的答案,因为在重新编译GHC之后,所有这些都应该工作。非常感谢 :) – kuratkull 2011-03-20 16:08:20

0

这使得GHC静态编译(注意并行线程是optl静态前): ghc --make -static -optl-pthread -optl-static test.hs

编辑:但静态编译似乎有点冒险。大多数时候都有一些错误。而在我的x64 fedora上它根本不起作用。形成的二分也是相当大的,1.5M的main = putStrLn "hello world"

+5

但是这使得可执行文件的静态,我想有静态库(*。所以/ * a)所示。我试图用 '-shared' 标志在那里,但我得到: 在/ usr/bin中/ LD:/usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/crtbeginT.o:搬迁R_X86_64_32在制作共享对象时不能使用'__DTOR_END__';与-fPIC /usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/crtbeginT.o重新编译:看不懂的符号:错误值。 好像做静态库可能完全不毕竟那么容易。或者我做错了什么? – kuratkull 2011-02-28 11:52:56