设置:我有一个Haskell库HLib
,它可以调用C / C ++后端CLib
来提高效率。后端很小,专门用于HLib
。 CLib
的界面只会通过HLib
公开; HLib
测试,HLib
基准测试和第三方库(取决于HLib
)不会直接向CLib
发出FFI调用。从测试/基准/第三方lib的角度来看,HLib
应该看起来纯粹是Haskell。这意味着在例如HLib
测试的cabal文件部分中,不应该引用-lCLib
,libCLib
等,只有build-depends
HLib
并且,可执行文件不需要查找动态CLib
库。我需要能够在HLib
和第三方库中构建和运行所有可执行文件,并运行cabal repl
进行开发。
最初,CLib
是用纯C.写的.Cabal支持这种情况,我可以使用{{1}以上述方式将CLib
整合到HLib
中cabal文件中的},include-dirs
和c-sources
字段。
includes
已演变成一个C ++库,我无法弄清楚如何让cabal轻松集成。相反,我使用自定义构建和Setup.hs的makefile,如this。您可以看到此方法的一个小示例here 1,2 。
在该示例中,我无法在CLib
中运行cabal repl
因为"不支持加载档案"。这实际上意味着我需要一个动态C ++库,这个库很容易创建(在HLib
makefile中有一个注释行来完成它)。但是,如果我确实创建了动态C ++库,那么CLib
的测试会在运行时失败,因为没有这样的文件或目录libclib.so"。这很糟糕(除了崩溃),因为测试可执行文件链接到动态库,这不是我想要的。
具体而言,HLib
和HLib
的测试都应该通过,我应该能够在SimpleLib
和cabal repl
目录中运行hlib
我尝试过的其他事情:this answer,this answer(我无法编译),this和阅读the docs(导致"重新安置"错误)。
我目前正在使用GHC-7.10.3,但如果这在8.0中显然更容易,那很好。
[1] 从lol/challenges简化。
[2] 下载并运行simplelib
。这构建./sandbox-init
(隐式构建HLib
和CLib
,这是一个依赖于SimpleLib
的Haskell库。
答案 0 :(得分:5)
一旦你了解了一些技巧,包含一个带有Haskell库的C或C ++库是微不足道的。
我从这个article获得了核心,虽然它似乎使事情过于复杂。你可以使用cabal(目前为1.25)和Simple
构建类型(即没有特殊Setup.hs
),没有makefile,也没有像c2hs
这样的外部工具。
要包含纯C库中的符号:
Include-dirs: relative/path/to/headers/
或Includes: relative/path/to/myheader.h
。 C-sources: relative/path/to/csources/c1.c, relative/path/to/csources/c2.c, etc
。C ++还有几个额外的位:
.cpp
个文件添加到cabal文件中的C-sources
字段。 .cpp
个文件中的所有函数中,添加extern "C"
以避免名称损坏。#ifdef __cplusplus ... #endif
对标题文件中的所有非纯C代码进行处理(请参阅n.m。的答案)。extra-libraries: stdc++
添加到您的cabal文件中,并使用g++
与ghc-options: -pgmlg++
链接。.c(pp)
)起作用,您可能需要使用列出cabal文件中cabal repl
个文件的订单进行一些操作。有关详细信息,请参阅this ticket。那就是它!您可以查看适用于stack
和cabal
的完整工作示例here。
答案 1 :(得分:3)
GHC无法真正理解C ++头文件。它需要纯C代码。 C ++头文件提供C接口的常用方法是用#ifdef __cplusplus
隔离C ++部分,例如:
#ifdef __cplusplus
extern "C" { // C compilers and various C-based FFIs don't like this
#endif
void foo();
#ifdef __cplusplus
}
#endif
此外,历史上已知GHCi在链接C ++代码时存在问题。例如,有一点它没有理解弱符号(通常由编译器与内联函数和模板实例一起产生)。您可能会看到其中一个问题。我建议向GHC团队提交错误报告。