我熟悉从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.h
、Safe.o
和Safe.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.o
和test.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运行时。