将Haskell和C++进行接口连接

12

我想在C++程序中调用一些Haskell函数。

为了做到这一点,我已经按照 这些说明 并将其适应于我的代码和系统。

目前我所拥有的是:

  • Main.cpp
  • 共享头文件和cpp文件
  • makefile
  • cpp/
    • 一些cpp和头文件
  • haskell/
    • hello.hs

Makefile如下:

CPP_SOURCES = main.cpp textures.cpp cpp/game.cpp \
cpp/piece.cpp cpp/factories.cpp cpp/utils.cpp
HASKELL_SOURCES = haskell/hello.hs

all: main; ./main

main: $(CPP_SOURCES) HaskellPart.o; g++ \
    -lsfml-graphics \
    -lsfml-window \
    -lsfml-system \
    -I/usr/lib/ghc/include \
    -liconv \
    -I/usr/lib/ghc/ghc-8.0.1/include \
    -L/usr/lib/ghc/ghc-8.0.1 \
    -L/usr/lib/ghc/rts \
    -lHSrts \
    -L/usr/lib/ghc/base-4.9.0.0 \
    -lHSbase-4.9.0.0 \
    -L/usr/lib/ghc/ghc-prim-0.5.0.0 \
    -lHSghc-prim-0.5.0.0 \
    -L/usr/lib/ghc/integer-gmp-1.0.0.1 \
    -lHSinteger-gmp-1.0.0.1 \
    -lHSghc-prim-0.5.0.0 \
    -fno-stack-protector \
    -Wall \
    -o main $(CPP_SOURCES) haskell/hello.o

HaskellPart.o: $(HASKELL_SOURCES); ghc -fforce-recomp -fPIC $(HASKELL_SOURCES)

