在Mac上创建静态链接的Haskell库

时间:2015-08-23 05:10:07

标签: macos haskell static ghc ffi

我正在使用:Mac OS X 10.10,GHC 7.10.2(Haskell平台),Cabal 1.22

我正在尝试在Haskell中创建一个静态链接的库。目的是为库提供与C兼容的ABI,以便跨平台和跨语言使用。这个库的消费者都不希望在Haskell中实现,因此C兼容的ABI是至关重要的,因为易于分发生成的库。

我的问题是,FFI教程/示例中没有一个使用第三方模块,甚至几乎没有提到cabal。这些都是我的先决条件。当我按照一个简单的FFI教程它可以工作,但是一旦我加入第三方模块,它就失败了。

我创建了一个非常简单的示例,详细说明了我的问题:https://github.com/tomkludy/ffihell

如果使用cabal configure;cabal build构建库,您将在dist\build中找到一个名为libHSffihell-0.1.0.0-70CjWiqse6C2Al3vL5a4k7的库(后跟.a,_p.a和-ghc7.10.2)。 dylib)。

问题1:图书馆每次都被命名为不同的。每次构建库时,如何将库命名为库?

如果您通过修改build_c.sh指向正确的库名称来构建使用它的C程序(tryit.c),它可以工作:

> ghc tryit.c -Idist/build -Ldist/build -lHSffihell-0.1.0.0-70CjWiqse6C2Al3vL5a4k7 -no-hs-main -o tryit
> ./tryit
foo 4: 5

但是,如果你在Foo.hs中取消注释这些行,导致它引入Data.Text库:

{-# LANGUAGE ForeignFunctionInterface, OverloadedStrings #-}
module Foo where

import qualified Data.Text as T

foreign export ccall foo :: Int -> IO Int

foo :: Int -> IO Int
foo n = return $ n + 1

-- UNCOMMENTED BELOW HERE...
foreign export ccall bar :: Int -> IO ()
bar :: Int -> IO ()
bar n = putStrLn $ T.unpack $ T.concat $ ["." :: T.Text | _ <- [1..n]]

然后尝试构建......

> cabal build
(... no errors ...)
> ghc tryit.c -Idist/build -Ldist/build -lHSffihell-0.1.0.0-70CjWiqse6C2Al3vL5a4k7 -no-hs-main -o tryit
Undefined symbols for architecture x86_64:
  "_textzu1l1AN4I48k37RaQ6fm6CEh_DataziText_concat_closure", referenced from:
      _S45B_srt in libHSffihell-0.1.0.0-70CjWiqse6C2Al3vL5a4k7.a(Foo.o)
  "_textzu1l1AN4I48k37RaQ6fm6CEh_DataziText_concat_info", referenced from:
      _ffihezu70CjWiqse6C2Al3vL5a4k7_Foo_zdfstableZZC0ZZCffihezzu70CjWiqse6C2Al3vL5a4k7ZZCFooZZCbar2_info in libHSffihell-0.1.0.0-70CjWiqse6C2Al3vL5a4k7.a(Foo.o)
      _c4bD_info in libHSffihell-0.1.0.0-70CjWiqse6C2Al3vL5a4k7.a(Foo.o)
  "_textzu1l1AN4I48k37RaQ6fm6CEh_DataziTextziShow_unpackCStringzh_closure", referenced from:
      _S45B_srt in libHSffihell-0.1.0.0-70CjWiqse6C2Al3vL5a4k7.a(Foo.o)
  "_textzu1l1AN4I48k37RaQ6fm6CEh_DataziTextziShow_unpackCStringzh_info", referenced from:
      _ffihezu70CjWiqse6C2Al3vL5a4k7_Foo_zdfstableZZC0ZZCffihezzu70CjWiqse6C2Al3vL5a4k7ZZCFooZZCbar4_info in libHSffihell-0.1.0.0-70CjWiqse6C2Al3vL5a4k7.a(Foo.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

问题2:无法找到与第三方模块相关的符号

错误似乎与Data.Text导入的符号有关。

这个例子尽我所能,但是我的真实图书馆有大约50个第三方模块,随着我扩展所提供的功能,模块列表会随着时间的推移而改变。我需要访问一个静态链接的库,其中包含我自己的函数+所有依赖项,以便使用我的库的人不必不断更改他们的构建脚本/ makefile /等。

问题3:无法使用clang / gcc构建

我唯一可以获得&#34; tryit.c&#34;甚至在消费第三方之前,与我的程序链接的程序就是用GHC编译它。由于我的消费者不编程Haskell他们不会有GHC。是否有任何关于针对Haskell库编译程序的文档,而不是使用GHC进行编译?我找不到任何东西......只是文档声明它应该是可能的&#34;但没有任何细节。

感谢您的帮助!

更新 通过使用下面建议的ld -r,结合-force_load (我的库)-reexport_library (每个模块库),我能够更进一步,加上许多GHC框架库)。您可以在同一个git仓库中看到新代码。 build_lib.sh构建Haskell库,build_c.sh然后使用该库构建消耗它的C源可执行文件。

我仍然无法解决问题#1或问题#3,我也在努力寻找一种方法来自动获取所有正确的模块库依赖项。如果我得到一个完整的解决方案,我会更新。

1 个答案:

答案 0 :(得分:1)

简而言之,使用ghc -v构建一个使用您的库的应用程序,并在链接步骤中查看它如何调用gcc,然后使用ld -r。您可能还需要调整link命令以静态链接某些C依赖项(如GMP),具体取决于您的需求。