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

标签 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 项目。打开项目的属性并导航到配置属性→链接器→输入并编辑附加依赖项字段。 Qmake 帮助“修复”了库的名称,因此将“HSsomething.lib”的每个实例替换为“libHSsomething.a”。同样,将“Cffi-6.lib”重命名为“libCffi-6.a”,将“HSrts.lib”重命名为“libHSrts.a”。

这个疯狂的过程来自this page在维基上。它假定 C++ 文件将 #include "SpectrumMath_stub.h",这是一个由 GHC 在步骤 2 中生成的文件。

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

最佳答案

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


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 不太清楚你在做什么。

您会发现三个与您的 cabal 项目相关的重要文件:

  • HSdll.dll
  • HSdll.dll.a (Windows 正常调用这些 .lib 文件;您可以根据需要重命名)
  • build\...\MyLibrary_stub.h

请注意,此 DLL 静态链接所有 Haskell 依赖项。因此,除了您的 DLL 之外,您不需要告诉 Visual Studio 任何其他信息。


C++ 方面

  • 在您的 C++ 代码中,您需要包含 MyLibrary_stub.h上面生成的文件。
  • 您还需要包括 HsStart 的原型(prototype)和 HsEnd某处:

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

  • _stub.h文件包含一些 GHC header ,因此您需要在 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.dllghc-options .即使它有效,GHC 也会在您执行此操作时向您发出警告,表明它并不真正知道发生了什么。为了解决这个问题,您可以预构建 StartEnd.c进入StartEnd.o并将其链接起来。使用的命令是这样的:

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

现在,在 ghc-options , 替换 src/StartEnd.cobj/StartEnd.o .

正在替换 cabalstack如果您使用 stack,也应该可以使用.

关于visual-studio-2010 - 如何将 Haskell DLL 集成到 C++/Qt Windows 应用程序中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31438420/

相关文章:

visual-studio-2010 - 如何在 Visual Studio 中设置 CUDA 标志

c# - 从 Internet/Intranet 访问 SQL Server

asp.net - 由于端口小于 1024,无法打开包含网站的解决方案?

c++ - 我可以在内部函数中禁用宏吗?

haskell - 使用 Maybe 和 Writer 过滤列表并跟踪过滤器命中

haskell - ghci tab-completion in haskell-mode

c# - 单击任何按钮的事件(C# windows 窗体)

haskell - 我可以在 Free Monad 的 Show 实例中消除 UndecidableInstances 的使用吗?

list - haskell [[Char]] 到 [[Int]]

haskell - 多次调用 applyTwice 时无法理解结果