如何编译导出符号的Haskell Mach-O可执行文件?

时间:2019-05-25 13:59:06

标签: macos haskell ghc ffi

如何在成功foreign export成功运行的macOS 10.14.5上使用GHC> = 8.2.1(最好在8.6。*上)编译Haskell 可执行文件(不是库) (即在二进制文件中将其公开为公共符号)?这在GHC 8.0.2中有效,但在更高版本中无效。

我已经在ghc 8.0.2(通过堆栈),8.2.2(通过nix和堆栈),8.4.4(通过nix和堆栈)和8.6.4(通过nix和堆栈)上进行了尝试)。仅8.0.2有效。我知道8.2引入了此更改:GHC will now use ld.gold or ld.lld instead of the system’s default ld , if available.但我不清楚8.0.2是否会首先使用其他“系统默认” ld(darwin ld与llvm lld相对?)。 。我知道ghc的-pgml [ld-program-here]选项可用于设置链接器,但我无法将其手动设置为已成功编译并链接任何东西以进行进一步测试的任何东西。

我有这个文件Main.hs

module Main where

import Foreign.C

foreign export ccall "my_square" my_square :: CInt -> CInt

my_square :: CInt -> CInt
my_square x = x * x

main :: IO ()
main = putStrLn "FFI Test"

使用ghc 8.0.2:

> rm Main.hi Main.o && ghc-8.0.2 Main.hs && nm -g Main | grep my_square
[1 of 1] Compiling Main             ( Main.hs, Main.o )
[some apparently unrelated clang warnings]
Linking Main ...
[further clang warnings]
2544:0000000100001260 T _my_square

使用ghc 8.6.4时,似乎未导出该符号,因此将来尝试用该符号链接另一个程序都会失败。

> rm Main.hi Main.o && ghc-8.6.4 Main.hs && nm -g Main | grep my_square
[1 of 1] Compiling Main             ( Main.hs, Main.o )
Linking Main ...

1 个答案:

答案 0 :(得分:1)

按照我在评论中所说的,您测试的GHC版本均未从_my_square导出Main。相反,它们从_my_square导出Main.o(这就是为什么您可以使用ghc来编译和链接使用.c的{​​{1}}文件的原因)。当my_square链接到最终的Main.o可执行文件时,GHC都不告诉链接器导出Main。 GHC 8.6.4(我认为,从8.2开始)告诉链接器剥离未使用的,未导出的符号,因此_my_square消失了。 GHC 8.0.2不会这样做,完全是偶然地将_my_square保留在_my_sqaure可执行文件中。

您可以告诉GHC告诉链接器保留该符号。为此的链接器选项为Main。我的GHC实际上是通过-exported_symbol <symbol>调用链接程序的,所以我必须用gcc包裹这两个参数。无论出于何种原因,将该选项传递给实际编译-Wl的GHC都会导致错误;您必须使用一个简单的GHC调用进行Main.hs,然后再次调用GHC将其链接到Main.o,这次是使用链接器选项。也许这是我的系统特有的-您可以尝试寻找更好的方法。

Main

我仍然建议您提交GHC问题,以简化此过程。