- Home /
iOS Objective C plugin linker error
I'm trying to get a simple objective C iOS plugin working and am having problems with linker errors. There's various discussions about this but no clear simple working samples that I can find. See my code below. I'm getting the following error:
"__getO2", referenced from: RegisterMonoModules() in RegisterMonoModules.o ld: symbol(s) not found for architecture armv7 clang: error: linker command failed with exit code 1 (use -v to see invocation) Here's my code. (Note that it's the .h and .m files that don't work. If I replace the .h and .m with the .mm file it runs perfectly): Assets/Scripts/CubeLevitate.cs:Undefined symbols for architecture armv7:
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
public class CubeLevitate : MonoBehaviour {
[DllImport ("__Internal")]
private static extern float _getO2();
private float o2Val;
void Start () {
o2Val = getO2();
Debug.Log("Return Float = " + o2Val);
}
void Update () {
}
float getO2()
{
if (Application.platform == RuntimePlatform.IPhonePlayer)
return _getO2();
else
return 95f;
}
}
Assets/Plugins/iOS/O2Plugin.h: #import
@interface O2Plugin : NSObject
{ float _getO2; }
@end Assets/Plugins/iOS/O2Plugin.m: #import "O2Plugin.h"
@implementation O2Plugin
-(float)_getO2 { return 98.2f; }
@end Assets/Plugins/iOS/O2Plugin.mm (this works when I replace the .h and .m above with this C++ code, but I want to use Objective C directly. Do I really have to call the obj C from C++?? extern "C" {
float _getO2(void) { return 98.2f; }
bool _initializeBT(void) {
} }
I am not a ObjC expert (not even a novice) but check if there is a language feature for exporting types or APIs just like you do with C's extern
keyword. Also your ObjC getter appear to exist inside a class (again I am not even a novice so only kick me when I am laying down :-)) so I would guess you'd have to specify which class, which method (and if it is not a static method, which object)
Answer by beopaul · Dec 22, 2013 at 04:09 PM
Got it working!
Now calling from C++
Changed extension from .m to .mm to accommodate C++ code
Now instantiating the class. Doh!
Here's the fixed code in Assets/Plugins/iOS/O2Plugin.mm:
#import "O2Plugin.h"
@implementation O2Plugin
static O2Plugin* _O2PluginSingleton = nil;
+ (O2Plugin *) O2PluginSingleton
{
@synchronized([O2Plugin class])
{
if (!_O2PluginSingleton)
{
_O2PluginSingleton = [[self alloc] init];
}
return _O2PluginSingleton;
}
return nil;
}
-(float) _getO2
{
return 98.2f;
}
@end
extern "C"
{
float PGgetO2()
{
return [[O2Plugin O2PluginSingleton] _getO2];
}
}
Glad to hear you found a solution!
I noticed while moderating the posts here on Answers that you sent a couple of duplicate answers to your question. For new users with Low $$anonymous$$arma, all posts are moderated and users with high enough $$anonymous$$arma can approve or reject posts to keep the site clean from bots and the likes. So if you post an answer and don't see it show up instantly, it's because it's awaiting moderation. Accept your own answer to build up a little $$anonymous$$arma and you'll soon be able to post without having to go through moderation :)
Answer by vladimirg · Dec 22, 2013 at 09:34 AM
Do I really have to call the obj C from C++??
Yes. The documentation is pretty clear on this. (You think that's annoying? Wait until you'll need to pass complex structures to and forth and P/Invoke...)
As for samples, take a look at existing plugins, such as Facebook's.
EDIT: the simple "Yes" given at the beginning is technically wrong (oops). You don't have to use C++ for this, though Objective-C++ is natural for this purpose (as Unity's own files are .mm). You could use Objective C, but as Objective C method calls are actually message passes (which call the C function objc_msgSend behind the scenes), your C/C# interface still has to go through vanilla C functions, which can then use all the nice runtime Objective C facilities. (Technically, since Objective C is a superset of C, you can say that C# is calling Objective C directly! But that's misleading, as only functions can be invoked this way, not methods.)
Still, apart from the use of the extern keyword, this is mostly an academic point, since using C doesn't make your life any user.
And yes, the docs are not too clear, but they're still correct, in their own way.
Could you please clarify how the doc is clear on this as I had some trouble finding that in the docs you linked to. The docs even state the following:
If you are using C++ (.cpp) or Objective-C++ (.mm) to implement the plugin you must ensure the functions are declared with C linkage to avoid name mangling issues.
Plugins written in C or Objective-C do not need this since these languages do not use name-mangling.
From my best understanding, ObjC should be callable directly from C#, using P/Invoke.
Yup, I read the same text referenced above (regarding plugins written in Objective-C not needing C linkage otherwise needed to prevent name mangling), thus implying that ObjC can be directly linked. I'd love to see a simple example showing this to be the case, though it's largely academic at this point now that I got things working.
@Statement, you're right, I updated the answer. @beopaul, Objective C can be directly used, just not in a way that gives you the power you need. You still have to write a wrapper, and then it may as well be in Objective C++. Even if you write it in (Objective) C, you have to go through the same motions as with Objective C++.
Your answer
Follow this Question
Related Questions
Call Unity class in XCode 1 Answer
Unity iPhone plugin - what data type to use? 1 Answer
UnitySendMessage and NSString allocation 1 Answer