在参数typedef更改时重建动态库
我们假设,我有一个C结构,DynApiArg_t.
typedef struct DynApiArg_s { uint32_t m1; ... uint32_t mx; } DynApiArg_t; 这个结构的指针作为arg传递给函数说 void DynLibApi(DynApiArg_t *arg) { arg->m1 = 0; another_fn_in_the_lib(arg->mold); /* May crash here. (1) */ } 它存在于动态库libdyn.so中.通过调用的dlopen / dlsym过程从可执行文件调用此API. 如果此动态库更新到版本2,其中DynApiArg_t现在有新成员,比如m2,如下所示: typedef struct DynApiArg_s { uint32_t m1; OldMbr_t *mold; ... uint32_t mx; uint32_t m2; NewMbr *mnew; } DynApiArg_t; 如果没有完全重建通过dlopen / dlsym调用此API的可执行文件或其他库,每次调用此API时,由于结构中任何成员的某些取消引用,我看到该进程崩溃.我知道访问m2可能是个问题.但是看到像下面这样的成员模具会导致崩溃. typedef void (*fnPtr_t)(DynApiArg_t*); void DynApiCaller(DynApiArg_t *arg) { void *libhdl = dlopen("libdyn.so",RTLD_LAZY | RTLD_GLOBAL); fnPtr_t fptr = dlsym(libhdl,"DynLibApi"); fnptr(arg); /* actual call to the dynamically loaded API (2) */ } 在通过fnptr调用API时,在标记为(2)的行中,当旧的/现有成员(在lib的v1中,当最初编译DynApiCaller时)在(1)处被访问时,它恰好是任何垃圾值甚至是有时为NULL. 每次更新从属库时,如果没有完整重新编译可执行文件,处理此类更新的正确方法是什么? 我已经看到libs用symliks命名,版本号如libsolid.so.4.是否有与此版本控制系统相关的内容可以帮助我?如果是这样的话,你可以指出我的正确文件吗? 解决方法
有许多方法可以解决这个问题:
>在动态库名称中包含API版本. 而不是dlopen(“libfoo.so”),您使用dlopen(“libfoo.so.4”).该库的不同主要版本基本上是分开的,可以在同一系统上共存;因此,该库的包名称将是例如libfoo的-4.您可以同时安装libfoo.so.4和libfoo.so.5.次要版本,比如libfoo-4.2,安装libfoo.so.4.2,symlink libfoo.so.4到libfoo.so.4.2. 例如,您的库的第4版可以实现 struct libfoo_api { int (*func1)(int arg1,int arg2); double *data; void (*func2)(void); /* ... */ }; 并且只导出一个符号, int libfoo_init(struct libfoo_api *const api,const int version); 调用该函数将使用支持的符号初始化api结构,并假设结构对应于指定的版本.单个共享库可以支持多个版本.如果不支持某个版本,则可能会返回失败. 这对于插件类型的接口特别有用(尽管_init函数更可能调用应用程序提供的功能注册函数,而不是填充结构),因为单个文件可以包含针对多个版本的优化功能,优化适用于多种兼容的硬件架构(例如,支持不同SSE / AVX / AVX2 / AVX512的AMD / Intel架构). 请注意,上述实现细节可以“隐藏”在头文件中,使得使用共享库的实际C代码更加简单.它还有助于使相同的API跨多个操作系统工作,只需更改头文件即可使用最适合该操作系统的方法,同时保持实际的C接口不变. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |