Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux,C-是否可以链接到两个具有相同函数名的动态库_C_Linux_Gcc_Shared Libraries_Linker Flags - Fatal编程技术网

Linux,C-是否可以链接到两个具有相同函数名的动态库

Linux,C-是否可以链接到两个具有相同函数名的动态库,c,linux,gcc,shared-libraries,linker-flags,C,Linux,Gcc,Shared Libraries,Linker Flags,我被迫将同一第三方动态库(Linux.so,C语言)的两个版本链接到同一个可执行文件中,以支持同一进程中的新旧功能。不希望有两个可执行文件或远程服务 我假设这一定是一项可行的任务。我尝试了一种简单的方法,创建两个代理动态库,每个库都与一个真实库相链接,并重命名了函数。 不幸的是,此尝试失败–两个新函数调用相同的目标函数。 我仍然想相信问题在于我缺乏知识,因为有很多编译器和链接器(gcc和ld)选项 我将感谢任何帮助。我也期待使用dlopen/dlsym,但首先要检查原始方法是否可行 下面是示例代

我被迫将同一第三方动态库(Linux.so,C语言)的两个版本链接到同一个可执行文件中,以支持同一进程中的新旧功能。不希望有两个可执行文件或远程服务

我假设这一定是一项可行的任务。我尝试了一种简单的方法,创建两个代理动态库,每个库都与一个真实库相链接,并重命名了函数。 不幸的是,此尝试失败–两个新函数调用相同的目标函数。 我仍然想相信问题在于我缺乏知识,因为有很多编译器和链接器(gcc和ld)选项

我将感谢任何帮助。我也期待使用dlopen/dlsym,但首先要检查原始方法是否可行

下面是示例代码

/* ./old/b.c */

#include <stdio.h>
int b (int i)
{
    printf("module OLD %d\n",i);
    return 0;
}

/* ./old/Makefile */

libold.so: b.c
    gcc -c -g b.c
    gcc -shared b.o -o $@

/* ./new/b.c */

#include <stdio.h>
int b (int i)
{
    printf("module new %d\n",i);
    return 0;
}

/* ./new/Makefile */

libnew.so: b.c
    gcc -c -g b.c
    gcc -shared b.o -o $@

/* ./a1.c */

#include <stdio.h>
int b(int);
void call_new(void)
{
    printf("will call new 1\n");
    b(1);
    printf("called new 1\n");
}

/* ./a2.c */

#include <stdio.h>
int b(int);
void call_old(void)
{
    printf("will call old 2\n");
    b(2);
    printf("called old 2\n");
}

/* ./main.c */

#include <stdio.h>
int call_new(void);
int call_old(void);
int main()
{
   call_new();
   call_old();
   return 0;
}

/* ./Makefile */

.PHONY: DEPSNEW DEPSOLD clean
main: liba1.so liba2.so main.c
    gcc -c main.c
    gcc -o main main.o -rdynamic -Wl,-rpath=new -Wl,-rpath=old -L . -la1  -la2
DEPSNEW:
    make -C new
DEPSOLD:
    make -C old    
    
liba1.so: DEPSNEW a1.c
    gcc -c -fpic a1.c
    gcc -shared a1.o -L new -lnew -o liba1.so

liba2.so: DEPSOLD a2.c
    gcc -c -fpic a2.c
    gcc -shared a2.o -L old -lold -o liba2.so
clean:
    find -name "*.so" -o -name "*.o" -o -name main | xargs -r rm
    

/* ./run.sh */

#/bin/sh 
LD_LIBRARY_PATH=new:old:. main


在这种情况下,您无法控制动态库的自动加载,以确保为依赖库加载哪个库。您可以使用其中一个库(新库)作为动态链接器,并手动链接第二个库,如下所示:

添加函数以动态加载和链接库中的函数

a2.c

#include <stdio.h>
#include <dlfcn.h>
static int (*old_b)(int);

void init_old(void) {
   void* lib=dlopen("./old/libold.so", RTLD_LOCAL | RTLD_LAZY);
   old_b=dlsym(lib,"b");
}

void call_old(void)
{
    printf("will call old 2\n");
    old_b(2);
    printf("called old 2\n");
}
#include <stdio.h>

void init_old(void);
int call_new(void);
int call_old(void);
int main()
{
   init_old();
   call_new();
   call_old();
   return 0;
}
修改后

~$  ./run.sh
will call new 1
module new 1
called new 1
will call old 2
module OLD 2
called old 2

dlopen
RTLD\u LOCAL
是您最好的机会。我认为这不可能通过更改编程或构建过程中的任何内容来实现。但是,也可以通过将库踢到一边、创建链接器脚本并对符号进行别名来实现。或者只是让链接器脚本位于一个更好的位置。我不完全确定这是否符合您的需要,但它可能值得一看。将名称重命名为有意义的名称?您描述的类型是可以实现的,但您试图形成的特定组合可能是,也可能不是。做这种事不容易。在进一步讨论之前,我建议您学习Ulrich Drepper的论文,该论文详细介绍了动态链接(以及其他主题)。是否所有库都适合以这种方式加载?我们尝试了这种方法,其中一个函数产生了一个错误指示,表示“库未初始化”。不幸的是,我不能提供图书馆。我只能说我怀疑它写性很差,动态库(共享库)可以用这种方式加载。该错误意味着您需要在使用库之前调用库中的其他函数。通常,库导出初始化函数,该函数会从
dlopen()
自动调用,但许多库在使用前会有额外的初始化协议,特别是当它们是
插件类型的库时。这里有更多的关于。不幸的是,如果没有这个库,我很难判断到底发生了什么。我们通过dlopen成功地同时加载和使用了这两个库。我要感谢大家的帮助。
liba2.so: DEPSOLD a2.c
    gcc -c -fpic a2.c
    gcc -shared a2.o -L old -lold -ldl -o liba2.so
~$  ./run.sh
will call new 1
module new 1
called new 1
will call old 2
module OLD 2
called old 2