假设我有以下内容:
// 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
带有函数指针,但两个版本的类型不同?
Edit:我不认为这会违反一定义规则-只有其中一个会同时链接,而不会两个都链接。 (我也不确定是否同时加载了ODR,因为它们都是手动使用的,但这是另一个主题)
鉴于具有不同库特定类型
func
的事实,我怎么称呼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);
}
在某种程度上可以说该标准适用于动态对象,您说对了,永远不会加载在一起的多个对象之间没有ODR冲突(因为没有包含两个定义的program)。如果它包含(显然)每种类类型的定义或包含一个类的定义,并且(在运行时选择是它)加载使用另一种类型的动态对象,则不能对您的程序说同样的话。 (使用DLL的情况更奇怪:共享类型,但不共享其成员函数,静态数据成员或RTTI符号。)
答案是将这些定义分开:wrap每个动态对象都属于您自己(通过简单的-l
与之链接),它公开了一个[[common interface(对于这个问题才有意义)。在主程序中加载those中的一个,然后使用该接口中唯一的类型#include
d进行调用。