【发布时间】:2015-08-23 05:10:06
【问题描述】:
我正在使用:Mac OS X 10.10、GHC 7.10.2(Haskell 平台)、Cabal 1.22
我正在尝试在 Haskell 中创建一个静态链接库。目的是提供一个具有 C 兼容 ABI 的库,以供跨平台和跨语言使用。该库的所有使用者都不会在 Haskell 中实现,因此与 C 兼容的 ABI 至关重要,生成的库易于分发也是如此。
我的问题是,FFI 教程/示例都没有使用 3rd 方模块,甚至几乎没有提到 cabal。这两个都是我的先决条件。当我按照一个简单的 FFI 教程进行操作时,它可以工作,但是一旦我放入一个 3rd 方模块,它对我来说就失败了。
我创建了一个非常简单的示例来详细说明我的问题: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:库的名称每次都不同。如何让 cabal 每次构建时都将库命名为相同?
如果您随后通过修改 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:找不到与 3rd 方模块相关的符号
错误似乎与 Data.Text 导入的符号有关。
这个例子很简单,但我真正的库有大约 50 个 3rd 方模块,随着我扩展提供的功能,模块列表会随着时间而改变。我需要找到一个包含我自己的函数 + 所有依赖项的静态链接库,这样使用我的库的人就不必不断更改他们的构建脚本/makefile/等。
问题 3:无法使用 clang/gcc 构建
我可以让“tryit.c”程序与我的程序链接的唯一方法,甚至在使用第 3 方之前,就是用 GHC 编译它。由于我的消费者没有编程 Haskell,他们不会有 GHC。是否有关于针对 Haskell 库编译程序的文档,而不是使用 GHC 进行编译?我找不到任何东西......只是文档说明它“应该是可能的”但没有任何细节。
感谢您的帮助!
更新
通过使用ld -r,如下所示,结合-force_load(我的库) 和-reexport_library(每个模块库,以及许多 GHC框架库)。你可以在同一个 git repo 中看到新代码。 build_lib.sh 构建 Haskell 库,然后build_c.sh 使用该库构建使用它的 C 源可执行文件。
我仍然无法解决问题 #1 或问题 #3,而且我还在努力寻找一种方法来自动获取所有正确的模块库依赖项。如果我得到一个完整的解决方案,我会更新。
【问题讨论】:
标签: macos haskell static ghc ffi