I have a significant library of classes written in C++. I'm trying to make use of them through some type of bridge within Swift rather than rewrite them as Swift code. The primary motivation is that the C++ code represents a core library that is used on multiple platforms. Effectively, I'm just creating a Swift based UI to allow the core functionality to work under OS X.
There are other questions asking, "How do I call a C++ function from Swift." This is not my question. To bridge to a C++ function, the following works fine:
Define a bridging header through "C"
#ifndef ImageReader_hpp
#define ImageReader_hpp
#ifdef __cplusplus
extern "C" {
#endif
const char *hexdump(char *filename);
const char *imageType(char *filename);
#ifdef __cplusplus
}
#endif
#endif /* ImageReader_hpp */
Swift code can now call functions directly
let type = String.fromCString(imageType(filename))
let dump = String.fromCString(hexdump(filename))
My question is more specific. How can I instantiate and manipulate a C++ Class from within Swift? I can't seem to find anything published on this.
I've worked out a perfectly manageable answer. How clean you'd like this to be is entirely based upon how much work you're willing to do.
First, take your C++ class and create C "wrapper" functions to interface with it. For example, if we have this C++ class:
class MBR {
std::string filename;
public:
MBR (std::string filename);
const char *hexdump();
const char *imageType();
const char *bootCode();
const char *partitions();
private:
bool readFile(unsigned char *buffer, const unsigned int length);
};
We then implement these C++ functions:
#include "MBR.hpp"
using namespace std;
const void * initialize(char *filename)
{
MBR *mbr = new MBR(filename);
return (void *)mbr;
}
const char *hexdump(const void *object)
{
MBR *mbr;
static char retval[2048];
mbr = (MBR *)object;
strcpy(retval, mbr -> hexdump());
return retval;
}
const char *imageType(const void *object)
{
MBR *mbr;
static char retval[256];
mbr = (MBR *)object;
strcpy(retval, mbr -> imageType());
return retval;
}
The bridge header then contains:
#ifndef ImageReader_hpp
#define ImageReader_hpp
#ifdef __cplusplus
extern "C" {
#endif
const void *initialize(char *filename);
const char *hexdump(const void *object);
const char *imageType(const void *object);
#ifdef __cplusplus
}
#endif
#endif /* ImageReader_hpp */
From Swift, we can now instantiate the object and interact with it like so:
let cppObject = UnsafeMutablePointer<Void>(initialize(filename))
let type = String.fromCString(imageType(cppObject))
let dump = String.fromCString(hexdump(cppObject))
self.imageTypeLabel.stringValue = type!
self.dumpDisplay.stringValue = dump!
So, as you can see, the solution (which is actually rather simple) is to create wrappers that will instantiate an object and return a pointer to that object. This can then be passed back into the wrapper functions which can easily treat it as an object conforming to that class and call the member functions.
Making It Cleaner
While this is a fantastic start and proves that it is completely feasible to use existing C++ classes with a trivial bridge, it can be even cleaner.
Cleaning this up would simply mean that we remove the UnsafeMutablePointer<Void> from the middle of our Swift code and encapsulate it into a Swift class. Essentially, we use the same C/C++ wrapper functions but interface them with a Swift class. The Swift class maintains the object reference and essentially just passes all method and attribute reference calls through the bridge to the C++ object!
Having done this, all of the bridging code is completely encapsulated in the Swift class. Even though we are still using a C bridge, we are effectively using C++ objects transparently without having to resort to recoding them in Objective-C or Objective-C++.
Swift has no C++ interop currently. It's a long-term goal, but is very unlikely to happen in the near future.
In addition to your own solution, there is another way to do it. You can call or directly write C++ code in objective-c++.
So you can create an objective-C++ wrapper on top of your C++ code and create a suitable interface.
Then call objective-C++ code from your swift code. To be able to write objective-C++ code you may have to rename file extension from .m to .mm
Do not forget to release memory allocated by your C++ objects when suitable.
You can use Scapix Language Bridge to automatically bridge C++ to Swift (among other languages). Bridge code automatically generated on the fly directly from C++ header files. Here is an example:
C++:
#include <scapix/bridge/object.h>
class contact : public scapix::bridge::object<contact>
{
public:
std::string name();
void send_message(const std::string& msg, std::shared_ptr<contact> from);
void add_tags(const std::vector<std::string>& tags);
void add_friends(std::vector<std::shared_ptr<contact>> friends);
};
Swift:
class ViewController: UIViewController {
func send(friend: Contact) {
let c = Contact()
contact.sendMessage("Hello", friend)
contact.addTags(["a","b","c"])
contact.addFriends([friend])
}
}
As another answer mentioned, using ObjC++ to interact is much easier. Just name your files .mm instead of .m and xcode/clang, gives you access to c++ in that file.
Note that ObjC++ does not support C++ inheritance. I you want to subclass a c++ class in ObjC++, you can't. You will have to write the subclass in C++ and wrap it around an ObjC++ class.
Then use the bridging header you would normally use to call objc from swift.
Related
I need to use the mbed api but limited to using C. How can I use for example a SPI class in a c file. From looking online to use C++ classes you should create a wrapper function in C++ but as stated I can't use C++, is their another way around this?
How can I use for example a SPI class in a c file.
You cannot use a class† in C.
From looking online to use C++ classes you should create a wrapper function in C++
This is correct.
is their another way around this?
No.
but as stated I can't use C++
Then you're out of options (as far as the standards are concerned). A C++ API (with classes and everything) cannot be used in C. It is possible to create a wrapper interface that uses only features shared by both languages (which excludes all OOP stuff).
That wrapper interface can only be implemented in C++, because it has to interact with the interface that it is wrapping. If the wrapper could be implemented in C, then there would be no need for it. Once that wrapper interface is implemented, it can be used from C.
Some other points:
If a library uses C++, then main must be implemented in C++. That main can also be a trivial wrapper for a C function, which can be called from C++ without fuss.
You must link the dependencies of the C++ library, which may include the C++ standard library
Example:
C++ API
// interface.hpp
class C {
public:
std::string str;
};
C wrapper for the API
// wrapper.h
struct C;
struct C* makeC();
void freeC(struct C*);
void setStr(struct C*, char*);
conts char* getStr(struct C*);
Implementation of the wrapper (in C++)
extern "C" {
#include "wrapper.h"
}
#include "interface.hpp"
C* makeC() { return new C; }
void freeC(C* c) { delete c; }
void setStr(C* c, char* str) { c->str = str; }
const char* getStr(C* c) { return c->str.c_str(); }
Usage in C
struct C* c = makeC();
setStr(c, "test");
puts(getStr(c));
freeC(c);
†Except when the class definition and all of its sub objects use no C++ features whatsoever. Then it is compatible with an identical C struct.
The mbed HAL is written in C, so you can use that without the C++ wrappers. E.g. here is hal/spi_api.h.
Answer is simply - using mbed involves using C++.
If you have to program in C forget about mbed and write your own SPI library or use one of the many available libraries (frameworks) for your target hardware.
There is no other way
If you are limited to use C... just use C and compile it as a C++ file. Most code shall be compatible.
I am told to import my writen class in C++ into a dll and then use that dll in a c# application. Following this guide I created the dll, but I can't simply use it in a C# application since there are some issues concerning it:
What should I place for the return type of my factory function?
What is the equivalent of const wchar_t* which is my constructors argument type?
How can I retrieve and use my functions return type which is of type vector< wstring>?
These are the problems that prevent me from using my C++ DLL inside my C# applications. I was told that I need to create a wrapper with C++/CLI and then use that inside my C#. But sadly I have no idea about it, I don't know C++.net.
The only thing that currently seems to be a bit more sensational to me is to make it somehow compatible with C and then create a C DLL and use that in my C# application. I have read that in C, class object pointers are accessible through HANDLEs, so I thought that would be good idea to get things going without a lot of changes.
So the question is how can I use Handles to access my class objects in C and use them? And how can I convert a vector<wstring> to its C counterpart?
If I want to use CLI to create a wrapper (DLL?) for my C++ DLL, to be used in other dotnet apps what should I do?
In order to make a C wrapper for a C++ class to be used in for example a C# application you can do the following.
In Visual Studio choose Win32 Console Application and Enter a name, Then click next and on the next pane choose DLL and click finish. When you are done you are represented with a DLL project including 3 files.
testdll.h
testdll.cpp
dllmain
Delete everything that exists inside your testdll.h and testdll.cpp files and copy the following contents to each respectively. Add these lines to your testdll.h
// Our C wrapper for creating a dll to be used in C# apps
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the TESTDLL_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// TESTDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif
extern "C"
{
TESTDLL_API int OurTestFunction(int x, int y);
}
It is inside this extern "C" block where you define your interface, functions to access your class member functions.Note the TESTDLL before the function prototype. All of your functions must be proceeded by that.
Add these to your testdll.cpp file:
#include "testdll.h"
#include "ourClass.h"
#define DLL_EXPORT
extern "C"
{
OurClass ourObject;
TESTDLL_API int OurTestFunction(int x, int y)
{
return ourObject.Add(x,y);
}
}
You compile this and get a C based dll which can be used in a C# application.
There are couple of things to notice though, The more important ones are:
You need to understand that the code you use as a proxy- i mean
function definition inside your testdll.h, must only use C
compatible types, it is C after all not C++.
is that you would want to be able to allocate new objects of your
class instead of just using one global object to access all methods.
For this, if you need to pass your class objects between member functions, you need to first convert it to a void* which C can understand and then pass it and use it to access your member functions of whatever.
For example I would have something like this inside my testdll.h in order to make user capable of managing the objects indirectly:
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif
extern "C"
{
TESTDLL_API int OurTestFunction(int x, int y);
TESTDLL_API void* CreateHandle();
TESTDLL_API void* GetCurrentHandle();
TESTDLL_API void DisposeCurrentHandle();
TESTDLL_API void SetCurrentHandle(void* handle);
TESTDLL_API void* GetHandle();
TESTDLL_API void DisposeHandle(void*);
TESTDLL_API void DisposeArrayBuffers(void);
}
And inside my testdll.cpp I would define them as :
#include "testdll.h"
#include "ourClass.h"
#define DLL_EXPORT
extern "C"
{
OurClass *ourObject;
TESTDLL_API int OurTestFunction(int x, int y)
{
//return ourObject.Add(x,y); -- not any more !!
ourObject = reinterpret_cast<OurClass *>(GetHandle());
}
//Handle operations
TESTDLL_API void* CreateHandle()
{
if (ourObject == nullptr)
{
ourObject = new OurClass ;
}
else
{
delete ourObject ;
ourObject = new OurClass ;
}
return reinterpret_cast<void*>(ourObject);
}
TESTDLL_API void* GetCurrentHandle()
{
return reinterpret_cast<void*>(ourObject );
}
TESTDLL_API void DisposeCurrentHandle()
{
delete ourObject ;
ourObject = nullptr;
}
TESTDLL_API void SetCurrentHandle(void* handle)
{
if (handle != nullptr)
{
ourObject = reinterpret_cast<OurClass *>(handle);
}
else
{
ourObject = new OurClass ;
}
}
//factory utility function
TESTDLL_API void* GetHandle()
{
void* handle = GetCurrentHandle();
if (handle != nullptr)
{
return handle;
}
else
{
ourObject = new OurClass ;
handle = reinterpret_cast <void*>(ourObject );
}
return handle;
}
CDLL_API void DisposeHandle(void* handle)
{
OurClass * tmp = reinterpret_cast<OurClass *>(handle);
delete tmp;
}
TESTDLL_API void DisposeArrayBuffers(void)
{
ourObject = reinterpret_cast<OurClass *>(GetHandle());
return ourObject ->DisposeBuffers();//This is a member function defined solely for this purpose of being used inside this wrapper to delete any allocated resources by our class object.
}
}
And when we compile this Dll, we can easily work with it inside our C# application. Before being able to use our functions defined in this dll we need to use appropriate [ImportDll()]. So for our TestDll we would write:
[DllImport(#"TestDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int OurTestFunction(int firstNumber,int secondNumber);
And finally use it like:
private void btnReadBigram_Click(object sender, EventArgs e)
{
int x = OurTestFunction(10,50);
MessageBox.Show(x.ToString());
}
This is all I did to make my C++ class member functions accessible inside a C# application without any hassle.
Note:
When compiling your C# application make sure you have chosen the x86 Platform for compiling your project not AnyCpu.You can change your platform through properties.
Note 2:
For knowing how to create a C++/CLI wrapper for your native C++ class read this: C++/CLI wrapper for your native C++ class.
Using a native C++ class directly from C# is technically possible, but it's not trivial, and it's rarely even a good idea. For starters, you have to know the names to use to import from the DLL, which will be the names after C++ name-mangling. You also can't directly access things like vector from C#.
There are basically two good options:
The first is to write a DLL with a C interface that uses only types that can be marshalled into CLR types. You may use pointers along with the IntPtr type, but you can't really dereference those pointers. You can pretty much just store them in your C# code and then pass them back to the native DLL when needed. And you can also use simple struct types as long as you don't need deep copy to work on them. This option involves using P/Invoke.
The second option is to write a mixed-mode C++/CLI assembly that implements all the logic that needs to access your native code. This assembly can directly access classes and data from your C# code and also directly access your native code, although you should be forewarned that there are annoying breaks where you can't mix the two. For example, a ref class in C++/CLI can't have a shared_ptr member. However, it can have a raw C++ pointer as a member. A (mixed-mode) native class can also have access to a CLR handle type and make calls into the C# code through this. This option involves using C++ Interop.
It's worth noting that you could also go the other way with C++ Interop. You could have your C# code access a mixed-mode C++/CLI assembly that provides a .NET interface to some native code. However, you will still have to do some translation in this case so it's not hugely better than the first option.
A full tutorial on C++ Interop would be rather lengthy. I suggest you read up here and do some further investigation of C++ Interop on Google.
C++/CLI introduces managed objects, for which the pointer token * should be replaced with a ^, and a 'new' should be replaced with 'gcnew', you don't need to delete these objects when you're done with them, they'll be garbage collected, [edit] managed classes have a ref keyword in their definition [/edit].
Wrapping the C++ MyClass class in a C++/CLI wrapper class WrapperCLass could look something like this:
#include <stdio.h>
class MyClass
{
public:
void ShowStuff(const wchar_t *a)
{
wprintf(a);
}
};
public ref class WrapperClass
{
MyClass *wrapped;
public:
WrapperClass()
{
wrapped = new MyClass;
}
~WrapperClass()
{
delete wrapped;
}
void ShowStuff(IntPtr string)
{
wrapped->ShowStuff((const wchar_t *)string.ToPointer());
}
};
If you generate a dll with this, you'll be able to use it as a reference in your C# project
and you won't have to use the factory function mechanism.
In C++/CLI are available, so const wchar_t * is as wel.
To convert a System::String to a const wchar_t * you could use something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Client
{
class Program
{
static void Main(string[] args)
{
WrapperClass w = new WrapperClass();
IntPtr tmp;
w.ShowStuff(tmp = System.Runtime.InteropServices.Marshal.StringToHGlobalUni("Test"));
System.Runtime.InteropServices.Marshal.FreeHGlobal(tmp);
}
}
}
(There could very well be better ways to do this...)
For your return type you'll have to do the conversion in your wrapper class. Make some .net collection, iterate through your vector, convert the wstring to a System::String, and add it to the .net collection, and return that.
I have a program written in C and I need to use KDIS libraries which are written in C++. I compile my C program with automake&friends in KDevelop. How can I compile everything together?? Because I want to call some KDIS functions inside my C program.
Thank you in advance.
If you need to call C++ functions which are not declated extern "C", then you have to do so from a C++ program yourself. You can create one single C++ file in your project which wraps all the library functions you need in extern "C" functions to be used by the rest of your project. You'll have to tell autotools that you're using both C and C++. The file extensions should be enough to decide which is which.
To give you an example, consider the following mymagic.cc creating bindings for some libmagic written in C++:
#include <libmagic/magic.hh>
extern "C" {
int doMagic() {
magic::Wizard w("foo", 42);
magic::Result res = w.doMagic();
return res.getResultCode();
}
}
To the rest of your application, doMagic() would appear as just another C function. But the inside is C++, so it can use any C++ constructs you want. When you need to pass stuff from your library around, you should use pointers to opaque types. So in the header mymagic.h which is also used by your C code, you can write
struct magicValue;
int doMagic(void);
struct magicValue* createMagic(void);
void destroyMagic(struct magicValue*);
And in the mymagic.cc you'd then be more explicit:
struct magicValue {
magic::value v;
magicValue(magic::value val) : v(val) { }
};
magicValue* createMagic() {
return new magicValue(magic::value("foo"));
}
void destroyMagic(magicValue*) {
delete magicValue;
}
This link may help you understand how to mix C and C++ code in your application.
Also, look at this Stack Overflow question, I believe that's what you need.
i found a great post Calling Objective-C method from C++ method?
however, i have to 2 questions, which makes me overcoming this issue very problematic :
note that i have made a change to MyObject-C-Interface.h
#ifndef __MYOBJECT_C_INTERFACE_H__
#define __MYOBJECT_C_INTERFACE_H__ 1
struct CWrap {
void * myObjectInstance;
int MyObjectDoSomethingWith (void *parameter) {
//how to call the
//myObjectInstance->MyObjectDoSomethingWith ???
}
}
#endif
1) how can i call a method on a void * myObjectInstance…
i mean, i cannot cast to MyObject or otherwise let the compiler know, what method to call:(
2) how do i actually use it?
in my, lets say code.m that has both the
#import "MyObject.h"
//and
#include "MyObject-C-Interface.h"
i would do?
MyObject tmp = [[MyObject alloc] init];
CWrap _cWrap;
_cWrap.myObjectInstance = (void *)tmp;
//pass the CWrap to a deep C++ nest
myMainCPPCode->addObjectiveCToCWrap(_cWrap);
and than in my deep C++ code simply call
_cWrap.MyObjectDoSomethingWith((void *)somePrameter)
iam missing a link, and thats, how to link the C wraper function to a ObjectiveC function :(
thank you
i mean, i cannot cast to MyObject or otherwise let the compiler know, what method to call
Why not?
Your C++ wrapper class must be in an Objective-C++ file (usually denoted with the .mm) extension. Then, because you even have to declare your private instance variables in the class declaration, you need a private member to hold the Objective-C pointer in the class header. This must be something that a pure C++ compiler can understand so one thing you could do is this:
#ifndef __MYOBJECT_C_INTERFACE_H__
#define __MYOBJECT_C_INTERFACE_H__ 1
#if defined __OBJC__
typedef id MyObjCClass;
#else
typedef void* MyObjCClass;
#endif
struct CWrap {
MyObjCClass myObjectInstance;
int MyObjectDoSomethingWith (void *parameter);
}
Then in the .mm file
#import "ObjCClassHeader.h"
int CWrap::MyObjectDoSomethingWith(void *parameter)
{
return [myObjectInstance doSomethingWith: parameter];
}
__OBJC__ is a predefined macro that is defined when the compiler is compiling Objective-C or Objective-C++
I have a small C++ application which I imported Objective-C classes. It works as Objective-C++ files, .mm, but any C++ file that includes a header which may end up including some Objective-C header must be renamed to a .mm extension for the proper GCC drivers.
Is there a way to write either a purely C++ wrapper for Objective-C classes or can I separate the Objective-C objects out somehow and just link them separately? Maybe even if the Objective-C classes became a small library I could statically re-link at compile time?
The problem is that this code is cross-platform, and it is more difficult to compile on systems that normally do not use Objective-C (i.e. not Macs). Even though preprocessor commands restrict any implementation of Objective-C code on Windows or Linux, the original code still has .mm extensions and GCC still treats the code as Objective-C++.
Usually you simply wrap your Objective-C classes with C++ classes by e.g. using opaque pointers and forwarding calls to C++ methods to Objective-C methods.
That way your portable C++ sources never have to see any Objective-C includes and ideally you only have to swap out the implementation files for the wrappers on different platforms.
Example:
// c++ header:
class Wrapper {
struct Opaque;
Opaque* opaque;
// ...
public:
void f();
};
// Objective-C++ source on Mac:
struct Wrapper::Opaque {
id contained;
// ...
};
void Wrapper::f() {
[opaque->contained f];
}
// ...
Yes, that's easily possible, both ways, if you know a few tricks:
1) The "id" type is actually defined in a plain C header. So you can do the following:
In your header:
#include <objc/objc.h>
class MyWindow
{
public:
MyWindow();
~MyWindow();
protected:
id mCocoaWindow;
};
In your implementation (.mm):
#include "MyWindow.h"
#include <Cocoa/Cocoa.h>
MyWindow::MyWindow()
{
mCocoaWindow = [[NSWindow alloc] init];
}
MyWindow::~MyWindow()
{
[mCocoaWindow release];
mCocoaWindow = nil;
}
2) There are two preprocessor constants you can use to exclude C++/ObjC-specific code when a source file includes them that is one of the two, but not ObjC++:
#if __OBJC__
// ObjC code goes here.
#endif /* __OBJC__*/
#if __cplusplus
// C++ code goes here.
#endif
Just be careful, you can't just add/remove ivars or virtual methods with an #ifdef, that will create two classes with different memory layouts and make your app crash in very weird ways.
3) You can use a pointer to a struct without declaring its contents:
In your header:
#interface MyCppObjectWrapper : NSObject
{
struct MyCppObjectWrapperIVars *ivars; // This is straight ObjC, no ++.
}
#end
In your implementation file (.mm):
struct MyCppObjectWrapperIVars
{
std::string myCppString1;
std::string myCppString2;
std::string myCppString3;
};
#implementation MyCppObjectWrapper
-(id) init
{
if(( self = [super init] ))
{
ivars = new MyCppObjectWrapperIVars;
}
return self;
}
-(void) dealloc
{
delete ivars;
ivars = NULL;
[super dealloc];
}
#end
This will make your header simple standard C or ObjC, while your implementation file gets constructors/destructors of all ivars called without you having to create/delete each one as an object on the heap.
This is all only the Mac side of things, but this would mean that you could keep the ObjC stuff out of your headers, or at least make it compile when used from cross-platform client files of the Mac implementation of your C++ portability layer.