https://en.wikipedia.org/wiki/Name_mangling#How_different_co...
https://en.wikipedia.org/wiki/Name_mangling#How_different_co...
As to the very interesting question of how it's handled here, it looks like part of the project (the "qtdrv" folder) is a shared library written in C++ that includes Qt, wraps the desired functionality, and exports it as C-style symbols (with extern "C"). This is a pretty standard way of circumventing the name mangling problem.
What I find interesting is that everything appears to be wrapped into a single exported function "qtdrv". Might be a wrapping technique that I'm not aware of, or maybe I'm completely misreading the source. I'm actually quite interested in knowing how the wrapping code was generated, having projects where the same kind of C++ wrapping is required.
It appears that GoQt has this giant pile of wrappers around C++ types, casting pointers back and forth:
https://raw.githubusercontent.com/visualfc/goqt/master/qtdrv...
I would have expected this to require an `extern "C"` declaration. I'm sort of surprised it doesn't, but maybe the common C++ ABIs match the C ones if only C types are passed to and from the function?
(Also, is this file auto-generated?)
[it] would not suffice to guarantee C++ compiler
interoperability and it might even create a false
impression that interoperability is possible and
safe when it isn't.Take a look at the Itanium C++ ABI, the de facto standard on GNU/Linux etc. for a sense of the scale of the problem: https://mentorembedded.github.io/cxx-abi/abi.html
And that doesn't even standardize the layout of the actual types in std::* themselves, just the typesystem. That just gives you enough information to correctly access someone else's implementation of std::string; you still need to have that precise implementation around at compile time. There is, however, a proposal to standardize the layout of std: https://isocpp.org/files/papers/n4028.pdf
To be fair, you have the exact same problem when trying to call into e.g. Rust from e.g. C. Rust's typesystem is complex and its libstd is involved and not stabilized, so the easiest way is, again, to route through C types instead of trying to access Rust's String type in C.
That's interesting, thanks.
Although people like to bash C++, there isn't any programming language with an ABI as part of the language standard, not even C.
The C ABI that so many people adhere to, only exists in OS written either in C or C++ (via extern "C").
By the historical accident that all commercial major OSes are mostly written in C, developers that aren't language lawyers tend to think C ABI is somehow defined in some standard.
In OSes that weren't written C, with C compilers available, like OS/400, VMS, Lillith, Lisp Machines, Oberon, the ABI being used isn't the C one.
However, within a given platform, the ABI tends to be small, clear, and well-documented. It's not documented in the C language standard, but there is documentation for it, from whoever defines the platform.
I thought I had mentioned this in another comment, but to be clear, I'm not trying to "bash C++"; plenty of other type systems and standard libraries have the same issue (including Go, Rust, Python, etc.). I'm just relaying the fact that, on the platforms where Go and Rust support FFI, they do so by implementing the C ABI, which is a stable ABI defined in the platform documentation, and the C++ ABI tends not to be well-defined or stable and is also much more complex to implement. This isn't a criticism of C++, just a fact. (And there are good things about this; for instance, C++'s type system is so much more useful than C's.)
Calling into C++ is generally a big problem in any programming language though, and for most, you have to write a C wrapper.
You can perfectly write a C++ library and expose a C-safe subset. I've done so many times.
The problem arises if you need to expose objects (with virtual methods), which C obviously doesn't have as the ffi is basically restricted to plain functions and record types.
Of course, moving can cause problems for Go pointers in C land, but keeping Go pointers beyond a cgo function call will be prohibited in Go 1.6: