创建并链接一个带有Haskell外部函数导出且C中没有主函数的.o文件



我熟悉从C调用Haskell函数的方法,如下所定义:

https://wiki.haskell.org/Calling_Haskell_from_C

但是,我想做的不是创建一个可执行文件,而是创建一个稍后将与其他.o文件链接的.o。我的场景是这样的:

安全.hs

{-# LANGUAGE ForeignFunctionInterface #-}
module Safe where
import Foreign.C.Types
fibonacci :: Int -> Int
fibonacci n = fibs !! n
where fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
fibonacci_hs :: CInt -> CInt
fibonacci_hs = fromIntegral . fibonacci . fromIntegral
foreign export ccall fibonacci_hs :: CInt -> CInt

但C文件不同,没有main功能

测试.c

#include <HsFFI.h>
#ifdef __GLASGOW_HASKELL__
#include "Safe_stub.h"
#endif
int foo()
{
int i;
// some dummy values for argc and argv
hs_init(&argc, &argv);
i = fibonacci_hs(42);
hs_exit();
return i;
}

现在,为了将它们链接到一个.o文件中,我尝试了这样的方法:

ghc -fPIE -c -O Safe.hs

发出Safe_stub.hSafe.oSafe.hi文件。

接下来,我将test.c文件编译为对象文件

ghc --make -fPIE -no-hs-main -optc-O -c test.c -o test.o

给了我要查找的test.o对象文件。

现在,我尝试链接生成的两个对象文件,并使用ghc的链接器(内部使用gcc(:

ghc -no-hs-main -optc-nostartfiles -optc-static-pie test.o Safe.o -o result.o

这是我得到的

/usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/crt1.o:function _start: error: undefined reference to 'main'
collect2: error: ld returned 1 exit status
`x86_64-linux-gnu-gcc' failed in phase `Linker'. (Exit code: 1)

因此,对象文件似乎在某个地方引用了main。这是传递一些旗帜的问题吗?或者我做错了什么?提前感谢!

编辑

建议使用普通ld -r来链接对象文件。这种方法的问题是,如果使用普通的ld,它将不会在Haskell运行时中链接,从而使对象文件真正有用,并可由另一个C程序作为库调用。

如果从我的帖子中不清楚的话,我想创建一个.o文件,它可以用作调用Haskell代码的C库。

通常使用链接器将多个对象文件合并为一个可执行文件,该文件自然必须有一个main作为其入口点。显然,使用ld -r可以将多个对象文件合并为一个对象文件。GHC有这样的行为标志吗?也许吧,但我不能马上找到它。

但是,如果您只是要使用GHC来调用链接器,为什么不自己调用链接器呢?

ld -r test.o Safe.o -o result.o

这是我在多次使用各种标志后对问题的解决方案

ghc -c -O Safe.hs
ghc -c -no-hs-main -optc-O test.c

我不知道--make标志添加了什么。现在假设您分发了由上面生成的Safe.otest.o。用一个实际上有main方法的C函数编译它,比如:

testfoo.c

extern int foo();
int main(){
int k = foo();
return k;
}

你会这样做:

ghc -no-hs-main testfoo.c test.o Safe.o

生成的可执行文件当然会链接Haskell运行时。

最新更新