问题
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.
回答1:
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:
- In your cabal file, either add
Include-dirs: relative/path/to/headers/orIncludes: relative/path/to/myheader.h. - 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++:
- You can add
.cppfiles to theC-sourcesfield in the cabal file. - On all functions in
.cppfiles that Haskell needs access to, addextern "C"to avoid name mangling. - Surround all non-pure-C code in header files with
#ifdef __cplusplus ... #endif(see n.m.'s answer). - If you use the standard C++ library, you'll need to add
extra-libraries: stdc++to your cabal file, and link withg++usingghc-options: -pgmlg++. - 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.
回答2:
GHC cannot really understand C++ header files. It needs pure C code. The common way for a C++ header file to provide C interface is to isolate away C++ parts with #ifdef __cplusplus, e.g.:
#ifdef __cplusplus
extern "C" { // C compilers and various C-based FFIs don't like this
#endif
void foo();
#ifdef __cplusplus
}
#endif
In addition, GHCi is historically known to have problems with linking C++ code. For example, at one point it didn't understand weak symbols (often produced by the compiler in conjunction with inline functions and template instantiations). You might be seeing one of these problems. I'd recommend filing a bug report to the GHC team.
来源:https://stackoverflow.com/questions/37572628/statically-link-c-library-with-a-haskell-library