如何动态加载和调用具有库特定类型作为函数参数的符号
How to dynamically load and call a symbol which has a library-specific type as a function parameter
假设我有以下内容:
// lib1.h
struct S
{
int x;
};
void f(S* s); // defined in .cpp
和
// lib2.h
struct S
{
int x;
int y;
};
void f(S* s); // defined in .cpp
导致 lib1.so
和 lib2.so
。
那么,我的问题是:
#include <dlfcn.h>
int main()
{
const auto lib_to_use = <some application level logic, resulting in lib1.so or lib2.so>;
const auto lib = dlopen(lib_to_use, RTLD_LAZY);
assert(lib);
const auto func = dlsym(lib, "f");
assert(func);
// how do I call `func`, given the fact it takes different, library-specific type `S`?
dlclose(lib);
}
我的现实问题 是 - 如何在 运行 时间 libfuse2
或 libfuse3
加载并执行 fuse_main_real
,鉴于它有 fuse_operations*
参数,这是一个带有函数指针的 struct
,但两个版本的类型不同?
编辑:我不认为这会打破单一定义规则——只有其中一个会同时链接,绝不会同时链接。 (我也不确定如果两者都加载,ODR 是否被破坏,因为它们是手动使用的,但这是另一个话题)
就可以说该标准适用于动态对象而言,您是对的,在从未一起加载的多个对象之间没有 ODR 违规(因为没有 程序 包含两个定义)。如果您的程序包含每个 class 类型的定义(显然)或包含一个定义并且(运行时选择是它)加载使用另一个的动态对象,则不能对您的程序说同样的话。 (对于 DLL,情况比较奇怪:共享类型但不共享它们的成员函数、静态数据成员或 RTTI 符号。)
答案是将这些定义分开:将每个动态对象包装在你自己的一个对象中(用一个简单的-l
链接到它)公开一个common interface(这个问题必须是可行的)。在主程序中加载 those 中的一个,并使用该接口中的唯一类型 #include
d 调用它。
how do I call func
, given the fact it takes different, library-specific type S
?
显然,您不能在主程序中输入 S
同时匹配 lib1
S
和 lib2
S
。所以你必须声明两个不同的类型:S1
和 S2
.
其余的都是微不足道的:
int version = which_version_should_I_use();
if (version == V1) {
void *h = dlopen("lib1.so", RTLD_LAZY);
void (*fn)(S1*) = (void (*)(S1*))dlsym(h, "f");
assert(fn != NULL);
S1 s = ...;
fn(&s);
} else {
// must be V2
void *h = dlopen("lib2.so", RTLD_LAZY);
void (*fn)(S2*) = (void (*)(S2*))dlsym(h, "f");
assert(fn != NULL);
S2 s = ...;
fn(&s);
}
假设我有以下内容:
// lib1.h
struct S
{
int x;
};
void f(S* s); // defined in .cpp
和
// lib2.h
struct S
{
int x;
int y;
};
void f(S* s); // defined in .cpp
导致 lib1.so
和 lib2.so
。
那么,我的问题是:
#include <dlfcn.h>
int main()
{
const auto lib_to_use = <some application level logic, resulting in lib1.so or lib2.so>;
const auto lib = dlopen(lib_to_use, RTLD_LAZY);
assert(lib);
const auto func = dlsym(lib, "f");
assert(func);
// how do I call `func`, given the fact it takes different, library-specific type `S`?
dlclose(lib);
}
我的现实问题 是 - 如何在 运行 时间 libfuse2
或 libfuse3
加载并执行 fuse_main_real
,鉴于它有 fuse_operations*
参数,这是一个带有函数指针的 struct
,但两个版本的类型不同?
编辑:我不认为这会打破单一定义规则——只有其中一个会同时链接,绝不会同时链接。 (我也不确定如果两者都加载,ODR 是否被破坏,因为它们是手动使用的,但这是另一个话题)
就可以说该标准适用于动态对象而言,您是对的,在从未一起加载的多个对象之间没有 ODR 违规(因为没有 程序 包含两个定义)。如果您的程序包含每个 class 类型的定义(显然)或包含一个定义并且(运行时选择是它)加载使用另一个的动态对象,则不能对您的程序说同样的话。 (对于 DLL,情况比较奇怪:共享类型但不共享它们的成员函数、静态数据成员或 RTTI 符号。)
答案是将这些定义分开:将每个动态对象包装在你自己的一个对象中(用一个简单的-l
链接到它)公开一个common interface(这个问题必须是可行的)。在主程序中加载 those 中的一个,并使用该接口中的唯一类型 #include
d 调用它。
how do I call
func
, given the fact it takes different, library-specific typeS
?
显然,您不能在主程序中输入 S
同时匹配 lib1
S
和 lib2
S
。所以你必须声明两个不同的类型:S1
和 S2
.
其余的都是微不足道的:
int version = which_version_should_I_use();
if (version == V1) {
void *h = dlopen("lib1.so", RTLD_LAZY);
void (*fn)(S1*) = (void (*)(S1*))dlsym(h, "f");
assert(fn != NULL);
S1 s = ...;
fn(&s);
} else {
// must be V2
void *h = dlopen("lib2.so", RTLD_LAZY);
void (*fn)(S2*) = (void (*)(S2*))dlsym(h, "f");
assert(fn != NULL);
S2 s = ...;
fn(&s);
}