META: If one of the main Haskell lists is a better place for than ffi for this discussion, please let me know. Many thanks for the help Alastair. I'll study the Greencard and this code this weekend and see if it looks like a good way to acheive what I'd like to do. In the mean time, a couple of immediate points/questions. On 28 Aug 2001, Alastair David Reid wrote:
You might look at Greencard. Greencard was specifically designed to let you easily map a C function interface into the corresponding idiomatic Haskell type. I believe this was _not_ such an important goal for hdirect. [Other tools (which are being more actively developed) have the same goal - but I haven't used them so I can't comment on them.]
ATM I'm more interested in the opposite direction: getting informatoin out of a Haskell function which returns a non-abstract, non-primitive data type.
Although Greencard is targetted at C, we (the Yale group) used it with a C++ visual tracking library. I'm attaching some code to show you what it looks like because although 'extern "C"' does play a role, I think it's different from what you're thinking of.
Other than being inelegant, is there anything to prevent me trying to hack on a stage in the foreign code interface stuff that compares the output of `nm' and `nm --demangle' to do automatic conversion into mangled-names when there is no overloading going on. (I ask this because it would minimise the changes needed to the C++ source code to call C++ functions.)
I don't see a fundamental problem - but it does sound like one of those projects that is always 90% complete because the last 10% is too painful to do properly.
I'm a bit puzzled here: I've got an object file which, amongst other things contains one function called blockMatchScore16x16Simple. It's the only function of that name (no overloading). If I do the output nm --demangle on the file the only occurrence of that string is in the context of this line: 00000000 T blockMatchScore16x16Simple(int *, int, int, int, unsigned char *, unsigned char *) Equally the only occurence in the straight nm output is 00000000 T blockMatchScore16x16Simple__FPiiiiPUcT4 Doesn't this mean that to make the function calling mechanism work in one of the Haskell ffi's `as is' all that has to be done is change the string blockMatchScore16x16Simple into blockMatchScore16x16Simple__FPiiiiPUcT4. (I suppose a C++ compiler might theoretically be allowed to have a completely different calling convention to the corresponding C one, but I can't imagine it actually happening in practice.) Note that I'm not proposing to do anything for either overloaded or `optional argument' functions, it'd just be nice to be able to avoid a ripple effect when, after changing a function to be extern "C" so that it can be called from Haskell any object file containing a call to that function has to be recompiled. And then recompiled again when I finish the prototyping and take away the extern "C" (Cf. my .signature :-) ). [snip]
5) The system this was used in was described in our ICSE'99 paper:
Yes it was reading this paper recently which prompted me to think again about trying to integrate Haskell prototyping with the C++ code. However, that paper seems to tackle the problem of building applications (more especially the control logic) from well understood and implemented low-level, compute-intensive primitives in C++. I'm thinking more about the situation where you're actively researching new low-level primitives and it'd be nice to be able to try out ideas for new low-level stuff quickly in haskell. A good example which has happened recently is formulating an objective function over a long vector which the plan is to minimise by `annealing' using the partial derivatives; many times the definition may have multiple local minima which prevent convergence to the `correct' answer, and this property is often quite sensitive to the exact form of the objective function. It'd be nice to be able to experiment with this in a language with garbage collection, local lambda functions, list comprehensions, etc. However, if the algorithm looks promising it'll be translated into the C++ part of the program for quickest execution. By contrast, the control-logic parts of my programs are relatively simple. To be more concrete what I'd like to be able to do without too much work setting up each new case is C++ ----------> Haskell | C++ function <------ (The re-entrant call into C++ is for simple calls to simple numerical functions, say gaussian_err(float *mean,float **covar,float *x) which could be defined in Haskell without any problems but I'd just like to minimise the duplication because each duplication allows the possibilities of typos.) Whilst the C++ side does have all the weird (and wonderful aspects) of C++ like objects, overloading, etc, I don't see that it'd be particularly useful for what I want to get done to move them to across the language border; i.e., I'm basically thinking about interfacing to C functions, except compiled with a C++ compiler. Many thanks for any illumination anyone can shed on this, ___cheers,_dave________________________________________________________ www.cs.bris.ac.uk/~tweed/pi.htm |tweed's law: however many computers email: tweed@cs.bris.ac.uk | you have, half your time is spent work tel: (0117) 954-5250 | waiting for compilations to finish.
D Tweed <tweed@cs.bris.ac.uk> writes:
Other than being inelegant, is there anything to prevent me trying to hack on a stage in the foreign code interface stuff that compares the output of `nm' and `nm --demangle' [...]
Alastair wrote:
I don't see a fundamental problem - but it does sound like one of those projects that is always 90% complete because the last 10% is too painful to do properly.
D Tweed <tweed@cs.bris.ac.uk> replied:
I'm a bit puzzled here: [explanation of why it's simple deleted]
I guess it was more of a metacomment. This sounds like the kind of little hack which succeeds so well in its narrow domain that you find yourself extending it to do a little bit more. This too succeeds but increases the demands a bit more... And before you know it, the whole thing has grown out of control but, for the new domain that it has grown into, it really isn't very good at all. Personally, I'd use GreenCard (but compile the code with C++) for this part of the project. For the function you describe: result blockMatchScore16x16Simple(int *, int, int, int, unsigned char *, unsigned char *) all you'd have to write is: %#include "some_header.hh" %fun blockMatchScore16x16Simple :: Int* -> Int -> Int -> Int -> Char* -> Char* -> Result [I've written Int* and Char* instead of a more appropriate type because I can't tell if those are in or out functions or arrays or ... Fortunately, GreenCard deals well with these cases - you just write a little bit more to disambiguate.] No messing around with object files and the C++ compiler checks the types of everything you write. [If you really want to explore the object file route, I can offer you a program to rename symbols in ELF files :-) It's a very small part of Knit which you can get by following the links to my current project in my web page.]
To be more concrete what I'd like to be able to do without too much work setting up each new case is
C++ ----------> Haskell | C++ function <------
Ah, I hadn't appreciated that you wanted to do a lot of calling in from C++. Greencard can do Haskell -> C/C++ but offers no support for the other direction. (Probably because the dynamic linking required in Hugs would be ugly.) Seems like the more recent C<->Haskell tools ought to be of some use. Of course, the function names will need mangled somehow. Apart from using ugly names in the Haskell code, options include: 1) Use your nm | grep | ... trick 2) If using Hugs' ffi implementation (not strongly recommended), try compiling the code Hugs generates with a C++ compiler. It might just work... 3) Use my object file renamer -- Alastair Reid reid@cs.utah.edu http://www.cs.utah.edu/~reid/
participants (2)
-
Alastair David Reid -
D. Tweed