Undefined symbols when calling ObjC++ method from C++ - c++

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?

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.

Related

Vscode terminal message

I use mac vscode, and try to run the following file. When the error message pops up, the phrases are partially strange and not meaningful. Is there a way to change setting of vscode so that the output of my error message becomes normal again, something like Parent.class, Parent.h ... instead of Zn3_Parent...?
Below is the code I run:
#include <iostream>
using namespace std;
class Parent {
public :
virtual int func () = 0;
virtual ~Parent();
};
class Child : public Parent {
public :
int data;
Child (int k) {
data = k;
}
int func() { // virtual function
cout<<"Returning square of 10\n";
return 10*10;
}
void Display () {
cout<<data<<"\n";
}
~ Child() {
cout<<"Overridden Parents Destructor \n";
}
};
int main() {
Child a(10);
a.Display();
//cout << "asdf";
return 1;
}
And the output I get:
Undefined symbols for architecture x86_64:
"__ZN6ParentD2Ev", referenced from:
__ZN5ChildD1Ev in ccn2pmId.o
"__ZTI6Parent", referenced from:
__ZTI5Child in ccn2pmId.o
"__ZTV6Parent", referenced from:
__ZN6ParentC2Ev in ccn2pmId.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
I don't want those things like __ZN6, ZTI6, ZTV6.

undefined reference to pthread create even with lpthread [duplicate]

This question already has answers here:
Difference between -pthread and -lpthread while compiling
(3 answers)
Closed 4 years ago.
I want to make use of pthread ad hence use the -lpthread flag to compile, but here's what I get:
$ g++ -lpthread pseudo_code.cpp
/tmp/cc3mPrvt.o: In function `MyThreadClass::StartInternalThread()':
pseudo_code.cpp:(.text._ZN13MyThreadClass19StartInternalThreadEv[_ZN13MyThreadClass19StartInternalThreadEv]+0x26): undefined reference to `pthread_create'
collect2: error: ld returned 1 exit status
The code I try to compile is below:
#include <pthread.h>
#include <iostream>
#include <vector>
#define OK 0
#define ERROR -1
//-- ThreadClass
class MyThreadClass
{
public:
MyThreadClass() {/* empty */}
virtual ~MyThreadClass() {/* empty */}
/** Returns true if the thread was successfully started, false if there was an error starting the thread */
bool StartInternalThread()
{
return (pthread_create(&_thread, NULL, InternalThreadEntryFunc, this) == 0);
}
/** Will not return until the internal thread has exited. */
void WaitForInternalThreadToExit()
{
(void) pthread_join(_thread, NULL);
}
protected:
/** Implement this method in your subclass with the code you want your thread to run. */
virtual void InternalThreadEntry() = 0;
private:
static void * InternalThreadEntryFunc(void * This) {
((MyThreadClass *)This)->InternalThreadEntry(); return NULL;
}
pthread_t _thread;
};
//-- /ThreadClass
//--- DUMMY DECLARATIONS BELOW TO MAKE IT COMPILE ---//
#define LOG_NS_ERROR std::cout
class test{
public:
int get_child(std::string x){return OK;};
};
test *_global;
typedef struct test_struct{} _db_transact;
class db_transact{
public:
db_transact(int,int&,int&){};
};
int _ns;
int _log_id;
//--- DUMMY DECLARATIONS ABOVE TO MAKE IT COMPILE ---//
class db_c_hndlr : public MyThreadClass{
public:
db_c_hndlr(void);
~db_c_hndlr(void);
db_transact *db_conn_get(void);
void InternalThreadEntry(void *func);
private:
int _stop;
std::vector<db_transact*> _db_pool;
};
//---------------------------------------------------------
db_c_hndlr::db_c_hndlr(void) {
}
//---------------------------------------------------------
void db_c_hndlr::InternatThreadEntry(void *func) {
while(!stop){
std::cout << "going!" << std::endl;
sleep(1);
}
}
//---------------------------------------------------------
db_c_hndlr::~db_c_hndlr() {
int i = 0;
std::vector<db_transact*>::iterator it;
for (i=0, it = _db_pool.begin();it!=_db_pool.end();it++, i++) {
if (_db_pool[i])
if (_db_pool[i]!=NULL)
delete _db_pool[i];
}
}
//---------------------------------------------------------
db_transact *db_c_hndlr::db_conn_get(void) {
db_transact *tmp;
tmp = new db_transact(_global->get_child("db_config"), _ns, _log_id);
_db_pool.push_back(tmp);
return tmp;
}
//---------------------------------------------------------
int main(void)
{
db_transact *conn=NULL;
db_c_hndlr db;
//db = new db_c_hndlr();
conn= db.db_conn_get();
return OK;
}
Probably you need to do this:
extern "C" {
#include <pthread.h>
}
That tells the compiler that this header is for a C library, and that it should not use C++ name mangling.
You also need to use -pthread instead of -lpthread, because the pthread library is special and GCC wants to explicitly know you are trying to use threads, not simply link against libpthread.
Please try to compile with the command.
g++ pseudo_code.cpp -lpthread
It makes a difference where in the command you write this option; the
linker searches and processes libraries and object files in the order
they are specified. Thus, foo.o -lz bar.o searches library z after
file foo.o but before bar.o. If bar.o refers to functions in z, those
functions may not be loaded.
It worked for me. It seems, needs to specify the library after the source file so that symbols are searched in the library.

Setting a calling convention for std::function

