我用 Haskell 编写了一些函数,我想将它们构建到一个 DLL 中,这样我就可以从我的 C++ 应用程序中调用它们。我过得很糟糕。 (似乎从 Haskell 调用 C DLL 更常见,也有更好的文档记录。)
我的 Haskell 安装是 MinGHC 7.10.1(32 位)。 C++项目使用Visual Studio 2010和Qt 5.4;我使用 qmake 从 .pro 文件生成 VS 项目文件。这是我正在做的:
- 使用 cabal-install 安装我的图书馆需要的包。 (这些在全局范围内安装,而不是在沙箱中。)
- 运行
ghc -no-hs-main -v SpectrumMath.hs > ghc_output 2>&1
将 GHC 的详细构建输出转储到文件中。 - 查看
ghc_output
文件并找到链接器命令(它是“*** Linker:”之后的行)。提取库目录(由-L
标志指示)和库名称(由-l
标志指示)。 将这些库添加到 Qt .pro 文件中,例如
LIBS += \ -Lsome_long_path_here \ -Lsome_other_long_path_here \ -lsome_library_name_here \ -lsome_other_library_name_here
运行
ghc --print-libdir
。将/include
附加到此路径的末尾并将其添加到 .pro 文件中:INCLUDEPATH += "C:/Program Files (x86)/MinGHC-7.10.1/ghc-7.10.1/lib/include"
运行 qmake 生成 Visual Studio 项目。
- 打开 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.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
,也应该可以使用.
关于visual-studio-2010 - 如何将 Haskell DLL 集成到 C++/Qt Windows 应用程序中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31438420/