如何将Haskell编译成静态库?
嘿, 我正在学习 Haskell,我有兴趣使用它来制作静态库,以便在 Python 和 C 中使用。经过一番谷歌搜索后,我发现如何让 GHC 输出共享对象,但它动态地依赖于 GHC 的库。 在 GHC 中编译生成的 ELF 是动态依赖的,仅依赖于 C 库,并且大小略低于 1 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
当谷歌搜索时,我发现了有关整个问题的一些信息 - 它可能来自 GHC 以特定方式编译的事实(动态/静态? ),因此静态链接是不可能的。如果这是真的,ELF 二进制文件怎么可能是静态链接的?
不管怎样,我希望有人能对此有所了解,因为大量的谷歌搜索给我留下了比开始时更多的问题。
非常感谢。
Hey,
I'm learning Haskell and I'm interested in using it to make static libraries for using in Python and probably C. After some googling I found out how to get GHC to output a shared object, but it dynamically depends on GHC`s libraries.
The resulting ELF from compiling in GHC is dynamically dependand only on C libs and it's a bit under a MB in size - it has been statically linked with GHC`s libs. How and if can this be achieved for shared objects?
Example of current state:
$ 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)
If I try to compile it with(without '-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
When googling I found something about this whole issue - that it may come from the fact that GHC is compiled in a specific way(dynamic/static?) and so static linking is not possible. If this is true how is it possible that the ELF binary is statically linked?
Anyway, I am hoping someone can shed some light on this since a huge amount of googling left me with more questions than I started with.
Huge thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
规范的方法是这样的:
手册的以下部分对此进行了描述: [1] [2]
另一方面,您可以尝试这篇博文中描述的技术(顺便说一下,这是我的):
http://mostlycode.wordpress.com/2010/01/03/shared-haskell-so-library-with-ghc-6-10-4- and-cabal/
它归结为创建一个小的 C 文件,该文件在加载库后立即自动调用。
它应该链接在一起进入库。
编辑:描述此技术的原始博客文章是这样的: http:// /weblog.haskell.cz/pivnik/building-a-shared-library-in-haskell/
The canonical way of is this:
The following sections of manual describe this: [1] [2]
On the other way, you can try technique described in this blog post (which mine, by the way):
http://mostlycode.wordpress.com/2010/01/03/shared-haskell-so-library-with-ghc-6-10-4-and-cabal/
It boils down to creating a small C file which is called automatically right after a library is loaded.
It should be linked together into the library.
Edit: Original blog post describing this technique is this: 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 上它根本不起作用。生成的二进制文件也相当大,
main = putStrLn "hello world" 为 1.5M
This makes ghc compile statically (note that the pthread is before optl-static):
ghc --make -static -optl-pthread -optl-static test.hs
Edit: But the static compilation seems to be a bit risky. Most of the times there are some errors. And on my x64 fedora it doesn't work at all. The resulting binary is also quite large, 1.5M for
main = putStrLn "hello world"