静态链接C ++库和Haskell库

时间:2016-06-01 15:14:46

标签: haskell ghc cabal

设置:我有一个Haskell库HLib,它可以调用C / C ++后端CLib来提高效率。后端很小,专门用于HLibCLib的界面只会通过HLib公开; HLib测试,HLib基准测试和第三方库(取决于HLib)不会直接向CLib发出FFI调用。从测试/基准/第三方lib的角度来看,HLib应该看起来纯粹是Haskell。这意味着在例如HLib测试的cabal文件部分中,不应该引用-lCLiblibCLib等,只有build-depends HLib并且,可执行文件不需要查找动态CLib库。我需要能够在HLib和第三方库中构建和运行所有可执行文件,并运行cabal repl进行开发。

最初,CLib是用纯C.写的.Cabal支持这种情况,我可以使用{{1}以上述方式将CLib整合到HLib中cabal文件中的},include-dirsc-sources字段。

includes已演变成一个C ++库,我无法弄清楚如何让cabal轻松集成。相反,我使用自定义构建和Setup.hs的makefile,如this。您可以看到此方法的一个小示例here 1,2

在该示例中,我无法在CLib中运行cabal repl因为"不支持加载档案"。这实际上意味着我需要一个动态C ++库,这个库很容易创建(在HLib makefile中有一个注释行来完成它)。但是,如果我确实创建了动态C ++库,那么CLib的测试会在运行时失败,因为没有这样的文件或目录libclib.so"。这很糟糕(除了崩溃),因为测试可执行文件链接到动态库,这不是我想要的。

具体而言,HLibHLib的测试都应该通过,我应该能够在SimpleLibcabal repl目录中运行hlib

我尝试过的其他事情:this answerthis answer(我无法编译),this和阅读the docs(导致"重新安置"错误)。

我目前正在使用GHC-7.10.3,但如果这在8.0中显然更容易,那很好。

[1] lol/challenges简化。

[2] 下载并运行simplelib。这构建./sandbox-init(隐式构建HLibCLib,这是一个依赖于SimpleLib的Haskell库。

2 个答案:

答案 0 :(得分:5)

一旦你了解了一些技巧,包含一个带有Haskell库的C或C ++库是微不足道的。

我从这个article获得了核心,虽然它似乎使事情过于复杂。你可以使用cabal(目前为1.25)和Simple构建类型(即没有特殊Setup.hs),没有makefile,也没有像c2hs这样的外部工具。

要包含纯C库中的符号:

  1. 在您的cabal文件中,添加Include-dirs: relative/path/to/headers/Includes: relative/path/to/myheader.h
  2. 添加C-sources: relative/path/to/csources/c1.c, relative/path/to/csources/c2.c, etc
  3. C ++还有几个额外的位:

    1. 您可以将.cpp个文件添加到cabal文件中的C-sources字段。
    2. 在Haskell需要访问的.cpp个文件中的所有函数中,添加extern "C"以避免名称损坏。
    3. 使用#ifdef __cplusplus ... #endif对标题文件中的所有非纯C代码进行处理(请参阅n.m。的答案)。
    4. 如果您使用标准C ++库,则需要将extra-libraries: stdc++添加到您的cabal文件中,并使用g++ghc-options: -pgmlg++链接。
    5. 如果您希望动态链接(即.c(pp))起作用,您可能需要使用列出cabal文件中cabal repl个文件的订单进行一些操作。有关详细信息,请参阅this ticket
    6. 那就是它!您可以查看适用于stackcabal的完整工作示例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团队提交错误报告。