如何从C+;按需加载动态库+;函数/Qt方法
我创建了动态库,如下所示 cat myfile.cc如何从C+;按需加载动态库+;函数/Qt方法,qt,linker,tcl,shared-libraries,system-calls,Qt,Linker,Tcl,Shared Libraries,System Calls,我创建了动态库,如下所示 cat myfile.cc struct Tcl_Interp; extern "C" int My_Init(Tcl_Interp *) { return 0; } 1) 整理cc文件 g++ -fPIC -c myfile.cc 2) 创建共享库 g++ -static-libstdc++ -static-libgcc -shared -o libmy.so myfile.o -L/tools/linux64/qt-4.6.0/lib -lQtCore -lQt
struct Tcl_Interp;
extern "C" int My_Init(Tcl_Interp *) { return 0; }
1) 整理cc文件
g++ -fPIC -c myfile.cc
2) 创建共享库
g++ -static-libstdc++ -static-libgcc -shared -o libmy.so myfile.o -L/tools/linux64/qt-4.6.0/lib -lQtCore -lQtGui
3) 从TCL进程加载库
然后我发出命令
tclsh
指挥
%加载libmy.so
是否有任何与负载相同的C++函数/Qt,可以从另一个C++函数按需加载共享库。 我的要求是在函数内部的运行时加载动态库,然后直接使用qt函数
1) 加载qt共享库(对于lib1.so) 2) 直接调用函数,无需任何解析调用例如,我们有dopen,但对于每个函数调用,我们必须调用dsym。我的要求是只调用共享库,然后直接调用这些函数。您希望无延迟加载样板文件。在Windows上,MSVC通过发出存根来实现,存根通过函数指针解析函数。你也可以这样做。首先,让我们观察一下,如果只调用函数指针和函数,它们是可以互换的。调用函数或函数指针的语法相同:
void foo_impl() {}
void (*foo)() = foo_impl;
int main() {
foo_impl();
foo();
}
其思想是将函数指针最初设置为thunk,该thunk将在运行时解析实际函数:
extern void (*foo)();
void foo_thunk() {
foo = QLibrary::resolve("libmylib", "foo");
if (!foo) abort();
return foo();
}
void (*foo)() = foo_thunk;
int main() {
foo(); // calls foo_thunk to resolve foo and calls foo from libmylib
foo(); // calls foo from libmylib
}
当您第一次调用foo
时,它将真正调用foo\u thunk
,解析函数地址,并调用realfoo
实现
为此,可以将库拆分为两个库:
-动态库lib1
-lib1的静态需求负载thunklib1\u需求
-使用main
lib1\u demand
由于C的限制,需要使用预处理器和有点多余的语法。如果您想仅为C++实现此,则不需要重复参数列表。
需求负荷 我们将使用DEMAND\u load.h
中的DEMAND\u FUN
而不是直接声明函数。如果在包含标题时定义了DEMAND\u LOAD\u LIB1
,则它将向库提供一个DEMAND LOAD接口。如果定义了DEMAND\u BUILD
,它将定义需求负载thunks。如果两者都没有定义,它将提供一个普通接口
我们注意取消定义特定于实现的宏,这样全局名称空间就不会受到污染。然后,我们可以在项目中包含多个库,每个库可以在按需加载和非按需加载之间单独选择
lib1/lib1.h
实施过程没有争议:
lib1/lib1.c
对于这样一个库的用户,按需加载减少到定义一个宏,并使用thunk库lib1_demand
而不是动态库lib1
main/main.pro
main/main.cpp
lib1_demand/lib1_demand.cpp
#定义需求#构建
#包括“lib1/lib1.h”
#包括
void(*resolve_LIB1(const char*name))(){
auto f=QLibrary::resolve(“../lib1/liblib1”,名称);
返回f;
}
> p>完全不同于将库加载到C++代码中(Kuber Ober的答案覆盖得很好),加载的代码是错误的;即使您设法加载它,您的代码也会崩溃!这是因为在文件范围内有一个类型为Tcl\u Interp
的变量;这是对Tcl库的错误使用。相反,该库只提供了一种获取解释器上下文句柄的方法,Tcl\u CreateInterp()
(以及一些其他围绕它的函数),该方法返回一个已正确初始化的Tcl\u Interp*
。(严格地说,它实际上返回了一个句柄,该句柄实际上是Tcl\u Interp
的内部子类,因此您自己无法有效地分配一个句柄。)
该库的正确用法如下:
Tcl_FindExecutable(NULL); // Or argv[0] if you have it
Tcl_Interp *interp = Tcl_CreateInterp();
// And now, you can use the rest of the API as you see fit
这是为了在代码中放入Tcl解释器。反过来说,您可以创建一个int My_Init(Tcl_Interp*)
函数,正如您所描述的,它用于告诉您解释器在哪里,但您不会询问如何加载代码,因为Tcl已经对此提供了合理的支持。您看了吗?据我所知,我需要解决所有对QT方法的调用,这些调用似乎并不干净。你能推荐一些更干净的方法吗?我只有几行代码可以在运行时加载共享库好的,我在阅读你的问题时没有想到这一点。如果在运行时使用dlopen加载库,那么没有dllsym是不行的。另一种方法是在编译时链接到库。这个问题是不完整的,并且没有提到你试图用裸露的C++ API来请求加载C++库。即qtcore。共享库是我的案例m,我必须在运行时按需加载libQtCore.so和libQtGui。因此,在我的案例中,对Qt库代码的函数调用大约为80000,因此我理解,每次调用Qt函数都需要demand_FUNC,这对我来说是不实际可行的。如果有更干净的方法,我的问题是使用C++图书馆
// Configuration macros:
// DEMAND_NAME - must be set to a unique identifier of the library
// DEMAND_LOAD - if defined, the functions are declared as function pointers, **or**
// DEMAND_BUILD - if defined, the thunks and function pointers are defined
#if defined(DEMAND_FUN)
#error Multiple inclusion of demand_load.h without undefining DEMAND_FUN first.
#endif
#if !defined(DEMAND_NAME)
#error DEMAND_NAME must be defined
#endif
#if defined(DEMAND_LOAD)
// Interface via a function pointer
#define DEMAND_FUN(ret,name,args,arg_call) \
extern ret (*name)args;
#elif defined(DEMAND_BUILD)
// Implementation of the demand loader stub
#ifndef DEMAND_CAT
#define DEMAND_CAT_(x,y) x##y
#define DEMAND_CAT(x,y) DEMAND_CAT_(x,y)
#endif
void (* DEMAND_CAT(resolve_,DEMAND_NAME)(const char *))();
#if defined(__cplusplus)
#define DEMAND_FUN(ret,name,args,arg_call) \
extern ret (*name)args; \
ret name##_thunk args { \
name = reinterpret_cast<decltype(name)>(DEMAND_CAT(resolve_,DEMAND_NAME)(#name)); \
return name arg_call; \
}\
ret (*name)args = name##_thunk;
#else
#define DEMAND_FUN(ret,name,args,arg_call) \
extern ret (*name)args; \
ret name##_impl args { \
name = (void*)DEMAND_CAT(resolve_,DEMAND_NAME)(#name); \
name arg_call; \
}\
ret (*name)args = name##_impl;
#endif // __cplusplus
#else
// Interface via a function
#define DEMAND_FUN(ret,name,args,arg_call) \
ret name args;
#endif
TEMPLATE = lib
SOURCES = lib1.c
HEADERS = lib1.h
INCLUDEPATH += ..
DEPENDPATH += ..
#ifndef LIB_H
#define LIB_H
#ifdef __cplusplus
extern "C" {
#endif
#define DEMAND_NAME LIB1
#ifdef DEMAND_LOAD_LIB1
#define DEMAND_LOAD
#endif
#include "demand_load.h"
#undef DEMAND_LOAD
DEMAND_FUN(int, My_Add, (int i, int j), (i,j))
DEMAND_FUN(int, My_Subtract, (int i, int j), (i,j))
#undef DEMAND_FUN
#undef DEMAND_NAME
#ifdef __cplusplus
}
#endif
#endif
#include "lib1.h"
int My_Add(int i, int j) {
return i+j;
}
int My_Subtract(int i, int j) {
return i-j;
}
if (true) {
# Use demand-loaded lib1
DEFINES += DEMAND_LOAD_LIB1
LIBS += -L../lib1_demand -llib1_demand
} else {
# Use direct-loaded lib1
LIBS += -L../lib1 -llib1
}
QT = core
CONFIG += console c++11
CONFIG -= app_bundle
TARGET = demand-load-39291032
TEMPLATE = app
INCLUDEPATH += ..
DEPENDPATH += ..
SOURCES = main.cpp
#include "lib1/lib1.h"
#include <QtCore>
int main() {
auto a = My_Add(1, 2);
Q_ASSERT(a == 3);
auto b = My_Add(3, 4);
Q_ASSERT(b == 7);
auto c = My_Subtract(5, 7);
Q_ASSERT(c == -2);
}
QT = core
TEMPLATE = lib
CONFIG += staticlib
INCLUDEPATH += ..
DEPENDPATH += ..
SOURCES = lib1_demand.cpp
HEADERS = ../demand_load.h
#define DEMAND_BUILD
#include "lib1/lib1.h"
#include <QLibrary>
void (* resolve_LIB1(const char * name))() {
auto f = QLibrary::resolve("../lib1/liblib1", name);
return f;
}
Tcl_FindExecutable(NULL); // Or argv[0] if you have it
Tcl_Interp *interp = Tcl_CreateInterp();
// And now, you can use the rest of the API as you see fit