I have a shared object my_lib.cc that defines in its header a class together with a factory function:
extern Foo* GetFoo():
class Foo {
public:
Foo() {}
virtual ~Foo() {}
};
Now I would like application that uses the library, main.cc, to contain:
#include "my_lib.h"
class Bar : public Foo {
// ...
};
Foo* GetFoo() {
return new Bar();
}
The point being that when the code inside the shared object needs to create a Foo it will call the method provided by the application dynamically linking it. Is this possible to do? Typically, an application depends on symbols provided by shared objects, but is it possible to have a shared object depend on a symbol in the binary that dynamically loads it?
Dynamic linking goes one way, from the user of the library → to the library.
Callbacks from the library to the user are usually done through a function pointer:
In my_lib.cc:
Foo* (*MakeFoo)();
void setFooFactory(Foo* (*pMakeFoo)()) {
MakeFoo = pMakeFoo;
}
Then in main.cc:
Foo* MakeBar() {
return new Bar();
}
int main() {
// load my_lib ...
setFooFactory(MakeBar);
// . . .
}
You can also wrap MakeFoo() into a factory class and use the C++ virtual function mechanism. I'm just demonstrating the main idea.
Related
I have implemented singleton of Meyers and four function to work with it. For example:
//A.h
class A
{
private:
Device d;
public:
A(){//...}
~A(){d.release();}
}
My class singleton Meyers
//Controller.h
class Controlle
{
private:
//some members
A m_member;
Controller();
Controller(const Controller&);
Controller& operator=(const Controller&);
public:
static Controller& GetInstance()
{
static Controller instance;
return instance;
}
}
And interface for working the class of Controller
extern "C" API Result InitDevice(const ParamsDevice* param);
extern "C" API Result InitAlgorithm(const ParamAlgorithm* param);
extern "C" API Result Operation_1();
extern "C" API Result Operation_2();
I build the library and get the Controller.dll and Controller.lib files. Library is shared lib.
Then I create a program where Controller.dll is used (implicit). Runtime library exception is thrown after program termination. I compiled the library in debug to check where the exception is thrown from.
I am getting the exception from comip.h file from method Release() class
template<typename _IIID> class _com_ptr_t
{
public:
// Declare interface type so that the type may be available outside
// the scope of this template.
//
typedef _IIID ThisIIID;
typedef typename _IIID::Interface Interface;
........
// Provides error-checking Release()ing of this interface.
//
void Release()
{
if (m_pInterface == NULL) {
_com_issue_error(E_POINTER);
}
else {
m_pInterface->Release();
m_pInterface = NULL;
}
}
}
I think that when the program terminates, the resources of static objects that are used in the library are incorrectly released. If I replace the singelton Meyers with a classic singelton and create methods for explicitly freeing up the memory of a static pointer, then everything works well. Could you help me explain this effect?
I think there is an answer to my question, but it is not complete for me and I cannot understand
https://stackoverflow.com/a/50644725/13970084
P.S. Sorry for my English. English isn't my native language.
I'm crating a DLL in C++ which handles different classes: in particular I have a main class which have a lot of member objects of the other the classes. For exmaple I have my class "A" which has a member of class "B":
Class A header
#include "BClass.h"
class __declspec(dllexport) A
{
B* objectB = nullptr;
public:
A();
initClassB();
}
Class A cpp:
A::A() { // Class A constructor. In these statements B is still nullptr}
A::initCLassB() { objectB = new B() }
Class B header:
class __declspec(dllexport) B
{
int x;
bool y;
char* z;
public:
B() { // class B constructor}
}
When I import my DLL in my target project, it compiles with no error, and until here everything's ok.
My main is something like:
#include "AClass.h"
int main()
{
A a;
return 0;
}
Notice that I don't invoke initClassB() in my main and this cause the error "Unable To Read Memory". If I explore the debugger I see that the error is related to all A::objectB members.
Why is this happening? Can't the shared library handle a nullptr member object?
I'm quite new in compiling DLL and this error looks a bit weird to me
DLLs on windows need to export their symbols when building the dll. Client code that uses the library needs to import it.
In your header for class B:
class __declspec(dllexport) B
This is what you want when building the library, but in code that uses it, you want it to be dllimport instead. Usually people use macros to toggle this, with it defaulting to import, and only exporting if a special commandline macro is set.
See this Macro for dllexport/dllimport switch
I'm trying to implement a design similar to the one described here:
http://www.linuxjournal.com/article/3687
I've got a core projects which compiles into an executable binary. I also want to have shared libraries loaded at runtime using dlopen(). Now I'm facing the problem that there are some classes which should be known in the core project and also in all of the loaded libraries. I thought I'd put them together in another shared library which gets linked to all of them at compilation. Everything seems to compile fine but during loading the shared library ConnectionModule.so dlopen returns no handle and dlerror says 'undefined symbol: _ZTV17PipelineProcessor' where PipelineProcessor is a class defined and implemented in the shared library which should be compiled in every addition shared library.
Does anyone have an idea of what is wrong with my implementation or is this design just doomed to fail?
some code here:
loading of library at runtime
#include "../SharedHeaders/SharedInEveryLibrary.h"
// ...
map<string, maker_t*, less<string> > module_library;
// ...
void *hndl = dlopen(library_file_path, RTLD_NOW | RTLD_GLOBAL);
if (hndl == nullptr) {
Logger::error << "Could not load library " << library_file_name << ": " << dlerror() << endl;
exit(-1);
}
ConditionModule.h (should be loaded at runtime)
#pragma once
#include "../SharedHeaders/SharedInEveryLibrary.h"
class ConditionModule : public B {
public:
A* processRequest(X* data) override; // implemented at ConditionModule.cpp
};
extern "C" {
A *maker() {
return new ConditionModule;
}
class proxy {
public:
proxy() {
module_library["condition_module"] = maker;
}
};
proxy p;
}
... and of course aome of the content of SharedInEveryLibrary.h
class Z; // gets implemented later, I guess it's not important
struct X {
int something;
// ...
};
class A {
public:
virtual void setSomeData(X* v_some_data);
virtual A* process(Z* data) = 0;
protected:
X* some_data;
};
class B : public A {
public:
A* process(Z* data) override;
virtual A* processRequest(X* data) = 0;
};
typedef A* maker_t();
extern map<string, maker_t*, less<string> > module_library;
EDIT -----
Forgot to mention that I currently develop only with Linux as compilation target.
There is nothing wrong with this design. But when you dlopen() a shared library, all it's symbols need to be resolved. Your error means that you do not have the path to .so your library depends on in LD_LIBRARY_PATH. To check what library it needs, use
ldd <your library.so>
Than add the directory where this library resides to LD_LIBRARY_PATH.
I have a QT library and I want to import it in another project.
Now, since I want that, even when I modify the library, the other project does not need to be compiled again, I started using QLibrary.
But... I can't import a class. Or better, I can import the class, but I can't access its methods.
This is the example I made.
This is the class declaration:
class TESTDLL_LIBSHARED_EXPORT TestDLL_lib
{
public:
TestDLL_lib();
int a;
int b;
int c;
int getValues();
};
and this the implementation:
#include "testdll_lib.h"
TestDLL_lib::TestDLL_lib()
{
a = 10;
b = 20;
c = 30;
}
int TestDLL_lib::getValues()
{
return a+b+c;
}
extern "C" TESTDLL_LIBSHARED_EXPORT TestDLL_lib* create_TestDLL_lib()
{
return new TestDLL_lib();
}
while this is the main file, in the other project:
#include <testdll_lib.h>
#include <QDebug>
#include <QLibrary>
int main(int argc, char *argv[])
{
QLibrary library("TestDLL_lib");
if (library.load())
{
typedef TestDLL_lib* (*create_TestDLL_lib_fun)();
create_TestDLL_lib_fun create_TestDLL_lib = (create_TestDLL_lib_fun)library.resolve("create_TestDLL_lib");
if (create_TestDLL_lib)
{
TestDLL_lib *myClassInstance = create_TestDLL_lib();
if (myClassInstance)
{
//qDebug() << QString::number(myClassInstance->getValues());
qDebug() << QString::number(myClassInstance->a) + " " + QString::number(myClassInstance->b) + " " + QString::number(myClassInstance->c);
}
}
library.unload();
}
}
Now, I can access all the data values (a, b, c) of the object myClassInstance (and, if i change them in the DLL, they also get changed in the program without a rebuild) but I can't call myClassInstance->getValues() because I get
main.obj:-1: error: LNK2001: unresolved external symbol "__declspec(dllimport) public: int __thiscall TestDLL_lib::getValues(void)" (__imp_?getValues#TestDLL_lib##QAEHXZ)
How can I solve this? Is it possible to call methods from imported classes?
Thank you..
You cannot call methods on classes imported at runtime. This is because the compiler links these calls at compile-time and not at run-time (which it cannot do). A way out is provided by our good ol' friend, the vtable:
You can, call virtual methods on classes implementing an interface (the interface is not "imported" at runtime). That means to define a class defining the interface using virtual (possibly pure virtual) methods. TestDLL_lib would then inherit that interface, implementing the methods. You would refer to the TestDLL_lib instance via that interface and call methods trough that interface, effectively calling them trough the vtable of the interface, which is "superseded" by TestDLL_libs vtable.
Don't forget to make your d'tor virtual and to add a virtual dtor to the interface. If you don't do that you cannot safely delete instance trough the interface pointer.
I might also explain why you can access members, but not call functions on "imported" classes. The members are accessed by memory location, and the memory location is solely defined by the compiler. Thus the compiler generates the code to access members without ever referring to any of the classes' symbols (methods and so on). This in turns leads to no linkage dependency. Note however that you would need to recompile both the DLL and the application using the DLL if you change the class, e.g. adding or removing a member, since that changes the memory layout.
class TestInterface
{
public:
virtual ~TestInterface()
{
}
virtual int getValues() = 0;
}
class TESTDLL_LIBSHARED_EXPORT TestDLL_lib : public TestInterface
{
public:
TestDLL_lib();
virtual ~TestDLL_lib();
int a;
int b;
int c;
int getValues() override; // MSVC may not support "override"
};
// return pointer to interface!
// TestDLL_lib can and should be completely hidden from the application
extern "C" TESTDLL_LIBSHARED_EXPORT TestInterface *create_TestDLL_lib()
{
return new TestDLL_lib();
}
I'm creating a helper to create multiple inheritance between C++ classes and Lua objects. Because Lua store C/C++ user objects as void *, it's hard to do safe casts when you retrieve objects.
For instance,
if you have
class A { }
class B { }
class C : public A, public B { }
And you pass an object of type C to Lua, you pass the address of the C instance, when you need to cast it to B, the C++ compiler will automatically align the pointer to the position of B in C and thus, it's not safe to cast the void * pointer from C to B directly.
To avoid this issue, I use a kind of converter. In Lua, the objects contains their name as a string, so when you need to cast the object from type to an other type, it uses the converter like this:
converters["B"]["C"](mypointer, myresultpointer);
This is the class that helps creating these converters :
// Common.h
#include <functional>
#include <memory>
#include <unordered_map>
#include <string>
typedef std::function<void (void *, void *)> LuaConverter;
typedef std::unordered_map<
std::string,
std::unordered_map<
std::string,
LuaConverter
>
> LuaConverters;
class LuaeClass {
public:
static LuaConverters converters;
public:
template <class From, class To>
static void createConverter(const std::string &fromName,
const std::string &toName)
{
converters[toName][fromName] = [&] (void *ptr, void *result) -> void {
std::shared_ptr<From> *from = static_cast<std::shared_ptr<From> *>(ptr);
*((std::shared_ptr<To> *)result) = std::static_pointer_cast<To>(*from);
};
}
};
This class is compiled as static library to be used many times in the project.
Object need to be passed as shared_ptr (it also solve the problem of ownership and deletion). It works well, however, it segfaults when using as static libraries.
Then, I have a simple module Battery, compiled as shared object and links to the common library.
For the scope of the example, it does not contains much functions, but it actually use the LuaeClass:
// Battery.cpp
#include <lua.hpp>
#include "Common.h"
class Battery {
public:
int getPercent() {
return 100;
}
};
extern "C" int luaopen_battery(lua_State *L)
{
LuaeClass::createConverter<Battery, Battery>("Battery", "Battery");
return 0;
}
This compiled as a shared object named battery.so, Lua will use dlopen() and dlcose() to load it.
Finally, the main. It links to common also and use it to create objects.
// main.cpp
#include <iostream>
#include <memory>
#include <string>
#include <lua.hpp>
#include "Common.h"
using namespace std;
class LuaDeleter {
public:
void operator()(lua_State *L) {
lua_close(L);
}
};
typedef unique_ptr<lua_State, LuaDeleter> LuaState;
int main(void)
{
LuaState L(luaL_newstate());
luaL_requiref(L.get(), "_G", luaopen_base, 1);
luaL_requiref(L.get(), "package", luaopen_package, 1);
// This will dlopen() and dlclose()
string code = "local battery = require \"battery\"";
LuaeClass::createConverter<int, int>("Int", "Int");
if (luaL_dostring(L.get(), code.c_str()) != LUA_OK) {
cerr << lua_tostring(L.get(), -1) << endl;
}
return 0;
}
To summary:
Common.cpp, Common.h are compiled as simple static library (libcommon.a)
Main.cpp, compiled and links to libcommon.a
Battery.cpp, compiled as a shared object and links to libcommon.a
The main segfaults at exit, the core file says it's in the destructor of std::function<> so I guess it is called multiple times on the same pointer, is it?
Is the static library data shared in all code? How can I avoid this issue?
The begin of the core
#0 0x0000000000404062 in std::__1::function<void (void*, void*)>::~function() ()
#1 0x0000000000404025 in std::__1::function<void (void*, void*)>::~function() ()
The next trace are just unreadable and unusable.
The code and global/static data of static library will be injected into each module which links it. So for your case, there are multiple LuaeClass::converters instances exist in your project. And you need to call luaopen_battery() in each module which links the static library.
I am not sure if your crash has anything to do with static link, but I am quite sure you went to a complicated implementation.
The first issue you want to address is safely converting void* to A*, B*, C*. Which class/interface you want to export to Lua? If it's class C, you can define below methods in class C:
void pushThis(lua_State *L);
static C* getThis(lua_State *L, int idx);
Both methods use C*, so you don't need a convert function. You can use meta table to distinguish your pointers from other userdata. If you need B*, just:
B* b = (B*)C::getThis(L, idx);
And you may not really need a shared_ptr. shared_ptr doesn't help on deleting your C++ object when your Lua object is collected by GC(because the shared_ptr still exist in heap). Instead, you have to implement a __gc callback in the meta table to delete your object.