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

Tom*_*udy 5 macos static haskell ffi ghc

我正在使用:Mac OS X 10.10,GHC 7.10.2(Haskell Platform),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
Run Code Online (Sandbox Code Playgroud)

但是,如果您在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]]
Run Code Online (Sandbox Code Playgroud)

然后尝试建立...

> 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)
Run Code Online (Sandbox Code Playgroud)

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

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

这个示例非常简单,但是我的真实库中有大约50个第三方模块,随着我扩展提供的功能,模块列表将随着时间而变化。我需要进入一个包含我自己的函数和所有依赖项的静态链接库,以便使用我的库的人们不必继续更改其构建脚本/ makefiles / etc。

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

我可以使“ tryit.c”程序与我的程序完全链接的唯一方法,甚至在使用第3方之前,也就是使用GHC对其进行编译。由于我的消费者未在编程Haskell,因此他们将没有GHC。是否有关于针对Haskell库编译程序的文档,而不是使用GHC进行编译?我什么也找不到...只是文档指出“应该”,但没有任何细节。

谢谢你的帮助!

通过将ld -r以下建议与-force_load(我的库)-reexport_library(每个模块库,再加上许多GHC框架库)结合使用,Update I可以得到更进一步的信息。您可以在同一git repo上看到新代码。该build_lib.sh版本将构建Haskell库,build_c.sh然后使用该库来构建使用它的C源可执行文件。

我仍然无法解决问题1或问题3,并且我也在努力寻找一种自动选择所有正确的模块库依赖项的方法。如果有完整的解决方案,我将进行更新。

Rei*_*ton 1

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