简体   繁体   中英

Linker problem using Objective-C++ with Objective-C

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

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 */

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM