Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
249 views
in Technique[技术] by (71.8m points)

ghc - Statically link C++ library with a Haskell library

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...