如何使用共享对象库启用/禁用功能? 语言:C 操作系统:Red Hat EL
以“例如”开头:如何使用共享对象库启用/禁用功能? 语言:C 操作系统:Red Hat EL,c,linux,shared-libraries,dynamic-linking,C,Linux,Shared Libraries,Dynamic Linking,以“例如”开头: 假设我有两个库:libJUMP.so和libSIT.so 跳转包含函数JUMP(),类似地,SIT包含函数SIT() 我有一个应用程序,我想提供给不同的人;他们可以获得jump()功能,也可以获得sit()功能,或者两者兼有。但是,如果可能的话,我不想使用#ifdef libJUMP.so的标题: #ifndef JUMP_H_ #define JUMP_H_ #define JUMP_ENABLED void jump(); #endif /* JUMP_H_ */
- 假设我有两个库:
和libJUMP.so
李>libSIT.so
- 跳转包含函数
,类似地,SIT包含函数JUMP()
SIT()
- 我有一个应用程序,我想提供给不同的人;他们可以获得
功能,也可以获得jump()
功能,或者两者兼有。但是,如果可能的话,我不想使用sit()
#ifdef
libJUMP.so的标题:
#ifndef JUMP_H_
#define JUMP_H_
#define JUMP_ENABLED
void jump();
#endif /* JUMP_H_ */
#ifndef SIT_H_
#define SIT_H_
#define SIT_ENABLED
void sit();
#endif /* SIT_H_ */
libSIT.so的头文件
:
#ifndef JUMP_H_
#define JUMP_H_
#define JUMP_ENABLED
void jump();
#endif /* JUMP_H_ */
#ifndef SIT_H_
#define SIT_H_
#define SIT_ENABLED
void sit();
#endif /* SIT_H_ */
我有一份申请:
#include "jump.h"
#include "sit.h"
int main()
{
// #ifdef JUMP_ENABLED
jump();
// #endif /* JUMP_ENABLED */
// #ifdef SIT_ENABLED
sit();
// #endif /* SIT_ENABLED */
}
因此:
- 有没有不使用
的方法来执行此操作?还有更好的办法吗?#ifdef
- 我听说我们可以通过使用两个SO库进行编译来实现这一点,如果在目标系统上运行应用程序时缺少一个,它可以自动排除该功能(使用
和dlopen()
?)任何简单的示例,如果这确实正确的话?如果可能的话,举一个上面我的代码的例子:Ddlsym()
- 我听说我们可以通过使用两个SO库进行编译来实现这一点,如果在目标系统上运行应用程序时缺少一个,它可以自动排除该功能(使用
如果这是一个愚蠢的问题,或者根本不可能,请随时告诉我。如果有类似的问题,这将被视为重复的,让我知道,我将删除这篇文章。考虑这三个文件。首先,
jump.c
:
#include <stdio.h>
int jump(const double height)
{
fflush(stdout);
fprintf(stderr, "Jumping %.3g meters.\n", height);
fflush(stderr);
return 0;
}
#include <stdio.h>
int sit(void)
{
fflush(stdout);
fprintf(stderr, "Sitting down.\n");
fflush(stderr);
return 0;
}
第三,example.c
使用上述一项或两项,具体取决于它们(分别为libjump.so
或libsit.so
)是否存在于当前工作目录中:
#include <stdio.h>
#include <dlfcn.h>
static const char *jump_lib_path = "./libjump.so";
static int (*jump)(const double) = NULL;
static const char *sit_lib_path = "./libsit.so";
static int (*sit)(void) = NULL;
static void load_dynamic_libraries(void)
{
void *handle;
handle = dlopen(jump_lib_path, RTLD_NOW | RTLD_LOCAL);
if (handle) {
jump = dlsym(handle, "jump");
/* If no jump symbol, we don't need the library at all. */
if (!jump)
dlclose(handle);
}
handle = dlopen(sit_lib_path, RTLD_NOW | RTLD_LOCAL);
if (handle) {
sit = dlsym(handle, "sit");
/* If no sit symbol, the library is useless. */
if (!sit)
dlclose(handle);
}
}
int main(void)
{
int retval;
load_dynamic_libraries();
if (jump) {
printf("Calling 'jump(2.0)':\n");
retval = jump(2.0);
printf("Returned %d.\n\n", retval);
} else
printf("'jump()' is not available.\n\n");
if (sit) {
printf("Calling 'sit()':\n");
retval = sit();
printf("Returned %d.\n\n", retval);
} else
printf("'sit()' is not available.\n\n");
return 0;
}
程序输出的结果是,jump()和sit()都不可用。让我们将jump.c编译到动态库libjump.so中,然后再次运行该示例:
gcc -Wall -O2 -fPIC -shared jump.c -Wl,-soname,libjump.so -o libjump.so
./example
现在,jump()函数开始工作。让我们也编译sit.c,最后一次运行该示例:
gcc -Wall -O2 -fPIC -shared jump.c -Wl,-soname,libsit.so -o libsit.so
./example
在这里,两个函数都被调用,一切都正常工作
在
example.c
中,jump
和sit
是函数指针。我们将它们初始化为NULL,以便使用if(jump)
检查jump
是否指向有效函数
load\u dynamic\u libraries()
函数使用和来获取函数指针。请注意,如果动态库成功打开,并且找到了必需的符号,则我们不会dlclose()。(如果它看起来不是我们想要的那种库,我们只能dlclose()
如果要避免使用If(jump)
和If(sit)
子句,可以使用如下存根
在load\u dynamic\u libraries()
的末尾,将函数转移到存根而不是空指针,即
if (!jump)
jump = unsupported_jump;
if (!sit)
sit = unsupported_sit;
请注意,类似函数的接口最容易使用,因为函数指针充当有效的原型。如果需要对象,我建议使用getter函数。只要记住dlsym()
返回指向对象的指针,对象就可以正常工作;使用getter函数,这在getter函数指针类型中是显式的
插件接口通常只有一个函数(例如,int属性(struct-plugin*const-props,const-int-version)
),用于填充函数和对象指针的结构。应用程序提供它使用的结构的版本,插件函数返回成功或失败,这取决于它是否可以填充结构以适应该版本
由于插件通常存储在单个目录中(/usr/lib/yourapp/plugins/
非常常见),您可以通过使用并逐个扫描插件目录中的文件名来加载所有插件,dlopen()
ing每个文件名,获得properties()
函数指针,并调用它来查看插件提供了什么样的服务;通常创建一个数组或插件结构的链接列表
正如您所看到的,所有这些在Linux中都非常、非常简单和直接。如果您想要一个特定的插件功能示例,我建议您将其作为一个单独的问题提出,并提供更多关于接口应公开哪种功能的详细信息——确切的数据结构和功能原型在很大程度上取决于我们手头的应用程序类型
有问题吗?注释?我将创建一个新的定义,称为例如JUMP\u或_SIT
,它是JUMP
或SIT
。是否有帮助?首先,您给出的示例太模糊,无法推荐可靠的解决方案。如果编译时检查正常,您的答案可能是autoconf。它可以检查现有库,并将适当的define
s放入配置头文件中。Linux内核开发书建议尽可能避免函数内部的ifdef
。在您的情况下,如果未定义sit\u ENABLED
,本书建议您定义一个空的sit函数,并且您仍然可以在任何地方调用sit。@遗憾的是,这并不重要。它谈到了darwin
,这很好,因为我认为苹果gcc和标准gcc之间有一些相似之处。然而,他所说的只是剥离符号,而不是在运行时启用或禁用某些函数。@holgac这是我的目标-避免函数中出现#ifdef
。我将研究autoconf
。我试图保持这个例子简短-如果它含糊不清的话,很抱歉。我可以根据需要添加更多详细信息。我的最终目标是让某些函数在运行时可用(或不可用),如果这更有意义的话?非常感谢!这是迄今为止我见过的最简单的解释,也是我一直在寻找的。如果可以的话,我会给你买杯啤酒,但既然我不能