用Haskell库静态链接C ++库 [英] Statically link C++ library with a Haskell library

查看:136
本文介绍了用Haskell库静态链接C ++库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

安装:我有一个Haskell库 HLib ,它可以调用C / C ++后端 CLib 来提高效率。后端很小,专门用于 HLib CLib 的接口将 通过 HLib 暴露出来。 HLib 测试, HLib 基准测试和第三方库取决于 HLib 不会直接对 CLib 进行FFI调用。从测试/基准/第三方lib的角度来看, HLib 应该纯粹是Haskell。这意味着在例如 HLib 测试的cabal文件部分中,不应该引用 -lCLib libCLib 等,在 HLib 上只有一个 build-depends ,并且可执行文件不应该需要查找动态 CLib 库。我需要能够在 HLib 和第三方库中生成并运行所有可执行文件,以及运行 cabal repl for development。



原来, CLib 是用纯C编写的.Cabal支持这种情况,而I可以通过使用 include-dirs ,以> CLib <> HLib code>, c-sources 包括字段。



CLib 已经发展成一个C ++库,我无法弄清楚如何轻松集成cabal。相反,我使用了自定义构建和Setup.hs的makefile,例如 。你可以在这里看到这个方法的一个小例子 1,2



在该例中,我无法在 HLib cabal repl $ c>因为加载不支持的档案。这实际上意味着我需要一个动态的C ++库,它非常简单,可以创建(在 CLib makefile中有一条注释行)。但是,如果我制作动态C ++库,由于没有这样的文件或目录libclib.so, HLib 的测试在运行时失败。这是坏的(除了崩溃),因为测试可执行文件链接到动态库,这不是我想要的。



具体而言, HLib SimpleLib 都应该通过,我应该能够运行 cabal repl hlib simplelib 目录中都有

我试过的其他东西:这个答案 a>,这个答案(我无法编译), ,并阅读文档(导致重定位错误)。



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



[1] lol / challenges b
$ b

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

解决方案



我从这个文章,尽管它看起来过于复杂。你可以使用cabal(目前是1.25)和 Simple 构建类型(即没有特殊的 Setup.hs ),没有makefile ,并且没有外部工具,如 c2hs



包含纯C库中的符号:


  1. 在您的cabal文件中,可以添加 Include-dirs:relative / path / to / headers / 包含:relative / path / to / myheader.h

  2. 添加 C-sources:relative / path /to/csources/c1.c,相对/路径/到/ csourc es / c2.c等。

C ++有一些额外的位:


  1. 您可以将 .cpp 文件添加到 C-sources 字段。

  2. 在Haskell需要访问的 .cpp 文件中添加 externC以避免名称混乱。

  3. #ifdef __cplusplus ... #endif 包围头文件中的所有非纯C代码c $ c>(请参阅nm的答案)。
  4. 如果使用标准C ++库,则需要添加 extra-libraries:stdc ++
  5. code>添加到您的cabal文件中,并使用 ghc-options:-pgmlg ++ 链接到 g ++ li>
  6. 您可能不得不用命令摆弄你列出的 .c(pp)文件cabal文件,如果你想动态链接(即 cabal repl )工作。有关详情,请参阅此故事单

  7. ol>

    就是这样!您可以在这里看到一个完整的工作示例,它可以与 stack cabal


    Setup: I have a Haskell library HLib which makes calls to a C/C++ backend CLib for efficiency. The backend is small and specialized for use with HLib. The interface to CLib will only be exposed through HLib; HLib tests, HLib benchmarks and third party libraries depending on HLib will not make direct FFI calls to CLib. From the test/benchmark/3rd party lib perspective, HLib should be appear purely Haskell. This means in the cabal file sections for, e.g., HLib tests, there should be no references to -lCLib, libCLib, etc, only a build-depends on HLib, and that executables should not need to look for a dynamic CLib library. I need to be able to build and run all executables in HLib and third-party libs, as well as run cabal repl for development.

    Originally, CLib was written in pure C. Cabal has support for this case, and I can integrate CLib into HLib in precisely the manner described above by using include-dirs, c-sources, and includes fields in the cabal file.

    CLib has evolved into a C++ library, which I couldn't figure out how to get cabal to integrate easily. Instead, I resorted to a makefile with custom build and Setup.hs, like this. You can see a small example of this method here1,2.

    In that example, I can't run cabal repl in HLib because "Loading archives not supported". This really means I need a dynamic C++ library, which is simple enough to create (there's a commented line in the CLib makefile to do it). If I do make the dynamic C++ library, however, the test for HLib fails at runtime due to a "no such file or directory libclib.so". This is bad (in addition to the crash) because the test executable linked against the dynamic library, which is not what I want.

    Concretely, the tests for HLib and SimpleLib should both pass, and I should be able to run cabal repl in both the hlib and simplelib directories.

    Other things I've tried: this answer, this answer (which I can't get to compile), this, and reading the docs (results in "relocation" errors).

    I'm using GHC-7.10.3 at the moment, though if this is significantly easier in 8.0, that's fine.

    [1] Simplified from lol/challenges.

    [2] Download and run ./sandbox-init. This builds HLib (which implicitly builds CLib, and SimpleLib, which is a Haskell library that depends on HLib.

    解决方案

    Including a C or C++ library with a Haskell library is trivial once you know a few tricks.

    I got the core from this article, though it seems to overcomplicate things. You can use cabal (currently 1.25) with a Simple build type (i.e. no special Setup.hs), no makefile, and no external tools like c2hs.

    To include symbols from a pure C library:

    1. In your cabal file, either add Include-dirs: relative/path/to/headers/ or Includes: relative/path/to/myheader.h.
    2. Add C-sources: relative/path/to/csources/c1.c, relative/path/to/csources/c2.c, etc.

    There's a couple of extra bits for C++:

    1. You can add .cpp files to the C-sources field in the cabal file.
    2. On all functions in .cpp files that Haskell needs access to, add extern "C" to avoid name mangling.
    3. Surround all non-pure-C code in header files with #ifdef __cplusplus ... #endif (see n.m.'s answer).
    4. If you use the standard C++ library, you'll need to add extra-libraries: stdc++ to your cabal file, and link with g++ using ghc-options: -pgmlg++.
    5. You may have to fiddle a bit with the order that you list the .c(pp) files in the cabal file if you want dynamic linking (i.e. cabal repl) to work. See this ticket for more information.

    That's it! You can see a complete working example here which works with both stack and cabal.

    这篇关于用Haskell库静态链接C ++库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