Wrapping a C++ library

Hi there, There is a C++ library for which I'm working on an FFI wrapper. I've written a translation unit which defines several functions with an extern "C" API. Each of the functions does a little bit of C++ to operate the third party library, but the point is that I now have a C API that I can wrap with the FFI. The next thing I did was to try and get Cabal to compile this translation unit for me. I eventually hacked together a Setup.hs that I barely understand that calls gcc to compile the .cpp file and then calls `ar` to, um, well do whatever it is that ar does with .o files, make some sort of archive, or something. Next, I need to get my hsc file (in which I define some imported functions and some data types with Storable instances for shovelling data through the FFI) to compile. This file uses the hsc2hs #include macro to include the .h file of my translation unit. In turn, that .h includes some of the C++ header files from the third party, and eventually an STL header: vector. At this point, the compiler, gcc, complains that it can't find vector. The gcc command that hsc2hs (I think?) is creating does not include -lstdc++, and nethier does it use g++, either of which would, I think, result in a successful compilation of the hsc2hs .c file. In my cabal file I have: extra-libraries: stdc++ ghc-options: -pgml g++ -Wall But these don't seem to fix anything. Perhaps they don't have any effect on how hsc2hs operates? There's a specific question here which goes something like: how do I get hsc2hs to compile code that uses STL headers? But there's also a more general question as to whether my whole approach of creating an extern "C" wrapper is actually going to work? Any answers would be very appreciated. Richard

Quoth Richard Lewis
There's a specific question here which goes something like: how do I get hsc2hs to compile code that uses STL headers?
From there, I would have guessed "extra-libraries: stdc++" would do it, (assuming you have also arranged to get your wrapper library in there), but I'm no cabal expert. I use C++ more or less like you're doing, so
For me, that would be the first thing to fix. Use #ifdef __cplusplus, or just reorganize, so the hsc2hs-generated files are just C. You wrote your wrapper library for the C++ part, and if the callers need to be C++ it kind of defeats the purpose. there's hope, but I haven't gotten around to the cabal part of the exercise. Donn

