Windows 上带有 FFI 的 GHC -staticlib 尝试链接可执行文件,但缺少“外部导出”符号

问题描述 投票:0回答:1

我有以下 Haskell 源代码,我想从中编译一个可以链接到 C 程序的静态库:

{-# LANGUAGE ForeignFunctionInterface #-}

module Lib where

printHello :: IO ()
printHello = putStrLn "Hello world"
foreign export ccall printHello :: IO ()

我使用的命令是:

ghc -staticlib Lib.hs

但这会生成一个

main.exe
文件而不是
liba.a
(正如我根据 文档 所期望的那样)。

这不起作用;当我尝试将它与 C 源代码(使用 GHC 或普通 GCC)链接时,我得到未定义的引用。奇怪的是,它找到了 FFI 中预定义的函数(如

hs_init
hs_exit
);只有我导出的 (
printHello
) 丢失了。

我尝试使用

nm
检查文件,结果得到
Lib.o: file format not recognized
(并且没有
printHello
符号)。

更有趣的是,如果我直接针对

Lib.o
文件 main.exe
 文件(使用 GHC)进行编译,它似乎可以工作。所以 
Lib.o
 本身可能没有损坏。我也尝试用 
ar
 交换对象,但没有帮助。

目标是生成一个静态库(带有

.a

.lib
 扩展名的库),我可以使用 GHC 或 GCC 链接到 C 程序。为此,可能需要查看使用 
nm
 导出的符号。

我已经阅读了标志、FFI、ar、nm、ld 的文档,但我仍然不知道如何处理这个问题。

如果这有帮助,我正在 Windows 10 1903 上使用 GHC 9.2.8。

提前非常感谢您:)

haskell linker ghc static-linking haskell-ffi
1个回答
0
投票
哈;完成了......我仍然不太明白,但我认为

Lib.o

本身就是一个库,而不是一个简单的目标文件。

所以,我用

ghc -staticlib -o liba.a Lib.hs

 创建了存档。那么,在
ar
中,正确的命令是:

create libb.a addlib liba.a addlib Lib.o save end
一个虚拟的 C 程序,简单地调用 

printHello

:

void hs_init(int* argc, char*** argv); void hs_exit(void); void printHello(void); int main(int argc, char** argv) { hs_init(&argc, &argv); printHello(); hs_exit(); return 0; }
尽管如此,出于某种原因,必须为 GCC 指定系统库。但在那之后,它起作用了:

gcc main.c libb.a -lpthread -lws2_32 -lntdll -lDbghelp -lOle32 -lRpcrt4 -lucrt -lgdi32 -lwinmm
因此,整个批处理脚本会成功:

ghc -staticlib -o liba.a Lib.hs (echo "create libb.a" && echo "addlib liba.a" && echo "addlib Lib.o" && echo save && echo end) | ar -M gcc main.c libb.a -lpthread -lws2_32 -lntdll -lDbghelp -lOle32 -lRpcrt4 -lucrt -lgdi32 -lwinmm
    
© www.soinside.com 2019 - 2024. All rights reserved.