如何将Haskell DLL集成到C ++ / Qt Windows应用程序中?

时间:2015-07-15 18:35:33

标签: visual-studio-2010 haskell

我在Haskell中编写了一些函数,我想将它们构建成一个DLL,这样我就可以从我的C ++应用程序中调用它们了。我有一段可怕的时间。 (似乎从Haskell调用C DLL更常见,更好地记录。)

我的Haskell设置是MinGHC 7.10.1(32位)。 C ++项目使用Visual Studio 2010和Qt 5.4;我使用qmake从.pro文件生成VS项目文件。这就是我正在做的事情:

  1. 使用cabal-install安装我的库所需的软件包。 (这些是全局安装的,而不是安装在沙盒中。)
  2. 运行ghc -no-hs-main -v SpectrumMath.hs > ghc_output 2>&1将GHC的详细构建输出转储到文件中。
  3. 查看ghc_output文件并找到链接器命令(它是“*** Linker:”之后的行)。提取库目录(由-L标志指示)和库名称(由-l标志指示)。
  4. 将这些库添加到Qt .pro文件中,例如

    LIBS += \
        -Lsome_long_path_here \
        -Lsome_other_long_path_here \
        -lsome_library_name_here \
        -lsome_other_library_name_here
    
  5. 运行ghc --print-libdir。将/include附加到此路径的末尾并将其添加到.pro文件中:

    INCLUDEPATH += "C:/Program Files (x86)/MinGHC-7.10.1/ghc-7.10.1/lib/include"
    
  6. 运行qmake以生成Visual Studio项目。

  7. 打开VS项目。打开项目的属性并导航到Configuration Properties→Linker→Input并编辑Additional Dependencies字段。 Qmake帮助“修复”了库的名称,因此将“HS 某些 .lib”的每个实例替换为“libHS something .a”。同样,将“Cffi-6.lib”重命名为“libCffi-6.a”,将“HSrts.lib”重命名为“libHSrts.a”。
  8. 这个疯狂的过程来自维基上的this page。它假定C ++文件将#include "SpectrumMath_stub.h",这是GHC在步骤2中生成的文件。

    我在这一点上陷入困​​境,因为我不知道如何处理m库(来自-lm标志的那个)。 Visual Studio找不到“m.lib”,但如果我从列表中删除该库,我会收到许多“未解析的外部”消息,因此需要。如何告诉Visual Studio libm依赖?或者我应该完全遵循另一个过程吗?

1 个答案:

答案 0 :(得分:3)

我建议实际使用cabal-install(或stack)。如果您计划在没有LPGL兼容许可的情况下分发此DLL,您可能希望使用integer-simple而不是integer-gmp(默认值)使用GHC版本。

Haskell方

首先,熟悉this GHC tutorial

阅读完之后,您会发现某处需要StartEnd.c的副本。让我们说它在src\

所以这是你的MyLibrary.cabal文件:

...other cabal stuff...

library
  exposed-modules:     MyModule
  --other-modules:
  other-extensions:    ForeignFunctionInterface
  build-depends:       base
  hs-source-dirs:      src
  c-sources:           src/StartEnd.c  --tells cabal to rebuild if this changes
  default-language:    Haskell2010
  --default-extensions:

  -- Add whatever options you need, in addition to these:
  -- (In my experience, adding `-threaded` can make the DLL 
  --  behave better during debugging; but that's only a guess.)
  ghc-options:         -O1 -shared src/StartEnd.c

现在使用cabal build构建它(如果您使用stack build,则为stack。)

期待看到警告。 Cabal并不完全了解你的目标。

相对于您的阴谋项目,您会发现三个对您很重要的文件:

  • HSdll.dll
  • HSdll.dll.a(Windows通常会调用这些.lib个文件;如果您愿意,可以重命名该文件。
  • build\...\MyLibrary_stub.h

请注意,此DLL静态链接所有Haskell依赖项。因此,除了DLL之外,您无需告诉Visual Studio任何内容。

C ++方

  • 在C ++代码中,您需要包含上面生成的MyLibrary_stub.h文件。
  • 您还需要在某处包含HsStartHsEnd的原型:

    extern "C" { void HsStart(); void HsEnd(); }

  • _stub.h文件包含一些GHC标头,因此您需要在VS项目的“其他包含”中添加一个文件夹:<ghc-folder>\ghc-7.10.1\lib\include

    • 执行此操作的一个方法是运行where ghc,删除ghc.exe,然后将\..\lib\include附加到该结果中。

在您的C ++应用中,请务必在程序的开头和结尾调用HsStart()HsEnd()。我喜欢将它们封装在RAII结构中,所以我不能忘记做正确的事。

我的经历

我已尝试使用cabal-install 1.2 *版本和stack。我使用了GHC 7.8.4和7.10.1,每个都有32位和64位版本。

请注意,Cabal即将推出much better support for this

命名您的DLL

在Cabal获得更好的支持之前,我发现为您的DLL命名的唯一方法是将-o MyLibrary.dll添加到ghc-options。即使它有效,GHC会在你这样做时给你警告,表明它并不真正知道发生了什么。要提供帮助,您可以将StartEnd.c预先构建到StartEnd.o并将其链接起来。要使用的命令是这样的:

cabal exec -- ghc -optc-O -c src/StartEnd.c -o obj/StartEnd.o

现在,在ghc-options中,将src/StartEnd.c替换为obj/StartEnd.o

如果您使用cabal,则stack替换stack也应该有效。