【问题标题】:How to compile Haskell to a static library?如何将 Haskell 编译为静态库?
【发布时间】:2011-07-05 02:37:16
【问题描述】:

嘿, 我正在学习 Haskell,我有兴趣使用它来制作用于 Python 和 C 的静态库。经过一番谷歌搜索后,我发现了如何让 GHC 输出共享对象,但它动态地取决于 GHC 的库. 在 GHC 中编译产生的 ELF 是动态依赖的,仅依赖于 C 库,并且它的大小略低于 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 二进制文件怎么可能是静态链接的?

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

非常感谢。

【问题讨论】:

  • 你用什么系统?它似乎是 x86_64 Linux。 GHC 版本也很重要,因为它实际上可能是一个已经修复的错误。动态链接过去曾有过一些错误,它可能就是其中之一。
  • @Tener | Glasgow Haskell 编译器,版本 6.12.3,用于 Haskell 98,阶段 2,由 GHC 版本 6.12.1 引导 |也许我应该试试 GHC 7 看看它是否解决了这个问题。
  • @Tener。我开始安装 GHC7,但它仍然无法正常工作,尽管它给了我一些不同的错误。 =>>> --> ghc --make -shared -fPIC bwt.hs -o libbwt.so [1 of 1] Compiling Main ( bwt.hs, bwt.o ) Linking libbwt.so ... /usr/bin/ld: /usr/lib/ghc-7.0.2/base-4.3.1.0/libHSbase-4.3.1.0.a(Base__90.o): relocation R_X86_64_32S against "stg_upd_frame_info" can not be used when making a shared object; recompile with -fPIC /usr/lib/ghc-7.0.2/base-4.3.1.0/libHSbase-4.3.1.0.a: could not read symbols: Bad value collect2: ld returned 1 exit status
  • @kuratkull 没有关于这个问题的消息?我也有同样的愿望。

标签: haskell static-libraries static-linking ghc


【解决方案1】:

规范的方式是这样的:

  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/

【讨论】:

  • 谢谢,但这些方法都不起作用(相同的错误),这可能是由于这个(在您提供的链接之一中找到):“然而,在大多数平台上,这需要所有静态库已使用 -fPIC 构建,因此代码适合包含到共享库中,我们目前不这样做。”我可以假设我必须手动使用 -fPIC 重新编译 GHC 来解决我的问题 - 否则这是不可能的。我会将您的答案标记为正确答案,因为所有这些应该在重新编译 GHC 后工作。非常感谢:)
【解决方案2】:

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

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

【讨论】:

  • 但这使得可执行文件是静态的,我想要静态库(.so/.a)。我尝试在那里使用'-shared'标志,但我得到:/usr/bin/ld: /usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/crtbeginT.o: relocation R_X86_64_32 反对`制作共享对象时不能使用__DTOR_END__';使用 -fPIC /usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/crtbeginT.o 重新编译:无法读取符号:值错误。似乎制作静态库可能并不那么容易。还是我做错了什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-06
  • 2015-12-01
  • 2012-05-29
  • 2022-08-03
  • 2015-03-06
  • 1970-01-01
相关资源
最近更新 更多