I'm finding that I can call standalone C functions from Swift without any problem.
But when I try to call a standalone C++ function, the linker claims the function doesn't exist.
e.g. calling from Swift:
fubar (123); // error: undefined reference to fubar
e.g. in source.cpp:
static std::vector<int> myvector;
void fubar (int x) {
myvector.push_back(x);
}
Does anyone know why a standalone C++ function wouldn't link properly but a C function would?
It also seems that bridging via Objective-C isn't working:
bridging.h:16:9: note: in file included from bridging.h:16:
#import "Bridge.h"
^
./Bridge.h:2:1: error: expected identifier or '('
@interface Bridge
^
bridging.h:16:9: note: in file included from bridging.h:16:
#import "Bridge.h"
Check that you are exporting the C++ function as a C function. (C++ function signatures are mangled; Swift can't see them unless they are exported as C functions.)
I'm also using classes but I've been assuming the best way to build a bridge between Swift and C++ is to use standalone functions.
Also my header does declare fubar, however because swiftc refuses to parse any C++ in the bridging header, I have to have two headers, one for swiftc and one for C++ i.e. clang.
I suspect the error you're running into is that the declaration is extern C, while the definition is not. This doesn't haven anything to do with Swift. Just remove the extern C block, and let it be a normal, C++ forward declaration. Swift can handle those when you pass the enable interop flag.
I suspect you either need to recompile the c++ object file or maybe you're liking them together wrong. Seems like you got the hard part figured out though!
You just have to consider all these factors in concert:
Bridging header shall be using C / Obj-C language. Either no C++ stuff there or enclose C++ bits in "#ifdef __cplusplus" brackets.
Normally you won't need to use this bridging header in C++, but if you do remember that C++ doesn't know Obj-C, so you'll need some brackets there as well.
There's a language mode called Obj-C++, typically denoted via ".mm" file extension - this language mode knows all three languages.
"foobar" (used in Swift) should have C linkage. This linkage is automatic in C / Obj-C, just in case of C++ you have to tell this explicitly.
The easiest thing to tell this in C++ header (and make that header compatible with C/Swift) is to use the "#ifdef __cplusplus" brackets:
#ifdef __cplusplus
extern "C" {
#endif
... stuff here that should have C linkage
void foobar(int);
#ifdef __cplusplus
}
#endif
If it was a header purely for C++ usage you would be able specifying the C linkage more easily:
extern "C" void foobar(int);
But that's not compatible with C / Swift, so to use the same header in there you'd still need brackets:
But then you'd need to remember to keep them in sync. I'd not go that route but understandably for some that way would be easier to cope with ("no those ugly looking #ifdefs")
I'm on Linux, so my clang doesn't have Foundation. I think this might limit my ability to use Obj-C or Obj-C++ effectively.
So far the C-calling-C++ approach is working.
What would be more convenient though would be if I could create a global C++ object that I could call from Swift.
I believe for now you either have to call "Swift -> C -> C++" or "Swift -> Obj-C -> C++", creating the intermediate wrapper above your C++ object in C or Obj-C. The C / Obj-C wrapper part could still live in the same C++ / Obj-C++ file if that's more convenient for you. Don't know whether this is any different on Linux.
I can't really reply to all of this, but I think there are some misconceptions in this thread. I don't think Objective-C interop is really supported on Linux.
Also, you can (and imo should) use C++ interop, which will let you call C++ functions and use C++ types in Swift without any bridging. To enable C++ interop, you can use the flags we discussed earlier. If you use C++ interop, there is no need for the extern C blocks anywhere.