1

I'm following this answer here to build a TurboModule for React Native using C++

However, I need to use an Apple library that is only available in the AVFoundation framework which only works for Obj-C and C++

Therefore, I thought I could call Obj-C++ methods from regular C++ or at least a lot of the internet answers I've seen tells me that I can.

Nonetheless, when I try to compile my TurboModule, I get the following error:

stderr: Undefined symbols for architecture x86_64:
  "MyClassImpl::doSomethingWith(void*)", referenced from:
      MyCPPClass::doSomethingWithMyClass() in libOneRecognizerTurboModuleApple--830559412.a(MyCPPClass.cpp.o)
  "MyClassImpl::logMyMessage(char*)", referenced from:
      MyCPPClass::doSomethingWithMyClass() in libOneRecognizerTurboModuleApple--830559412.a(MyCPPClass.cpp.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

The way that I'm putting this together is with the following files:

MyObject-C-Interface.h

#ifndef __MYOBJECT_C_INTERFACE_H__
#define __MYOBJECT_C_INTERFACE_H__

class MyClassImpl {
 public:
  MyClassImpl(void);
  ~MyClassImpl(void);

  void init(void);
  int doSomethingWith(void* aParameter);
  void logMyMessage(char* aCStr);

 private:
  void* self;
};

#endif

MyObject.h

#import "MyObject-C-Interface.h"

@interface MyObject : NSObject {
  int someVar;
}

- (int)doSomethingWith:(void*)aParameter;
- (void)logMyMessage:(char*)aCStr;

@end

MyObject.mm

#import "MyObject.h"

@implementation MyObject

MyClassImpl::MyClassImpl(void) : self(NULL) {}

MyClassImpl::~MyClassImpl(void) {
  [(id)self dealloc];
}

void MyClassImpl::init(void) {
  self = [[MyObject alloc] init];
}

int MyClassImpl::doSomethingWith(void* aParameter) {
  return [(id)self doSomethingWith:aParameter];
}

void MyClassImpl::logMyMessage(char* aCStr) {
  [(id)self doLogMessage:aCStr];
}

- (int)doSomethingWith:(void*)aParameter {
  int result;
  return result;
}

- (void)logMyMessage:(char*)aCStr {
  NSLog(aCStr);
}

@end

MyCppClass.h

#ifndef __MYCPP_CLASS_H__
#define __MYCPP_CLASS_H__

class MyClassImpl;

class MyCPPClass {
  enum { cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING = 42 };

 public:
  MyCPPClass(void);
  ~MyCPPClass(void);

  void init(void);
  int doSomethingWithMyClass(void);

 private:
  MyClassImpl* _impl;
  int _myValue;
};

#endif

MyCppClass.cpp

#include "MyCPPClass.h"
#include "MyObject-C-Interface.h"

MyCPPClass::MyCPPClass(void) : _impl(NULL) {}

void MyCPPClass::init(void) {
  _impl = new MyClassImpl();
}

MyCPPClass::~MyCPPClass(void) {
  if (_impl) {
    delete _impl;
    _impl = NULL;
  }
}

int MyCPPClass::doSomethingWithMyClass(void) {
  int result = _impl->doSomethingWith(&_myValue);
  if (result == cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING) {
    _impl->logMyMessage((char*)"Hello, Arthur!");
  } else {
    _impl->logMyMessage((char*)"Don't worry.");
  }
  return result;
}

And calling it this way from my TurboModule:

MyTurboModule.cpp

#include "MyCPPClass.h"

// rest of libraries

jsi::Value OneRecognizerTurboModule::getValueWithPromise(
    jsi::Runtime& rt,
    bool error) {
  return createPromiseAsJSIValue(
      rt, [error](jsi::Runtime& rt2, std::shared_ptr<Promise> promise) {
        if (error) {
          promise->reject("intentional promise rejection");
        } else {
          MyCPPClass* css;
          css = new MyCPPClass();
          css->doSomethingWithMyClass();
          promise->resolve(jsi::String::createFromUtf8(rt2, "hello from c++!"));
        }
      });
}

I think that should work, but the linker is complaining that the symbols are undefined for my architecture. I browsed on the internet that this error is ambiguous and has nothing to do with my architecture and more to do with the way that I'm calling the function, but I'm completely new to C++ so I'm not sure what I'm doing wrong.

What's wrong with the way I'm calling the ObjC++ method in my implementation?

ILikeTacos
  • 17,464
  • 20
  • 58
  • 88

1 Answers1

0

It sounds to me as if your MyObject.mm file is either not being compiled, or its object code is not being linked into your final binary.

  • If you're using Xcode, make sure this source file is a member of your target. (It should show up in the "Compile Sources" section of your target's "Build Phases")
  • If using another build system, ensure that .mm files are built using the correct compiler (clang in the correct mode - i.e. -ObjC++) and that the resulting object code file (MyObject.o) is included in the link step.
pmdj
  • 22,018
  • 3
  • 52
  • 103