views:

354

answers:

3

I need to make a large c++ library avaiable for use in .Net languages such as C#.

The library contains a large number of classes which can be broken into two groups. Refrence counted classes, which implement the IRefCounted abstract class and use a factory method to create them, and just plain classes using new/delete.

In adittion there are many plain functions.

Origenannly I was just going to write wrapper classes for everything in c++/clr. However it is desired that the resulting wrapper libraries will work on Mono. Recompiling the library and the wrapper to target each platform is fine, however the problem is that it seems that c++/clr can only target windows as there is no compiler for it to target other platforms and thus the wrapper code wont work on other patforms...

Is there somthing I missed here (like a howto run c++/clr on x platform guide) or is there an alterative way to make all the c++ functions, structs and classes avaible to C#?

EDIT: By avaible I mean avaible to use eg say in my c++ lib I had

//namespace maths{
class Vector2
{
public:
    float x,y;
    Vector2();
    Vector2(const Vector&);
    Vector2(float x, float y);
    float Dot();
    //operators
    ...
};

Then in C# id like to be able to use it like a normal class eg

maths::Vector2 a = new maths::Vector2(5, 5);
maths::Vector2 b = new maths::Vector2(1, 10);
b *= 3
maths::Vector2 c = a + b;
//c.x == 8, c.y == 35

Also however I do it I cant edit the c++ library, anything must be done as a wrapper around the existing classes and functions.

A: 

If by making available you mean making avaible for editing, you could implement a template/macro-driven reflection system in C++ and build the wrapper for C# and Mono on top of that. For an idea on how to implement it, you could have a look at the

DECLARE_DYNAMIC

and

RUNTIME_CLASS

macros in MFC and the

ICustomTypeDescriptor

interface in C#.

Some books in the Game Programming Gems series also cover that topic.

If on the other hand you mean making available for programming, you'll obiously have to provide the programmer with all the types he's supposed to work with, i.e. you have to wrap them.

As far as I understand it, Mono is a virtual machine capable of executing byte-code produced by the CLR (and others), so the C# binaries are all you need.

I'm not aware of any way for C# to directly use c++ classes in static and dynamic libaries as well as many implemented directly in header files. Thats why I was going to use c++/clr since it can use unmanged c++ and provide an interface for C# to use. However it seems to be limited to windows...
Fire Lancer
+1  A: 

I used SWIG to wrap some C++ code and calling it from mono worked great.

timday
Looks like it is a viable solution, just a few things I dont really see explained to well which may cause problems for me:
Fire Lancer
Can it understand refrence counted c++ classes, increaseing and decreasing the refrence? I'm asumming it will ned some help here, ie if a pointer to a ref counted object is owned (needs to decrease the count when down) or borrwed(needs to increase the ref if its keeping the object).
Fire Lancer
And is there someway to provide some sort of conversion info for dealing with certain types. Eg that the std::basic_string<unsigned short> is encoded in utf-16 throughout my lib, so it needs to ensure string going in and out are correctly encoded.
Fire Lancer
My use of it was pretty simple. I actually changed some of the API to use char* strings to ease swigification. Didn't look into how C# and C++-world ref.counting interacted.
timday
+2  A: 

C++/CLI wrappers are definitely the best option if you are only targetting Windows. They perform very well, are very easy to write and maintain, etc. But, as you said, this will not work on Mono. The issue is that the assembly that gets created is not a clr:pure assembly, but one that has mixed native and IL code, so it will not work outside of Windows. In addition, you need to create separate assemblies in C++/CLI for x86 and x64 targets, if you're going to be targetting 64bit systems.

SWIG is definitely an option. It can handle all of the complexities of wrapping a C++ class, but when you get to more complex issues, you typically have to do some tweaking.

I'd recommend checking out the SWIG main site, and especially their C# section.

For good examples of using SWIG to wrap a very complex library, check out OGRE Dot Net (nearly dead, but still a good example) or GDAL. From what I remember, both have special handling for C# specific features, and handle reference counted classes, enums, etc.

The other nice thing about SWIG - if you make SWIG wrappers, it's very easy to extend it to other languages if you ever need to. Once you have the wrappers, making Java, python, ruby, etc wrappers is easy.

Reed Copsey