如何编译导出符号的 Haskell Mach-O 可执行文件?
How do I compile a Haskell Mach-O executable that exports a symbol?
如何在 macOS 10.14.5 上使用 GHC >=8.2.1(最好是 8.6.*)编译 Haskell 可执行文件(不是库)成功地 foreign export
是一个函数(即将它公开为二进制文件中的 public 符号)?这在 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 是否会首先使用不同的 'system default' ld(darwin 的 ld 而不是 llvm 的 lld? ).我知道 ghc 的 -pgml [ld-program-here]
选项可以设置 linker 但我无法手动将其设置为已成功编译的任何内容和 linked 任何内容以进一步测试。
我有这个文件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 中,该符号似乎没有被导出,因此以后尝试 link 使用该符号的另一个程序失败。
> 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 ...
与我在评论中所说的不同,您测试的 GHC 版本实际上都没有从 Main
导出 _my_square
。相反,他们从 Main.o
导出 _my_square
(这就是为什么您可以使用 ghc
编译和 link 使用 my_square
的 .c
文件的原因) .当 Main.o
被 link 编辑到最终的 Main
可执行文件中时,GHC 都不会告诉 linker 导出 _my_square
。 GHC 8.6.4(我认为自 8.2 起)告诉 linker 去除未使用的、未导出的符号,因此 _my_square
消失了。 GHC 8.0.2 没有,将 _my_sqaure
留在 Main
可执行文件中纯属偶然。
您可以告诉 GHC 告诉 linker 保留符号。 linker 选项是 -exported_symbol <symbol>
。我的 GHC 实际上通过 gcc
调用 linker,所以我必须用 -Wl
包装这两个参数。无论出于何种原因,将该选项传递给实际编译 Main.hs
的 GHC 都会导致错误;您必须通过一次简单的 GHC 调用来创建 Main.o
,然后再次调用 GHC 将其 link 转换为 Main
,这次使用 linker 选项。也许这是我的系统特有的——你可以尝试找到更好的方法。
$ ghc -c Main.hs
# Makes Main.hi Main.o Main_stub.h
$ ghc -optl-Wl,-exported_symbol -optl-Wl,_my_square Main.o -o Main
# Makes Main
$ objdump -t Main | grep _my_square
0000000100000dc0 g F __TEXT,__text _my_square
我仍然建议提交 GHC 问题以简化此操作。
如何在 macOS 10.14.5 上使用 GHC >=8.2.1(最好是 8.6.*)编译 Haskell 可执行文件(不是库)成功地 foreign export
是一个函数(即将它公开为二进制文件中的 public 符号)?这在 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 是否会首先使用不同的 'system default' ld(darwin 的 ld 而不是 llvm 的 lld? ).我知道 ghc 的 -pgml [ld-program-here]
选项可以设置 linker 但我无法手动将其设置为已成功编译的任何内容和 linked 任何内容以进一步测试。
我有这个文件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 中,该符号似乎没有被导出,因此以后尝试 link 使用该符号的另一个程序失败。
> 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 ...
与我在评论中所说的不同,您测试的 GHC 版本实际上都没有从 Main
导出 _my_square
。相反,他们从 Main.o
导出 _my_square
(这就是为什么您可以使用 ghc
编译和 link 使用 my_square
的 .c
文件的原因) .当 Main.o
被 link 编辑到最终的 Main
可执行文件中时,GHC 都不会告诉 linker 导出 _my_square
。 GHC 8.6.4(我认为自 8.2 起)告诉 linker 去除未使用的、未导出的符号,因此 _my_square
消失了。 GHC 8.0.2 没有,将 _my_sqaure
留在 Main
可执行文件中纯属偶然。
您可以告诉 GHC 告诉 linker 保留符号。 linker 选项是 -exported_symbol <symbol>
。我的 GHC 实际上通过 gcc
调用 linker,所以我必须用 -Wl
包装这两个参数。无论出于何种原因,将该选项传递给实际编译 Main.hs
的 GHC 都会导致错误;您必须通过一次简单的 GHC 调用来创建 Main.o
,然后再次调用 GHC 将其 link 转换为 Main
,这次使用 linker 选项。也许这是我的系统特有的——你可以尝试找到更好的方法。
$ ghc -c Main.hs
# Makes Main.hi Main.o Main_stub.h
$ ghc -optl-Wl,-exported_symbol -optl-Wl,_my_square Main.o -o Main
# Makes Main
$ objdump -t Main | grep _my_square
0000000100000dc0 g F __TEXT,__text _my_square
我仍然建议提交 GHC 问题以简化此操作。