- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我创建的动态库如下
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 -lQtGui
3) 从 TCL 处理器加载库然后我发出命令
tclsh并给出命令% 加载 libmy.so
是否有任何与 load 等效的 C++ 函数/Qt 可以根据另一个 C++ 函数的需要加载共享库。
我的要求是在函数内部运行时加载动态库,然后直接使用qt函数
1) 加载qt共享库(对于lib1.so)2)直接调用函数,无需调用resolve
例如,我们有 dopen,但对于每个函数调用,我们必须调用 dsym。我的要求只是调用共享库,然后直接调用这些函数。
最佳答案
您想要无样板的延迟加载。在 Windows 上,MSVC 实现 delay loading通过发出一个通过函数指针解析函数的 stub 。你也可以做到的。首先,让我们观察一下,如果您所做的只是调用函数指针和函数,那么它们是可以互换的。调用函数或函数指针的语法是相同的:
void foo_impl() {}
void (*foo)() = foo_impl;
int main() {
foo_impl();
foo();
}
这个想法是将函数指针最初设置为一个将在运行时解析实际函数的 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_thunk
,解析函数地址,并调用真正的foo
实现。
为此,您可以将库拆分为两个库:
可执行文件将链接到按需加载 stub 库;这是静态的或动态的。需求加载 stub 将在运行时自动解析符号并调用实现。
如果您足够聪明,您可以为实现设计 header ,以便 header 本身可用于生成所有 stub ,而无需输入两次详细信息。
一切如下,也可以从 https://github.com/KubaO/stackoverflown/tree/master/questions/demand-load-39291032 获取
顶级项目包括:
lib1
- 动态库lib1_demand
- lib1
的静态需求加载 thunkmain
- 使用lib1_demand
的应用程序TEMPLATE = subdirs
SUBDIRS = lib1 lib1_demand main
main.depends = lib1_demand
lib1_demand.depends = lib1
我们可以将聪明之处分解到一个单独的 header 中。该 header 允许我们定义库接口(interface),以便自动生成 thunk。
由于 C 的限制,需要大量使用预处理器和稍微冗余的语法。如果您只想为 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 += ..
我们将使用 demand_load.h
中的 DEMAND_FUN
,而不是直接声明函数。如果在包含 header 时定义了 DEMAND_LOAD_LIB1
,它将为库提供按需加载接口(interface)。如果定义了DEMAND_BUILD
,它将定义需求加载thunk。如果两者都没有定义,它将提供一个普通的接口(interface)。
我们小心地取消定义特定于实现的宏,以便全局 namespace 不被污染。然后,我们可以在项目中包含多个库,每个库都可以在按需加载和非按需加载之间单独选择。
#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;
}
对于此类库的用户,需求加载被简化为定义一个宏并使用 thunk 库 lib1_demand
而不是动态库 lib1
。
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);
}
最后,执行thunk。这里我们可以选择使用dlopen
+dlsym
或QLibrary
。为了简单起见,我选择了后者:
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;
}
关于qt - 如何从 C++ 函数/Qt 方法按需加载动态库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39291032/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!