how to stop name mangling in Qt class? - c++

ultimately my goal is to write a Qt class(my class inherits from QObject and uses Q_OBJECT macro), then build a dll from it. then in python use ctype to access that dll.
when I write the dll normally, method names get mangled so I can't use them directly. instead I have to use getattr which I don't want to use(because others may need to use the dll and I don't want them to get confused).
anyway I read that to stop name mangle I need to use extern "C"
so far I tried these:
extern "C"
{
class MyClass::public QObject
{
Q_OBJECT
public:
void SomeFunction(int Parameter);
}
}
this one does not build because in Q_OBJECT macro templates are used and I get "templates cannot be declared to have 'C' linkage" error.
i tried:
extern "C" typedef void SomeFunction_t(int parameter);
class MyClass::public QObject
{
Q_OBJECT
public:
SomeFunction_t SomeFunction;
}
this one compiled but still SomeFunction name was mangled;
also I can't use extern "C" directly before method declaration because it is inside of class.
so how can I prevent name mangling here?

I'm going to hazard a guess this might be failing because of this construct:
extern "C"
{
class I_AM_A_CPLUSPLUS_CONCEPT {};
}
Anyhow, this is solvable, but requires a little rethink. To expose the class to C, you will have to jump through a couple of hoops here.
// the C++
class MyClass : public QObject
{
Q_OBJECT
public:
void SomeFunction(int Parameter);
};
extern "C" MyClass* MyClass_new() {
return new MyClass;
}
extern "C" void MyClass_delete(MyClass* c) {
delete c;
}
extern "C" void MyClass_SomeFunction(MyClass* c, int p) {
c->SomeFunction(p);
}
'MyClass' will be mangled into a C++ name, and there isn't really any way to expose 'SomeFunction' as a member of MyClass, without using name mangling.
C-Name mangling in the above example will simply expose:
MyClass_new, MyClass_delete, and MyClass_SomeFunction as the symbol names. (i.e. devoid of the function argument types, return type, calling convention, owning class, etc... which is what C++ name mangling will add in).
Just treat MyClass as an opaque pointer, and C code should be happy enough with that. Short of resorting to pybind/boost::python (which clearly don't really work with DLL's cleanly!!), there aren't really any other nice ways to bind in a C++ object to c code.

Related

Calling mangled class instance methods from function marked extern C

I have a typically declared class:
class Task {
public:
int test(int &c);
};
int Task::test(int &c) {
c += 8;
return c;
}
For compiling to WASM, I was trying to instantiate this class and call the test method, like so:
extern "C" {
Task t;
int scratch() {
int c = 123;
t.test(c);
return c;
}
}
with extern "C" directive to prevent name mangling that makes exposing it difficult on the JS module.
However, compiling this program gives error undefined symbol: _ZN4Task4testERi (referenced by top-level compiled C/C++ code), indicating that the "unmangled" int scratch() method cannot call the "mangled" int Task::test(int &c). Wrapping the class definition and implementation with extern "C" produces the same output.
How could I best call int Task::test(int &c) on an instance from a function that is marked extern "C"?
Mangling is close to a hack that was invented to allow the low level linker to make a difference between int foo(int) and int foo(void). You can use extern "C" to explicitely forbid mangling, but you declare symbols to have that linkage, so it should only be used for plain functions and not for classes nor class members.
The idiomatic way is to remember that a call to a non static member function carries a hidden this pointer. So you do not change anything to the Task class but declare a plain function to act as a relay:
extern "C" {
int task_test(Task *obj, int *c) { // C language does not know about reference hence a pointer
return obj->test(*c);
}

How to remove mangling in C++

I tried to create a function which is returning a vector in C++. But when it built to dll, the function name seems to be mangled.
I tried to use the extern C but the problem is return type vector cannot support if I use extern C
Error : C Linkage function cannot return C++ class std:: Vector
Below is the code I am using
class __declspec(dllexport) TestClass
{
public:
string sClassName;
string sName;
string sDescription;
};
extern "C"
{
vector<TestClass> __declspec(dllexport) GetInfoList();
}
We see it is not problem with easy solution. Here's an involved solution. Use a non-mangled name (extern "C") with GetProcAddress to access a special function in the higher level DLL. . Define all the functions you want to call, as virtuals, in an abstract base class. Call that function above to retrieve the pointer P to a lazily instantiated concrete class with virtuals overriden. Invoke desired method through the pointer P.
vector is C++ type and so cannot be directly given under extern "C". Give the function inside a class and export the class as C Type.
extern "C"
{
class __declspec(dllexport) ClassToExport
{
vector<TestClass> GetInfoList();
};
}
Now use this class object to axcess the function.

extern "C" for member static callback function

I want to provide a callback function for code written in Haskell (GHC). It uses GCC C-compiler-like function types to export/import functionality and interoperate at runtime with my code.
I have to provide a callback function, which in fact accept this pointer to the class and just call its method:
struct C
{
int f(int i) { ; }
static int f_callback(void * self, int i)
{
static_cast< C * >(self)->f(i);
}
};
Logically f_callback is a part of class C, so I placed it into the corresponding namespace scope.
But I worry about should I use extern "C" language specification (calling convention is matters here, not name mangling)? It is possible to declare and define extern "C" function in plain namespace, there are a couple of special rules for extern "C" functions defined with the same name in different namespaces, but there is no distinction between namespace of class scope and simple namespace one.
Is it possible to define static extern "C" function into class scope?
The external callback is by design not linked to a specific class.
Making it a static class member is perhaps nice according to the internals of your code, but it misrepresents the reality.
I'd therefore advise to make it an independent extern "C" function. This avoids misunderstanding and highlights assumptions (for example that self is assumed to be a C but could in reality be something else). If f() is public, all this will be very clean. If it would be private, you'd need to make your callback a friend and this tight coupling would be again highlighted.
The wrapper alternative would just add a redundant middleman to come to the same result.

Expose C++ class via header file to C

I have a C++ class that I want to expose to C.
class Foo {
void Method();
}
Bridge to C
typedef struct Foo CFoo;
#ifdef __cplusplus
extern "C" {
#endif
CFoo * CFooInit();
void CFooRelease(CFoo * v);
void CFooMethod(CFoo * v);
#ifdef __cplusplus
}
#endif
and in cpp file, I have
CFoo * CFooInit(){
return new Foo();
}
void CFooRelease(CFoo * v){
delete v;
}
void CFooMethod(CFoo * v){
v->Method();
}
All is working OK, but there is one problem / warning during compilation.
'Foo': type name first seen using 'struct' now seen using 'class'
I know, why it is there, but I dont know, how to fix it. I cannot change the class to struct and I cannot have class keyword in C code. I can use void *, but it can lead to type unsafety.
You can't do that. As Lightness likes to say, there are no structs in C++; there are only classes. They may be represented differently.
You can only define extern "C" free functions in the C++ part which get a pointer to the class and expose those to the C code.
Intead of having a CFooInit return a CFoo*, used a void*. Similarly for CFooRelease, CFooMethod. Forget the typedef struct Foo CFoo.
Of course, those functions will have to cast between void* and Foo*, but that's the price you pay for mixing different type systems.
There's no value in pretending that there's something to be gained by having a C type that's somehow derived from a C++ type.

Accessing DLL with multiple classes in java

I have to access a third party dll which has multiple classes in my Java application. I checked this http://blog.mwrobel.eu/how-to-call-dll-methods-from-java/
But its describing a dll with just a class and some methods. How do I access each specific class and its methods in the dll. Is this possible?
You need to wrap the functionality you need in C-compatible functions (extern "C").
For example, if I have a C++ class as follows:
class Foo {
Foo();
~Foo();
void bar();
}
Then I would need to create some wrapper functions in the shared library that will be accessible via JNA:
extern "C" void* create_foo() { return new Foo(); }
extern "C" void delete_foo(void *foo) { delete (Foo *)foo; }
extern "C" void bar(void *foo) { ((Foo *)foo)->bar(); }
If you have to do a lot of this and compile some native code anyway, you might find using SWIG to be of use. You can customize how your native classes map into Java classes and vice versa.
Did you try adapting the interface from the examples from your link. I think that if you make similar interface with loadLibrary("otherClassName",...) you will be able to load another class from this interface.