1

Given this MVP code:

objc_funcs.h

#import <Foundation/Foundation.h>
NSString* doFoo(void);

objc_funcs.m

#import <Foundation/Foundation.h>
NSString* doFoo()
{
    return @"fffuuu";
}

main.mm

#import "objc_funcs.h"

int main(int argc, char * argv[]) {
    doFoo();
    return 0;
}

If I leave it this way, the build will result in

Undefined symbols for architecture x86_64:
  "doFoo()", referenced from:
      _main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Though if I rename main.mm -> main.m, the build will go just fine.

WAIDW?

apollov
  • 117
  • 9

2 Answers2

1

You have to make it valid for C++ compiler by either converting objc_funcs to .mm file or wrapping the import in main.mm with extern "C" {}:

extern "C" {
#import "objc_funcs.h"
}

You could read more about it here

ScorpiCon
  • 474
  • 2
  • 6
1

The problem relates to C vs C++ linkage.

The normal way this is handled in C headers is testing for the __cplusplus preprocessor macro and inserting an extern "C" if needed. CoreFoundation provides the CF_EXTERN_C_BEGIN and CF_EXTERN_C_END macros that handle this:

#if !defined(CF_EXTERN_C_BEGIN)
#if defined(__cplusplus)
#define CF_EXTERN_C_BEGIN extern "C" {
#define CF_EXTERN_C_END   }
#else
#define CF_EXTERN_C_BEGIN
#define CF_EXTERN_C_END
#endif
#endif

Using these your objc_funcs.h becomes:

#import <Foundation/Foundation.h>
CF_EXTERN_C_BEGIN
NSString* doFoo(void);
CF_EXTERN_C_END

if you don't want to use them you could use

#import <Foundation/Foundation.h>
#ifdef __cplusplus
extern "C"
#endif
NSString* doFoo(void);
sbooth
  • 16,646
  • 2
  • 55
  • 81