I'm very new to using std and I'm currently trying to call into a function that takes an std::function as a param. Something similar to below:
In the .h file in one lib:
typedef bool t (/*Params*/);
void __stdcall Foo(std::function<t> &function) {m_function = function;}
std::function<t> m_function;
I imported the lib and tried to use Foo in another cpp file:
bool Implementation (/*Params*/)
{
// Implementation
}
void Bar()
{
Foo(std::function<t> (Implementation));
}
I'm getting a linker error (LNK2019) when I compile for x86 (but not x64) because of the calling convention:
Unresolved External Symbol __stdcall Foo (class std::tr1::function<bool __cdecl(/*Params*/) const&)
From this I gathered that I need to mark "t" and Implementation as __stdcall but doing so causes other compile failures. I should also note the code compiled correctly when it was being built in the same lib. Is there a way to associate a calling convention to an std::function?
Try:
void Foo(const std::function<bool()> &func)
{
func();
}
bool Implementation (/*Params*/)
{
cout << "Implementation"<<endl;
return true;
}
void Bar()
{
Foo(std::function<bool()>(&Implementation));
}
int main()
{
Bar();
return 0;
}

Linking error for a naive singleton class in C++

My code is:
class cMySingleton{
private:
static bool bInstantiated;
int mInt;
cMySingleton(){
mInt=0;
}
public:
cMySingleton(int c){
if (bInstantiated){
cout << "you can only instantiated once";
}
else {
cMySingleton();
mInt=c;
}
}
};
int main () {
cMySingleton s(5);
cMySingleton t(6);
}
The linker keeps complaining:
Undefined symbols for architecture x86_64:
"cMySingleton::bInstantiated", referenced from:
cMySingleton::cMySingleton(int) 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)
What is going on? C++ novice here~~
you should initialize static field.
http://ideone.com/Y1huV
#include <iostream>
class cMySingleton{
private:
static bool bInstantiated;
int mInt;
cMySingleton(){
mInt=0;
}
public:
cMySingleton(int c){
if (bInstantiated){
std::cout << "you can only instantiated once";
}
else {
cMySingleton();
mInt=c;
}
}
};
bool cMySingleton::bInstantiated = true;
int main () {
cMySingleton s(5);
cMySingleton t(6);
}
More information you can be find here:
Static Data Member Initialization
there was also missing include and std:: around cout.
Initialize
static bool bInstantiated;
outside of cMySingleton
bool CMySingleton::bInstantiated;
Dont forget to initialize your static member outside of your class declaration in .cpp file:
bool cMySingleton::bInstantiated = false;

Understanding template classes in c++ - problem with new-operator

Dear all, I've been stuck with this problem now for a few days and my searches were not successful.
What I am trying to do:
I want a template reader class (VariableReader) to handle different types of variables (usually unsigned int and pointers to vector).
I started with
#ifndef READER_H_
#define READER_H_
#include <string>
namespace BAT {
template <typename variableType = unsigned int>
class VariableReader {
public:
VariableReader<variableType>();
VariableReader<variableType>(std::string varName);
virtual ~VariableReader<variableType>();
std::string getVariableName();
void setVariableName(std::string varName);
bool isValidVariableName(std::string varName);
variableType getVariable();
private:
std::string variableName;
variableType variable;
};
}
#endif
and
#include "../../interface/Readers/VariableReader.h"
namespace BAT {
template<typename variableType>
VariableReader<variableType>::VariableReader() :
variableName("") {
// TODO Auto-generated constructor stub
}
template <typename variableType>
VariableReader<variableType>::VariableReader(std::string varName) :
variableName(varName) {
}
template <typename variableType>
std::string VariableReader<variableType>::getVariableName() {
return variableName;
}
template <typename variableType>
void VariableReader<variableType>::setVariableName(std::string varName) {
if (VariableReader::isValidVariableName(varName)) {
variableName = varName;
}
}
template <typename variableType>
bool VariableReader<variableType>::isValidVariableName(std::string varName) {
return varName != "";
}
template <typename variableType>
VariableReader<variableType>::~VariableReader() {
// TODO Auto-generated destructor stub
}
}
However, although it seems to compile I can't use it within other projects.
EDIT: forgot to post test-code:
#include "cute.h"
#include "ide_listener.h"
#include "cute_runner.h"
#include "Readers/VariableReader.h"
using namespace BAT;
static VariableReader<int> *reader;
void setUp(){
reader = new VariableReader<int>::VariableReader();//this is problem-line
}
void thisIsATest() {
ASSERTM("start writing tests", false);
}
void runSuite(){
cute::suite s;
//TODO add your test here
s.push_back(CUTE(thisIsATest));
cute::ide_listener lis;
cute::makeRunner(lis)(s, "The Suite");
}
int main(){
runSuite();
}
I get following error message:
Building target: BAT_Tests
Invoking: GCC C++ Linker
g++ -L"/workspace/BAT/Debug Gcov" -fprofile-arcs -ftest-coverage -std=c99 -o"BAT_Tests" ./src/Test.o -lBAT
./src/Test.o: In function `setUp()':
/workspace/BAT_Tests/Debug Gcov/../src/Test.cpp:13: undefined reference to `BAT::VariableReader<int>::VariableReader()'
collect2: ld returned 1 exit status
make: *** [BAT_Tests] Error 1
As I understand it the linker tries to find the constructor for VariableReader, which is not explicitly defined since I want to have a general constructor only.
Please help me to understand what I am missing.
The C++ FAQ Lite section on How can I avoid linker errors with my template functions? shows two solutions:
Move the template class's methods into the .h file (or a file included by the .h file).
Instantiate the template in the .cpp file using template VariableReader<unsigned int>;.
The constructor(s) and destructor doesn't need the template arguments in it. In addition, template classes must have the full source available to compile- you can't declare the members and define them in another translation unit like you can with normal classes.