Richard,
If you create a straight C header that's able to call into the C++ library
then what you're trying to do will work. This is the standard (though
frustrating) approach to using C++ libraries within Haskell. I can send you
an example cabal file for building the Haskell code against the C headers
and archives if you'd like. There isn't much more to it than what you're
already doing though. The key is that the headers have to be pure C and you
have to force cabal to build the C code with g++ (since the implementing .c
files will necessarily make C++ calls).
Thanks,
Arjun
On Mon, Jan 26, 2015 at 11:29 AM, Donn Cave
Quoth Richard Lewis
, ... There's a specific question here which goes something like: how do I get hsc2hs to compile code that uses STL headers?
For me, that would be the first thing to fix. Use #ifdef __cplusplus, or just reorganize, so the hsc2hs-generated files are just C. You wrote your wrapper library for the C++ part, and if the callers need to be C++ it kind of defeats the purpose.
From there, I would have guessed "extra-libraries: stdc++" would do it, (assuming you have also arranged to get your wrapper library in there), but I'm no cabal expert. I use C++ more or less like you're doing, so there's hope, but I haven't gotten around to the cabal part of the exercise.
Donn _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Quoth Arjun Comar
Richard, If you create a straight C header that's able to call into the C++ library then what you're trying to do will work. This is the standard (though frustrating) approach to using C++ libraries within Haskell. I can send you an example cabal file for building the Haskell code against the C headers and archives if you'd like. There isn't much more to it than what you're already doing though. The key is that the headers have to be pure C and you have to force cabal to build the C code with g++ (since the implementing .c files will necessarily make C++ calls).
This is probably an absurdly elementary question, but at this last point, "... force cabal to build the C code with g++ ...", wouldn't this happen automatically, since they'll really be .C, not .c, files? E.g., in Blegger.hsc (#include "blegger.h") Blegger_stub.c (C code created by hsc2hs) blegger.h (C include file) blegger.C (extern "C" { #include "blegger.h" }) ... _stub.c shouldn't need g++, and .C should get it naturally? Donn

Unfortunately, Cabal doesn't support C++ sources directly. So if you plan
to use make or something to build the .C files outside of cabal, you're
right. But if you plan to throw the .C files into the cabal file, you'll
run into an issue with cabal calling gcc instead of g++ on the C++ sources.
gcc might do the right thing for you, but my experience is that the result
is thorny.
The approach I've managed to get working is to have cabal call g++ in place
of gcc, which works for both C and C++ sources.
Thanks,
Arjun
On Mon, Jan 26, 2015 at 5:37 PM, Donn Cave
Richard, If you create a straight C header that's able to call into the C++
Quoth Arjun Comar
, library then what you're trying to do will work. This is the standard (though frustrating) approach to using C++ libraries within Haskell. I can send you an example cabal file for building the Haskell code against the C headers and archives if you'd like. There isn't much more to it than what you're already doing though. The key is that the headers have to be pure C and you have to force cabal to build the C code with g++ (since the implementing .c files will necessarily make C++ calls).
This is probably an absurdly elementary question, but at this last point, "... force cabal to build the C code with g++ ...", wouldn't this happen automatically, since they'll really be .C, not .c, files?
E.g., in
Blegger.hsc (#include "blegger.h") Blegger_stub.c (C code created by hsc2hs) blegger.h (C include file) blegger.C (extern "C" { #include "blegger.h" })
... _stub.c shouldn't need g++, and .C should get it naturally?
Donn _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Arjun,
I'm not an expert in writing Haskell binding but pretty much experienced in
C/low-level stuff.
You shouldn't force compilation of .c files with g++. Instead, you should
keep your wrapping functions as extern "C" and place their implementation
in .cpp file (which of course should be compiled with g++). Don't forget to
link to C++ runtime library (-lstdc++).
There is also a wiki page[1] that describes how to call C++ from Haskell.
Best regards,
Alexey
[1]: https://wiki.haskell.org/CPlusPlusFromHaskell
2015-01-26 23:27 GMT+02:00 Arjun Comar
Richard, If you create a straight C header that's able to call into the C++ library then what you're trying to do will work. This is the standard (though frustrating) approach to using C++ libraries within Haskell. I can send you an example cabal file for building the Haskell code against the C headers and archives if you'd like. There isn't much more to it than what you're already doing though. The key is that the headers have to be pure C and you have to force cabal to build the C code with g++ (since the implementing .c files will necessarily make C++ calls).
Thanks, Arjun
On Mon, Jan 26, 2015 at 11:29 AM, Donn Cave
wrote: Quoth Richard Lewis
, ... There's a specific question here which goes something like: how do I get hsc2hs to compile code that uses STL headers?
For me, that would be the first thing to fix. Use #ifdef __cplusplus, or just reorganize, so the hsc2hs-generated files are just C. You wrote your wrapper library for the C++ part, and if the callers need to be C++ it kind of defeats the purpose.
From there, I would have guessed "extra-libraries: stdc++" would do it, (assuming you have also arranged to get your wrapper library in there), but I'm no cabal expert. I use C++ more or less like you're doing, so there's hope, but I haven't gotten around to the cabal part of the exercise.
Donn _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Alexey,
It's unfortunately been about a year since I've worked on the project that
needed FFI support so I don't recall the precise issue any longer. From
talking to people in #haskell, I discovered that it would be necessary to
call g++ and not gcc because gcc is unable to locate some headers and
libraries that inevitably get included by C++ projects.
Thanks,
Arjun
On Mon, Jan 26, 2015 at 5:49 PM, Alexey Shmalko
Arjun,
I'm not an expert in writing Haskell binding but pretty much experienced in C/low-level stuff.
You shouldn't force compilation of .c files with g++. Instead, you should keep your wrapping functions as extern "C" and place their implementation in .cpp file (which of course should be compiled with g++). Don't forget to link to C++ runtime library (-lstdc++).
There is also a wiki page[1] that describes how to call C++ from Haskell.
Best regards, Alexey
[1]: https://wiki.haskell.org/CPlusPlusFromHaskell
2015-01-26 23:27 GMT+02:00 Arjun Comar
: Richard, If you create a straight C header that's able to call into the C++ library then what you're trying to do will work. This is the standard (though frustrating) approach to using C++ libraries within Haskell. I can send you an example cabal file for building the Haskell code against the C headers and archives if you'd like. There isn't much more to it than what you're already doing though. The key is that the headers have to be pure C and you have to force cabal to build the C code with g++ (since the implementing .c files will necessarily make C++ calls).
Thanks, Arjun
On Mon, Jan 26, 2015 at 11:29 AM, Donn Cave
wrote: Quoth Richard Lewis
, ... There's a specific question here which goes something like: how do I get hsc2hs to compile code that uses STL headers?
For me, that would be the first thing to fix. Use #ifdef __cplusplus, or just reorganize, so the hsc2hs-generated files are just C. You wrote your wrapper library for the C++ part, and if the callers need to be C++ it kind of defeats the purpose.
From there, I would have guessed "extra-libraries: stdc++" would do it, (assuming you have also arranged to get your wrapper library in there), but I'm no cabal expert. I use C++ more or less like you're doing, so there's hope, but I haven't gotten around to the cabal part of the exercise.
Donn _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Hi Arjun,
I've been doing quite a bit of this kind of thing recently, but it took me
a while to figure it out too. I've made a little example at
https://github.com/ian-ross/cpp-ffi-example -- just clone the repo and
follow the instructions in the README.
The example has a C++ test library to build that doesn't do anything very
interesting but provides some things to bind to. It uses a C wrapper
around the C++ library and C2HS to write the Haskell FFI side of things
(you can almost certainly use hsc2hs in the same kind of way). There's
also a small test program so you see the bindings working end-to-end. I
guess the most critical thing is using extern "C" and the __cplusplus
compiler macro to control the visibility of C++ code to GCC -- take a look
at cbits/a.h and cbits/a.cpp in the repo to see what I mean.
Feel free to ask if you have any questions.
Cheers,
Ian.
On 26 January 2015 at 23:55, Arjun Comar
Alexey, It's unfortunately been about a year since I've worked on the project that needed FFI support so I don't recall the precise issue any longer. From talking to people in #haskell, I discovered that it would be necessary to call g++ and not gcc because gcc is unable to locate some headers and libraries that inevitably get included by C++ projects.
Thanks, Arjun
On Mon, Jan 26, 2015 at 5:49 PM, Alexey Shmalko
wrote: Arjun,
I'm not an expert in writing Haskell binding but pretty much experienced in C/low-level stuff.
You shouldn't force compilation of .c files with g++. Instead, you should keep your wrapping functions as extern "C" and place their implementation in .cpp file (which of course should be compiled with g++). Don't forget to link to C++ runtime library (-lstdc++).
There is also a wiki page[1] that describes how to call C++ from Haskell.
Best regards, Alexey
[1]: https://wiki.haskell.org/CPlusPlusFromHaskell
2015-01-26 23:27 GMT+02:00 Arjun Comar
: Richard, If you create a straight C header that's able to call into the C++ library then what you're trying to do will work. This is the standard (though frustrating) approach to using C++ libraries within Haskell. I can send you an example cabal file for building the Haskell code against the C headers and archives if you'd like. There isn't much more to it than what you're already doing though. The key is that the headers have to be pure C and you have to force cabal to build the C code with g++ (since the implementing .c files will necessarily make C++ calls).
Thanks, Arjun
On Mon, Jan 26, 2015 at 11:29 AM, Donn Cave
wrote: Quoth Richard Lewis
, ... There's a specific question here which goes something like: how do I get hsc2hs to compile code that uses STL headers?
For me, that would be the first thing to fix. Use #ifdef __cplusplus, or just reorganize, so the hsc2hs-generated files are just C. You wrote your wrapper library for the C++ part, and if the callers need to be C++ it kind of defeats the purpose.
From there, I would have guessed "extra-libraries: stdc++" would do it, (assuming you have also arranged to get your wrapper library in there), but I'm no cabal expert. I use C++ more or less like you're doing, so there's hope, but I haven't gotten around to the cabal part of the exercise.
Donn _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- Ian Ross Tel: +43(0)6804451378 ian@skybluetrades.net www.skybluetrades.net

Donn, Arjun, Alexey, Ian, Thanks, all, for your suggestions. At Mon, 26 Jan 2015 08:29:24 -0800, Donn Cave wrote:
Quoth Richard Lewis
, ... There's a specific question here which goes something like: how do I get hsc2hs to compile code that uses STL headers?
For me, that would be the first thing to fix. Use #ifdef __cplusplus, or just reorganize, so the hsc2hs-generated files are just C. You wrote your wrapper library for the C++ part, and if the callers need to be C++ it kind of defeats the purpose.
Yes, so it turns out the problem was that my wrapper .h was including one of the headers of the third party library which, in turn, was including vector. But I've managed to arrange it so that I don't need to include that third party header anymore so gcc can compile my translation unit without problems.
From there, I would have guessed "extra-libraries: stdc++" would do it, (assuming you have also arranged to get your wrapper library in there), but I'm no cabal expert. I use C++ more or less like you're doing, so there's hope, but I haven't gotten around to the cabal part of the exercise.
The challenge with Cabal now is to get it to link my .a library with the libHSMyLibrary.a that GHC creates. It seems, from what I've read [1], that there is no Cabal hook into the linker so it may involve quite a bit of work in the Setup.hs file. I was just following up a suggestion [2] that (I think), if the .a file Cabal has created for my wrapper static library is in the same directory as, um, not sure what--output libHSMyLibrary.a? gcc working directory?--and if its name is of the form "libxxx.a", then it may be possible to add -lmylib to gcc's options, and gcc will pick it up. Anyway, I altered my Setup.hs to do this, putting libmylib.a in dist/build and dynamically adding /path/to/dist/build to the "extra-libraries" option, but nm still reports that the resulting libHSMyLibrary.a does not contain libmylib.a (or would it be mylib.o?). This might be a discussion for a new thread, however. The immediate problem of how to compile the C wrapper is now fixed. Richard [1] http://stackoverflow.com/questions/18543228/statically-linking-a-c-library-w... [2] https://www.haskell.org/pipermail/haskell-cafe/2006-June/016022.html
participants (5)
-
Alexey Shmalko
-
Arjun Comar
-
Donn Cave
-
Ian Ross
-
Richard Lewis