Reputation: 7701
Currently I have an iOS project which is using Objective-C. For performance reasons I have implemented Objective-C++ code which looks like the following:
base11.mm
#include <string>
#include "base11.h"
static const std::string characters = "0123456789_";
const char* to_base11(long n) {
// some c++ code here
}
long from_base11(const char* input) {
// some c++ code here
}
base11.h
#ifndef base11_h
#define base11_h
#include <stdio.h>
const char* to_base11(long n);
long from_base11(const char* input);
#endif /* base11_h */
Of course, I used the .mm
extension for the class, and I am only using plain C function parameters and return types.
Then I have an Objective-C class which wraps these C++ functions in the following methods:
Util.m
#include "base11.h"
+(NSString*) convertBase10ToBase11:(long) base10 {
const char* base11 = to_base11(base10);
return [NSString stringWithUTF8String:base11];
}
+(NSNumber*) convertBase11ToBase10:(NSString*) base11 {
const char* input = [base11 UTF8String];
return @(from_base11(input));
}
And the Util.h:
@interface Util : NSObject
+(NSString*) convertBase10ToBase11:(long) base10;
+(NSNumber*) convertBase11ToBase10:(NSString*) base11;
@end
However this gives the following compilation error:
Undefined symbols for architecture x86_64:
"_from_base11", referenced from:
+[Util convertBase11ToBase10:] in Util.o
"_to_base11", referenced from:
+[Util convertBase10ToBase11:] in Util.o
ld: symbol(s) not found for architecture x86_64
However, this is very weird. I have chosen to NOT use the .mm
extension for the Util.m
class since I don't use any C++ code there. Also note that the base11.h
header file is not using any C++ code as well. So, why do I get this error? According to this post my approach should be correct:
How to call a method on .mm file from a objective c class
Upvotes: 1
Views: 726
Reputation: 4585
This is problem in function's symbol name. C++ allows functions with same name and different prototype. So when functions compiled with C++/Objective-C++ it got symbol name that describes it prototype and makes it unique.
So you need to force compiler use C's symbol name.
You can achieve that by adding extern "C"
before function prototype.
But it's not very convenient if you use this header in both C and C++ source files, because C doesn't know what it is extern "C"
.
Luckily CoreFoundation
already have solved this issue. You can peep how they declared their CFString.h
, CFArray.h
.
So you just need use CoreFoundation's macro: CF_EXTERN_C_BEGIN
and CF_EXTERN_C_END
.
#ifndef base11_h
#define base11_h
#include <stdio.h>
#include <CoreFoundation/CFBase.h>
CF_IMPLICIT_BRIDGING_ENABLED
CF_EXTERN_C_BEGIN
const char* to_base11(long n);
long from_base11(const char* input);
CF_EXTERN_C_END
CF_IMPLICIT_BRIDGING_DISABLED
#endif /* base11_h */
Upvotes: 3