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.
Related
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.
I use SWIG to bind C++ classes so I can use them in Lua.
I wonder if it's possible to handle construction failure of C++ class in Lua.
For example, I have the following Test class which tries to get the Userdata when it's constructed.
void *getUserdata(lua_State *L, const char *key)
{
lua_pushstring(L, key);
lua_gettable(L, LUA_REGISTRYINDEX);
return lua_touserdata(L, -1);
}
class Test
{
public:
Test(lua_State *L)
:data(static_cast<MyData *>(getUserdata(L, "my_name"))){};
void setDataNum(int num)
{
data->num = num;
}
private:
MyData *data;
};
However, if getUserdata() returns nullptr, calling setDataNum() crashes my application.
I wonder if there's any way to detect and handle the construction failure(data becoming nullptr in this case) so the class won't create in Lua.
The first step to error handling would be to check for the error. From the Lua reference manual:
void *lua_touserdata (lua_State *L, int index);
If the value at the given index is a full userdata, returns its block address. If the value is a light userdata, returns its pointer. Otherwise, returns NULL.
That means we can easily check whether the call succeeded by checking data for being NULL. Then we can act accordingly, I choose to throw an exception.
test.hpp
#pragma once
#include <stdexcept>
#include <lua.hpp>
struct MyData {
int num;
};
void *getUserdata(lua_State *L, const char *key) {
lua_pushstring(L, key);
lua_gettable(L, LUA_REGISTRYINDEX);
return lua_touserdata(L, -1);
}
class Test {
public:
Test(lua_State *L)
: data(static_cast<MyData *>(getUserdata(L, "my_name"))) {
if (data == nullptr) {
throw std::runtime_error("invalid userdata at \"my_name\"");
}
};
void setDataNum(int num) { data->num = num; }
private:
MyData *data;
};
This exception is not digestible by Lua and by default the interpreter will just crash with terminate called after throwing an instance of 'std::runtime_error'. This is not so nice and we rather want to have the exception converted to a Lua error. SWIG comes with support for that.
test.i
%module example
%{
#include "test.hpp"
%}
%include <exception.i>
%exception {
try {
$action
} catch (std::exception const &e) {
SWIG_exception(SWIG_RuntimeError, e.what());
}
}
%typemap(default) (lua_State *L) { $1 = L; }
%include "test.hpp"
Lua doesn't have exceptions and thus no try-catch blocks. Instead Lua has the concept of a protected call with pcall. This will return a flag whether the call was successful and the result of the call or an error.
local example = require("example")
local success, c = pcall(example.Test)
if (success) then
c:setDataNum(1)
else
print(c)
end
Example invocation:
$ swig -c++ -lua test.i
$ clang++ -Wall -Wextra -Wpedantic -I /usr/include/lua5.2 -fPIC -shared test_wrap.cxx -o example.so -llua5.2
$ lua5.2 test.lua
SWIG_RuntimeError:invalid userdata at "my_name"
I am currently working on a virtual run time environment program that is at a very early stage, i am prevented from continuing my work due to a linker error when using my makefile, provided below. The error i am receiving is:
g++ controller.o processor.o test.o -o final
controller.o: In function `Controller::run()':
controller.cpp:(.text+0x1e0): undefined reference to
Processor::codeParams(char)'
controller.o: In function `Controller::fetch()':
controller.cpp:(.text+0x290): undefined reference to `Controller::pc'
controller.cpp:(.text+0x299): undefined reference to `Controller::pc'
collect2: error: ld returned 1 exit status
makefile:16: recipe for target 'final' failed
make: *** [final] Error 1
I am unsure as to why i get this error as i thought i had defined these things in the source file corresponding to the header. All files will be given below so that the program can be compiled.
test.cpp:
#include <iostream>
#include <vector>
#include "includes/controller.h"
using namespace std;
int main()
{
vector<char> prog = {0x0};
Controller contr(prog);
cout << "Error Code: " << contr.run() << endl;
return 0;
}
controller.cpp:
/*
Author(s): James Dolan
File: controller.cpp
Build: 0.0.0
Header: includes/controller.h
DoLR: 21:39 11/1/2017
Todo: n/a
*/
#include "includes/controller.h"
Controller::Controller(vector<char> prog)
{
printf("Program:"); //Display program
for(auto i : program)
{
printf("%02X", i);
}
printf("\n");
Controller::program = program;
}
Controller::~Controller ()
{
}
int Controller::run()
{
bool runFlag = true;
int errorCode = 0;
char curCode;
vector<char> curInstr;
int paramRef;
while(runFlag)
{
curCode = fetch();
printf("curCode:%02X\n", curCode);
curInstr.push_back(curCode);
paramRef = proc.codeParams(curCode);
if (paramRef == 0xffff){runFlag = false; continue;} //Check if shutdown signal was returned, if so shutdown
printf("opcode good\n");
for(int i; i<paramRef; i++){curInstr.push_back(fetch());}
}
return errorCode;
}
char Controller::fetch()
{
return program[pc++]; //Return next instruction then increment the program counter
}
controller.h:
/*
Author(s): James Dolan
File: controller.h
Source: ../controller.cpp
DoLR: 21:39 11/1/2017
Todo: n/a
*/
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <iostream>
#include <vector>
#include <cstdlib>
#include "processor.h"
using namespace std;
class Controller{
public:
Controller(vector<char> prog);
~Controller();
int run();
protected:
private:
vector<char> program;
static int pc;
char fetch();
Processor proc();
};
#endif
processor.cpp:
#include "includes/processor.h"
Processor::Processor()
{
}
Processor::~Processor()
{
}
int codeParams(char code)
{
switch(code)
{
case 0x0: //Halt
return 0;
default:
printf("[ERROR!] Invalid opcode [%02X]", code);
return 0xffff; //Return shutdown signal
}
}
processor.h:
#ifndef PROCESSOR_H
#define PROCESSOR_H
#include <iostream>
#include <cstdlib>
class Processor{
public:
Processor();
~Processor();
int codeParams(char code);
protected:
private:
};
#endif
All if any help is appreciated massively as it will help me to continue with my passion of developing a fully fledged open-source virtual runtime enviroment like the java vm, thank you for your time.
In Controller.cpp you need a int Controller::pc; or int Controller::pc = 0;
In the header file you declared a static int named pc that exists somewhere. It needs to actually exist in a translation unit somewhere (in this case Controller.cpp) so that when the linker tries to find it... it exists.
In Processor.cpp your signature should look like int Processor::codeParams(char code) to let the compiler know that is Processor's codeParams and not a random function named codeParams that happens to also take a character.
For the member function Processor::codeParams you should define it as:
int Processor::codeParams(char code)
// ~~~~~~~~~~~
{
...
}
Otherwise it's just a normal (non–member) function.
For the static member Controller::pc you should define it outside of the class definition, in controller.cpp.
// Controller.h
class Controller {
...
private:
static int pc;
};
// controller.cpp
int Controller::pc;
Here's a simple set of files that reproduce the problem I'm having:
c.h:
void dummy();
c.cpp:
#include <stdio.h>
extern "C" {
#include "c.h"
}
class Bubu {
public:
static Bubu *getInstance() {
if (_instance == NULL) {
_instance = new Bubu;
}
return _instance;
}
private:
static Bubu *_instance;
};
Bubu *_instance = NULL;
void dummy() {
printf("bubu called\n");
Bubu *ptr = Bubu::getInstance();
}
main.cpp:
extern "C" {
#include "c.h"
}
int main() {
dummy();
return 0;
}
When I compile I get this:
g++ -W -Wall -c c.cpp -o c.o
c.cpp: In function ‘int bubu()’:
c.cpp:24: warning: unused variable ‘ptr’
g++ -W -Wall main.cpp c.o -o main
c.o: In function `Bubu::getInstance()':
c.cpp:(.text._ZN4Bubu11getInstanceEv[Bubu::getInstance()]+0x7): undefined reference to `Bubu::_instance'
c.cpp:(.text._ZN4Bubu11getInstanceEv[Bubu::getInstance()]+0x1d): undefined reference to `Bubu::_instance'
c.cpp:(.text._ZN4Bubu11getInstanceEv[Bubu::getInstance()]+0x24): undefined reference to `Bubu::_instance'
collect2: ld returned 1 exit status
make: *** [main] Error 1
Compilation exited abnormally with code 2 at Tue Dec 15 09:15:21
I've seen the answer to other similar questions but there the problem is either a missing Bubu:: when calling the static method or lack of initialisation of the static member outside the class declaration or missing the extern "C" construct. I'm fairly certain that I'm not making those mistakes ... I'm definitely making other(s).
Can you please explain what's going on?
When you define a static variable inside a class, you have to define it outside the class also. You tried to do this, but
Bubu *_instance = NULL;
will just make a global pointer to Bubu, not instantiate the static one inside the class. You need to use
Bubu *Bubu::_instance = NULL;
to tell the compiler this will be the static variable inside the class.
I'm new with C++ pthreads. What I'm trying to do is use one thread to catch UDP packets and put it into a queue, and another one to process them and send them after. My question is, how can I push/pop elements into/from a container in a separate thread?
Here's an example:
#include <queue>
#include <iostream>
#include <pthread.h>
#include <signal.h>
class A{
public:
A(){
pthread_create(&thread, NULL, &A::pushQueue, NULL);
pthread_join(thread, NULL);
}
virtual ~A(){
pthread_kill(thread, 0);
}
private:
static void* pushQueue(void* context){
for(int i = 0; i < 10; i++){
bufferInbound.push(i);
std::cout << i << " pushed!" << std::endl;
}
}
static std::queue<int> bufferInbound;
pthread_t thread;
};
int main(){
A* a = new A();
return 0;
}
When I compile, it gives me the following result:
U53R#Foo:~/$ make
g++ -g -lpthread main.cpp -c
g++ -g -lpthread main.o -o this
main.o: In function `A::pushQueue(void*)':
/home/U53R/main.cpp:20: undefined reference to `A::bufferInbound'
collect2: ld returned 1 exit status
make: *** [make] Error 1
Thanks for helping.
you need to initialize the static member, add std::queue<int> A::bufferInbound; after the class or move it inside your function.