clean: ; rm -rf main && rm -rf haskell/*.o && \
rm -rf haskell/*.hi && rm -rf haskell/*_stub.h

我所做的是:

  1. 添加 -I/usr/lib/ghc/include 以便让 g++ 找到 HsFFI.h
  2. 更新库路径
  3. 在 ghc 参数中添加 -fPIC 以避免符号错误。

但是,最终输出如下:

    $ make
ghc -fforce-recomp -fPIC haskell/hello.hs
[1 of 1] Compiling Hello            ( haskell/hello.hs, haskell/hello.o )
g++ \
-lsfml-graphics \
-lsfml-window \
-lsfml-system \
-I/usr/lib/ghc/include \
 -liconv \
-L/usr/lib/ghc/rts \
-lHSrts \
-L/usr/lib/ghc/base-4.9.0.0 \
-lHSbase-4.9.0.0 \
-L/usr/lib/ghc/ghc-prim-0.5.0.0 \
-lHSghc-prim-0.5.0.0 \
-L/usr/lib/ghc/integer-gmp-1.0.0.1 \
-lHSinteger-gmp-1.0.0.1 \
-lHSghc-prim-0.5.0.0 \
 -fno-stack-protector \
 -Wall \
 -o main main.cpp textures.cpp cpp/game.cpp cpp/piece.cpp cpp/factories.cpp cpp/utils.cpp haskell/hello.o
/tmp/ccHPRuDY.o: In function `main':
main.cpp:(.text+0x358): undefined reference to `hs_init'
main.cpp:(.text+0x375): undefined reference to `hs_exit'
haskell/hello.o: In function `sRs_info':
/tmp/ghc9fcb_0/ghc_7.o:(.text+0x2e): undefined reference to `newCAF'
/tmp/ghc9fcb_0/ghc_7.o:(.text+0x3e): undefined reference to `stg_bh_upd_frame_info'
/tmp/ghc9fcb_0/ghc_7.o:(.text+0x54): undefined reference to `ghczmprim_GHCziCString_unpackCStringzh_closure'
/tmp/ghc9fcb_0/ghc_7.o:(.text+0x5d): undefined reference to `stg_ap_n_fast'
/tmp/ghc9fcb_0/ghc_7.o:(.text+0x96): undefined reference to `newCAF'
/tmp/ghc9fcb_0/ghc_7.o:(.text+0xa6): undefined reference to `stg_bh_upd_frame_info'
/tmp/ghc9fcb_0/ghc_7.o:(.text+0xbc): undefined reference to `base_SystemziIO_putStrLn_closure'
/tmp/ghc9fcb_0/ghc_7.o:(.text+0xc5): undefined reference to `stg_ap_p_fast'
haskell/hello.o: In function `helloFromHaskell':
(.text+0xd8): undefined reference to `rts_lock'
haskell/hello.o: In function `helloFromHaskell':
(.text+0xee): undefined reference to `base_GHCziTopHandler_runIO_closure'
haskell/hello.o: In function `helloFromHaskell':
(.text+0xf9): undefined reference to `rts_apply'
haskell/hello.o: In function `helloFromHaskell':
(.text+0x10f): undefined reference to `rts_evalIO'
haskell/hello.o: In function `helloFromHaskell':
(.text+0x122): undefined reference to `rts_checkSchedStatus'
haskell/hello.o: In function `helloFromHaskell':
(.text+0x12e): undefined reference to `rts_unlock'
haskell/hello.o: In function `stginit_export_Hello_zdfstableZZC0ZZCmainZZCHelloZZChelloFromHaskell':
ghc_3.c:(.text+0x144): undefined reference to `foreignExportStablePtr'
haskell/hello.o: In function `sRs_closure':
/tmp/ghc9fcb_0/ghc_7.o:(.data+0x40): undefined reference to `stg_IND_STATIC_info'
haskell/hello.o: In function `rHM_closure':
/tmp/ghc9fcb_0/ghc_7.o:(.data+0x60): undefined reference to `ghczmprim_GHCziTypes_TrNameS_static_info'
haskell/hello.o: In function `rI0_closure':
/tmp/ghc9fcb_0/ghc_7.o:(.data+0x70): undefined reference to `ghczmprim_GHCziTypes_TrNameS_static_info'
/tmp/ghc9fcb_0/ghc_7.o:(.data+0x80): undefined reference to `ghczmprim_GHCziTypes_Module_static_info'
haskell/hello.o: In function `SRD_srt':
/tmp/ghc9fcb_0/ghc_7.o:(.data.rel.ro+0x0): undefined reference to `ghczmprim_GHCziCString_unpackCStringzh_closure'
/tmp/ghc9fcb_0/ghc_7.o:(.data.rel.ro+0x8): undefined reference to `base_SystemziIO_putStrLn_closure'
collect2: error: ld returned 1 exit status
makefile:17: recipe for target 'main' failed
make: *** [main] Error 1

我做错了什么?

谢谢!

编辑:

根据n.m的答案,我改变了g++参数的顺序。下面是新的makefile:

CPP_SOURCES = main.cpp textures.cpp cpp/game.cpp cpp/piece.cpp cpp/factories.cpp cpp/utils.cpp
HASKELL_SOURCES = haskell/hello.hs
CFLAGS = -Wall -g -fno-stack-protector

all: main; ./main

main: $(CPP_SOURCES) HaskellPart.o; g++ \
    $(CFLAGS) -o main $(CPP_SOURCES) haskell/hello.o \
    -lsfml-graphics \
    -lsfml-window \
    -lsfml-system \
    -I/usr/lib/ghc/include \
    -liconv \
    -I/usr/lib/ghc/ghc-8.0.1/include \
    -L/usr/lib/ghc/ghc-8.0.1 \
    -L/usr/lib/ghc/base-4.9.0.0 \
    -lHSbase-4.9.0.0 \
    -L/usr/lib/ghc/ghc-prim-0.5.0.0 \
    -lHSghc-prim-0.5.0.0 \
    -L/usr/lib/ghc/integer-gmp-1.0.0.1 \
    -lHSinteger-gmp-1.0.0.1 \
    -lHSghc-prim-0.5.0.0 \
    -L/usr/lib/ghc/rts \
    -lHSrts \

HaskellPart.o: $(HASKELL_SOURCES); ghc -fforce-recomp -fPIC $(HASKELL_SOURCES)

clean: ; rm -rf main && rm -rf haskell/*.o && rm -rf haskell/*.hi && rm -rf haskell/*_stub.h

但是它引发了另一个错误:

/usr/bin/ld: /usr/lib/ghc/rts/libHSrts.a(Itimer.o): undefined reference to symbol 'timer_settime@@GLIBC_2.3.3'

根据这个线程,我添加了-lrt,但是得到了以下错误:

/usr/bin/ld: /usr/lib/ghc/rts/libHSrts.a(Linker.o): undefined reference to symbol 'dlsym@@GLIBC_2.2.5'

所以,根据这个线程,我添加了-ldl,现在出现了大麻烦……

编辑: 悬赏

各位,我正在花费我较少的声望中的大部分来添加一个悬赏,因为我无法使此工作,并且真的需要它。

这是为学校相关项目,但我必须明确指出这并不是作弊,因为题目只说:“用C++编写一个大程序,并使用Haskell编写同样的程序”。

为两个程序制作共同的图形界面是我的决定,超出了课程范围。

除此之外,我认为互联网上缺乏有关此主题的文档,我的老师告诉我他从未成功过,因此有关g++与Haskell Foreign Export配置的构建答案将非常有用。

感谢您的帮助。


完成。我已经编辑了我的帖子,并提供了新的输出,但它看起来完全一样。谢谢。 - Maxime VAST
@alec 使用C语言会引入第三种语言,而我不被允许这样做。此外,必须能够通过将Haskell和C++编译在一起来实现我想要的功能。我无法相信这还没有被完成。我相信在这个帖子上有一个构建好的答案会帮助其他人。 - Maxime VAST
@MaximeVAST 这种事情往往会变得棘手(来源:我几个月前使用 Haskell/Java 做过这件事)。也许您愿意重新表述您的问题?目前,您没有真正拥有一个 MVCE。也许最好包含一个最小的 Haskell/C++ 程序,它不能工作 - 这样我们就有了“某些东西”可供尝试修复。目前,您是唯一可以迭代的人。 - Alec
@alec。明白了!这是MVCE问题:[链接](https://dev59.com/waDia4cB1Zd3GeqPD3Nv) - Maxime VAST
1
这是我在你的第二个问题的答案链接:https://dev59.com/waDia4cB1Zd3GeqPD3Nv#43107962 - James Burton
显示剩余3条评论
1个回答

4

我刚才尝试在你另一个版本的问题中链接到我的答案,但它决定自动将其变成评论...这不是特别有用,因为将来找到这个线程的人可能会将其视为未回答的,所以我会贴上完整的答案。

我不确定那是否实际在你的文件中,还是只是在你提出问题的版本中,但“// hello.hs”不会编译。在Haskell中,注释是--而不是//。

无论如何,让我们进入有趣的部分...

首先,您需要将HsFFI.h头文件导入到C++代码中。

#include <iostream>
#include "Hello_stub.h"
#include <HsFFI.h>

然后使用ghc在编译这些文件之后进行链接。打开命令提示符/终端并导航到包含C++和Haskell文件的目录。然后运行以下命令:

ghc -c -XForeignFunctionInterface -O hello.hs
g++ -c -O main.cpp -I "C:\Program Files\Haskell Platform\7.10.3\lib\include"                         
ghc -no-hs-main hello.o main.o -lstdc++

第二个命令中的文件路径是指包含HsFFI.h文件的目录。
运行main函数,输出如下:
Hello from C++
Hello from Haskell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接