I'm experimenting around with dll loading on runtime and I have a problem: I have a little helper class which is istanciated in the main program. The pointer to this object is handed to the loaded dll. To test it, i want to call a function from the class (printLine). But I can't compile the dll because I get a:
Utility.o: In function `ZN7Utility6onInitEv':
D:\Benutzer\Jan\Desktop\Programmierprojekte\Game Engine 5.0\Utilities\Debug/../Utility.cpp:7: undefined reference to `ModuleHelper::printLine(std::string)'
collect2.exe: error: ld returned 1 exit status
These two files are the only content of the dll:
Utility.h:
#ifndef UTILITY_H_
#define UTILITY_H_
#include <iostream>
#include <Definitions.h>
#include <ModuleHelper.h>
class Utility
{
public:
Utility();
~Utility();
static void onInit();
static void onUpdate();
static char* getName();
static char** getDependencies();
static int getCountDependencies();
static char* getServeAs();
static void setModuleHelper(ModuleHelper* helper);
private:
static constexpr char* name = "Utility";
static constexpr char** dependencies = nullptr;
static constexpr int countDependencies = 0;
static constexpr char* serveAs = "";
static ModuleHelper* moduleHelper;
};
extern "C" //GAME_API is a dllexport macro
{
char* GAME_API getName()
{
return Utility::getName();
}
char** GAME_API getDependencies()
{
return Utility::getDependencies();
}
int GAME_API getCountDependencies()
{
return Utility::getCountDependencies();
}
char* GAME_API getServeAs()
{
return Utility::getServeAs();
}
noargfunc GAME_API onInit()
{
return Utility::onInit;
}
noargfunc GAME_API onUpdate()
{
return Utility::onUpdate;
}
void GAME_API setModuleHelper(ModuleHelper* moduleHelper)
{
Utility::setModuleHelper(moduleHelper);
}
}
#endif /* UTILITY_H_ */
Utility.cpp:
#include "Utility.h"
ModuleHelper* Utility::moduleHelper; //with "= nullptr" or "= NULL" it didn't work either
void Utility::onInit()
{
moduleHelper->printLine("Hello from Utilities"); //wrapper for std::cout
}
void Utility::onUpdate()
{
}
char* Utility::getName()
{
return name;
}
char** Utility::getDependencies()
{
return dependencies;
}
int Utility::getCountDependencies()
{
return countDependencies;
}
char* Utility::getServeAs()
{
return serveAs;
}
void Utility::setModuleHelper(ModuleHelper* helper)
{
moduleHelper = helper;
}
An undefined reference means that the IMPLEMENTATION is not found.
it looks like you just included the header file in order to use the library.
The main problem (the linker error - not runtime!) is that you may forgot to link the library. (Project References in Visual Studio)
Anyway you will find your next error if you CAN compile and link your code.
ModuleHelper* Utility::moduleHelper; //with "= nullptr" or "= NULL" it didn't work either
if you initialize moduleHelper with NULL and then dereference the pointer with "->" trying to do sth you will get a null-pointer exception.
You have to initialize it... (could be = new ModuleHelper). Since I don't know the used library you have to read the documentation yourself.
Related
I'm working on a cross platform project where I have to load dynamic libraries. I therefore created a very basic platform independent templated wrapper class around dlopen/loadLibrary that act like a factory class and return unique_ptr<T>s of the lib object.
But this is very unpractical in most of the cases, I therefore wondered, how can I design a simple wrapper that can do the following:
Load a lib and become a factory on instances of that lib objects for when we have to use multiple instances of the lib object
Create a self managed entity (a struct containing a unique ptr on the object and the handle on the lib maybe ?) for when we want to use only one instance of a lib object and not bother with a factory
Use the library provided deleter (symbol "destroy") instead of the default one
Does this exist ? If not, what would be the best way to do this ?
My implementation so far:
#pragma once
#include <memory>
#include <iostream>
#if _WIN32
#include <Windows.h>
#else
#include <dlfcn.h> //dlopen
#endif
namespace utils
{
template <class T>
class DynLib
{
public:
DynLib() = default;
~DynLib()
{
if (handle_)
closeLib(handle_);
};
private:
bool printLibError()
{
#if _WIN32
std::cerr << GetLastError() << std::endl;
#else
std::cerr << dlerror() << std::endl;
#endif
return false;
}
void *openLib(const std::string &libName)
{
#if _WIN32
return LoadLibrary((libName + ".dll").c_str());
#else
return dlopen((libName + ".so").c_str(), RTLD_LAZY);
#endif
}
int closeLib(void *libHandle)
{
#if _WIN32
return FreeLibrary((HMODULE)libHandle);
#else
return dlclose(libHandle);
#endif
}
void *loadSymbol(void *libHandle, const char *sym)
{
#if _WIN32
return (void *)GetProcAddress((HMODULE)libHandle, sym);
#else
return dlsym(libHandle, sym);
#endif
}
public:
bool open(const std::string &filename, const char *csym = "create", const char *dsym = "destroy")
{
if (!(handle_ = openLib(filename)))
return printLibError();
if (!(create = (T * (*)()) loadSymbol(handle_, csym)))
return printLibError();
if (!(destroy_ = (void (*)(T *))loadSymbol(handle_, dsym)))
return printLibError();
return true;
}
std::unique_ptr<T> createUnique()
{
return (std::unique_ptr<T>(create()));
}
private:
void *handle_{nullptr};
T *(*create)();
void (*destroy_)(T *);
};
}
Have you considered Boost.DLL library?
It provides examples on how implement plugins/factory methods.
I have Application singleton wich has method
void addHandler(const std::string& command, std::function<std::string (const std::string&)> handler)
I want to create a lot of cpp files with handlers like this
//create_user_handler.cpp
Application::getInstance()->addHandler("create_user", [](std::string name) {
UserPtr user = User::create(name);
return user->toJson();
});
How automatically call this from my cpp files?
I try to change from void addHandler to bool addHandler and than use
namespace {
bool b = Application::getInatance()->addHandler......
}
but it didn't work for me
Udate
It works now, but could it be done in a better way, without unused bool variable?
Make use of static class instantiation.
Pseudo code -
Add a registrator class.
class Registrator {
template <typename Func>
Registrator(const std::string& name, Func handler) {
Application::getInstance()->addHandler(name, handler);
}
};
And in each cpp file, create a static class object:
test.cpp
static Registrator test_cpp_reg("create_user", [](std::string name) {
UserPtr user = User::create(name);
return user->toJson();
});
I assume that addHandler() should return bool? Otherwise, you can't assign to the bool variable.
To remove the bool return of addHandler, make the call from the constructor of some other class that you in turn instantiate statically.
This kind of code can work, but it is tricky. The problem is that in C/C++, the order of static-storage initializers is undefined. So while a static initializer is allowed to call any code, if that code references as-yet-uninitialized data, it will fail. And unfortunately the failure is non-deterministic. It might work for a while, and then you change some compiler flag or module order, and splat!
One trick is to implement the instance state of getInstance() using a dumb pointer, because that is always initialized to zero (null) before any of the static initializers fire. For example, the following code will print "Added foo" before main starts:
#include <string>
#include <functional>
#include <map>
#include <iostream>
class Application {
public:
static Application* getInstance() {
// Not thread-safe!
if (instance == 0) {
instance = new Application;
}
return instance;
}
typedef std::function<std::string(const std::string&)> HANDLER;
typedef std::map<std::string, HANDLER> HANDLER_MAP;
bool addHandler(const std::string& command, HANDLER handler) {
handlerMap.insert(HANDLER_MAP::value_type(command, handler));
std::cout << "Added " << command << "\n";
return true;
}
HANDLER_MAP handlerMap;
static Application* instance;
};
Application* Application::instance;
std::string myHandler(const std::string&) { return ""; }
bool b = Application::getInstance()->addHandler("foo", myHandler);
int main()
{
return 0;
}
I'm having a problem with SDL threads so I made a little multi file code so it will be easier to show my problem
Header file
#ifndef MAINC_H_INCLUDED
#define MAINC_H_INCLUDED
#include <iostream>
#include <CONIO.H>
#include <SDL.h>
#include <SDL_thread.h>
using namespace std;
class mainc
{
private:
SDL_Thread* thread;
int threadR;
int testN=10;
public:
int threadF(void *ptr);
int OnExecute();
bool start();
};
#endif
One file
#include "mainc.h"
bool mainc::start() {
if(SDL_Init(SDL_INIT_EVERYTHING) < 0) {
return false;
}
getch();
if(SDL_CreateThread(threadF, "TestThread", (void *)NULL)==NULL){
return false;
}
return true;
}
int mainc::threadF(void *ptr){
cout<<"This is a thread and here is a number: "<<testN<<endl;
return testN;
}
Second file
#include "mainc.h"
int mainc::OnExecute() {
if(!start())
{
return -1;
}
SDL_WaitThread(thread,&threadR);
return 0;
}
int main(int argc, char* argv[]) {
mainc game;
return game.OnExecute();
}
When I compile this I get this error
cannot convert 'mainc::threadF' from type 'int (mainc::)(void*)' to type 'SDL_ThreadFunction {aka int (*)(void*)}'
I dug around a bit and I found a solution but it gave me other errors I needed to make threadF static but I couldn't access any variables it gave me this error
invalid use of member 'mainc::testN' in static member function
But if I remove the variable from the function it runs fine
Now I don't know what do to because in my game I need to share variables which change
testN is neither a static nor a public property of class mainc and to do what you're trying to do, it needs to be either.
If you want to use members of class "mainc" from within another thread body, you need to pass a pointer to an object of class "mainc" to SDL_CreateThread:
// ...
SDL_CreateThread(threadF, "TestThread", this)
// ...
and then
int mainc::threadF(void *ptr)
{
mainc* myMainc = (mainc*)ptr;
myMainc->testN; // now you can use it as you need
}
Beware of the encapsulation, though (testN is actually private)
For some reasons, sometimes when I define my member functions in a CPP file rather than within their declaring header, I get undefined reference errors from g++.
This question is similar to Undefined Reference To Member function but that user managed to solve the problem by adding the missing file to his command line, which doesn't seem to be working here.
Btw, I'm not against using a makefile; in fact I plan to do so eventually, whenever I get used to these commands.
my main file ('ringbuftest.cpp'):
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <iostream>
#include <cstring>
#include "ringbuffer.h"
using namespace std;
void *reader(void* param);
void *writer(void* param);
struct pack{
char msg[256];
};
RINGBUFFER<pack> *ringo;
int main(){
pthread_t rdr;
pthread_t wtr;
ringo = new RINGBUFFER<pack>(12);
int ret1 = pthread_create(&rdr,NULL,reader,(void*)NULL);
int ret2 = pthread_create(&wtr,NULL,writer,(void*)NULL);
#ifdef _unix
cout<< "unix single underscore\n";
#elif defined __unix
cout<< "unix two underscores\n";
#endif
pthread_join(wtr,NULL);
pthread_join(rdr,NULL);
cout<< "threads are done\n";
exit(0);
return 0;
}
void *reader(void *param){
pack myPack;
while(true)
{
for(int i=0;i<10000;i++){int k=0;k=i;k++;i=k;i--;}
if( ringo->Pop(&myPack) )
{
cout<< myPack.msg;
}
}
}
void *writer(void *param){
pack myPack;
while(true){
strcpy(myPack.msg,"hello reader!\n");
ringo->Push(&myPack);
}
}
my class header ('ringbuffer.h'):
#include<stdlib.h>
using namespace std;
#ifndef __ring_buffer_h__
#define __ring_buffer_h__
#define RINGBUFFER_DEFAULT_SIZE 8
template <class T>
class RINGBUFFER
{
private:
unsigned int top;
unsigned int bottom;
unsigned int size;
unsigned int count;
void *items;
public:
RINGBUFFER();
RINGBUFFER(unsigned int size);
~RINGBUFFER();
bool Push(T *value);
bool Pop(T *value);
};
#endif
my class definitions ('ringbuffer.CPP'):
#include "ringbuffer.h"
template<class T>
RINGBUFFER<T>::RINGBUFFER()
{
top = bottom = 0;
size = RINGBUFFER_DEFAULT_SIZE;
count = 0;
items = malloc((size+1)*sizeof(T));
}
template<class T>
RINGBUFFER<T>::RINGBUFFER(unsigned int _size)
{
top = bottom = 0;
size = _size;
count = 0;
items = malloc(size*sizeof(T));
}
template<class T>
RINGBUFFER<T>::~RINGBUFFER()
{
free(items);
}
template<class T>
bool RINGBUFFER<T>::Push(T *value)
{
if( count<size )
{
memcpy(&(((T*)items)[bottom]),value,sizeof(T));
bottom = (bottom+1)%size;
count++;
return true;
}
return false;
}
template<class T>
bool RINGBUFFER<T>::Pop(T *value)
{
if( count>0 )
{
memcpy(value,&(((T*)items)[top]),sizeof(T));
top = (top+1)%size;
count--;
return true;
}
return false;
}
To compile, I've been trying to use:
g++ ringbuffer.CPP ringbuftest.cpp -lpthread -o ringbuffertest.o
and I get the errors:
/tmp/ccj8RqhY.o: In function `main':
ringbuftest.cpp:(.text+0x21): undefined reference to `RINGBUFFER<pack>::RINGBUFFER(unsigned int)'
/tmp/ccj8RqhY.o: In function `reader(void*)':
ringbuftest.cpp:(.text+0x157): undefined reference to `RINGBUFFER<pack>::Pop(pack*)'
/tmp/ccj8RqhY.o: In function `writer(void*)':
ringbuftest.cpp:(.text+0x1db): undefined reference to `RINGBUFFER<pack>::Push(pack*)'
collect2: error: ld returned 1 exit status
I'm guessing I'm doing something wrong with g++ because I keep hitting this problem in different projects, or maybe I'm using templates wrong.(?)
How can I resolve this error?
Edit:
I should mention that this compiles perfectly if I instead paste the member definitions into the header file and exclude the .CPP from the g++ command.
You need to move the entire definition of RINGBUFFER<T> from ringbuffer.cpp to ringbuffer.h so that it's visible when ringbuftest.cpp is being compiled.
I am getting linker error, for the following code. I want to know how do I initialize stl map
#include <iostream>
#include <map>
#include <string>
class Test {
public:
Test() {
}
static void setSerializer(void* fnptr, std::string className) {
m_registry.insert(std::make_pair(className, fnptr));
}
static void* getSerializer(std::string className) {
return m_registry.find(className)->second;
}
private:
static std::map<std::string, void*> m_registry;
};
void fn() {
}
int main() {
Test::setSerializer(&fn,"abc");
return 0;
}
You need to define your static variable in class implementation - as you do for extern C++ variables. Just declaring it in class isn't sufficient!
To do this put the code below to the .cpp file:
std::map<std::string, void*> Test::m_registry;
You need to initialize your static member in .cpp file. Normally we declare class in .h file and put definition into .cpp file. I did a bit enhancement to your code as shown below:
Test.h
class Test
{
public:
Test() { }
static void setSerializer(std::string className, void* fnptr); // I swap the order of parameter. it makes more sense to have name and pointer pair
static void* getSerializer(std::string className);
private:
static std::map<std::string, void*> m_registry;
};
Test.cpp
std::map<std::string, void*> Test::m_registry; // initialize static member here
void Test::setSerializer(std::string className, void* fnptr)
{
m_registry.insert(std::make_pair(className, fnptr));
}
void* Test::getSerializer(std::string className) {
auto iter = m_registry.find(className); // check if iterator is valid
if (iter != m_registry.end() )
{
return (*iter).second;
}
return NULL;
}