链接不同版本的共享库

Linking on different version of shared libraries

本文关键字:共享 版本 链接      更新时间:2023-10-16

我有两个版本的共享库:库版本 2:

简单.h

#pragma once
int first(int x);

简单.c

#include "simple.h"
#include <stdio.h>
__asm__(".symver first_1_0,first@LIBSIMPLE_1.0");
int first_1_0(int x)
{
printf("lib: %sn", __FUNCTION__);
return x + 1;
}
__asm__(".symver first_2_0,first@@LIBSIMPLE_2.0");
int first_2_0(int x)
{
int y;
printf("lib: %dn", y);
printf("lib: %sn", __FUNCTION__);
return (x + 1) * 1000;
}

链接器版本脚本文件:

LIBSIMPLE_1.0{
global:
first;
local:
*;
};
LIBSIMPLE_2.0{
global:
first;
local:
*;
};
gcc -Wall -g -O0 -fPIC -c simple.c
gcc -shared simple.o -Wl,--version-script,script -o libsimple.so.2.0.0

和库版本 3:

简单.h

#pragma once  
#ifdef SIMPLELIB_VERSION_3_0
int first(int x, int normfactor);
#else
int first(int x);
#endif //SIMPLELIB_VERSION_3_0

简单.c

#include "simple.h"
#include <stdio.h>
__asm__(".symver first_1_0,first@LIBSIMPLE_1.0");
int first_1_0(int x)
{
printf("lib: %sn", __FUNCTION__);
return x + 1;
}
__asm__(".symver first_2_0,first@LIBSIMPLE_2.0");
int first_2_0(int x)
{
printf("lib: %sn", __FUNCTION__);
return (x + 1) * 1000;
}
__asm__(".symver first_3_0,first@@LIBSIMPLE_3.0");
int first_3_0(int x, int normfactor)
{
printf("lib: %sn", __FUNCTION__);
return (x + 1) * normfactor;
}

链接器版本脚本文件:

LIBSIMPLE_1.0{
global:
first; second;
local:
*;
};
LIBSIMPLE_2.0{
global:
first;
local:
*;
};
LIBSIMPLE_3.0{
global:
first;
local:
*;
};
gcc -Wall -g -O0 -fPIC -c simple.c
gcc -shared simple.o -Wl,--version-script,script -o libsimple.so.3.0.0

所以我最终有两个不同的库。接下来,我创建一个简单的应用程序,最终我想链接到库版本 3,因此在其中我使用函数 first(),它接受两个参数:

主.c

#include <stdio.h>
#include "simple.h"
int main(int argc, char* argv[])
{
int nFirst = first(1, 10);
printf("First(1) = %dn", nFirst);
}

我使用以下命令编译应用程序:

gcc -g -Wall -DSIMPLELIB_VERSION_3_0 -c main.c 

然后,偶然地,我没有链接到库版本 3,而是链接到库版本 2。我预计链接会失败,但它通过了,并且应用程序正在工作。

gcc main.o -Wl,-L. -lsimple.2.0.0 -Wl,-R. -o demo

所以我的问题是:

  1. 是因为库导出名称为"函数"的符号,并且应用程序尝试链接到相同的符号名称,这就是为什么链接器没有抱怨,只是链接到库版本 2 的原因?
  2. 我认为由于 c++ 会破坏符号名称,因此不会发生这样的事情,并且链接器不会链接到库版本 2。所以我尝试了所有相同的方法,但我尝试使用 g++ 而不是 gcc 编译器。一切都很顺利,直到我尝试将应用程序链接到库,并且收到未解决的链接错误。不知道为什么。

附言对不起,大量的代码。我试图说清楚。 谢谢

是因为库导出名称为"函数"的符号,并且应用程序尝试链接到相同的符号名称,这就是为什么链接器没有抱怨,只是链接到库版本 2 的原因?

是的,由于普通 C 没有函数重载,因此不需要重整,因此只有函数名称将用作链接的符号。最后,您的应用程序代码想要与function链接,并且您的库代码导出function,这足以让链接器满意(即使从二进制接口的角度来看它无效)。

我认为由于 c++ 会破坏符号名称,因此不会发生这样的事情,并且链接器不会链接到库版本 2。所以我尝试了所有相同的方法,但我尝试使用 g++ 而不是 gcc 编译器。一切都很顺利,直到我尝试将应用程序链接到库,并且收到未解决的链接错误。不知道为什么。

是的,由于名称重整,此问题不应在C++中发生。但是,仅当您同时具有应用程序代码和库代码C++或者以正确的方式桥接 C 和C++代码时,才如此。

很难说(没有完整列表)当你使用 g++ 时在你的情况下发生了什么,但从它的外观来看,你最终在 C++ 中拥有应用程序代码,而库代码仍然是 C 格式。如果是这种情况,您的应用程序代码现在将希望与损坏的function链接,而您的库代码仍导出未修改的function

要验证这一点,您可以使用以下内容检查对象文件:

nm main.o

。并确切地看到它想要什么样的符号。如果你会得到这样的东西:

...
U _Z3functionii
...

。而不是:

...
U function
...

。那么情况就是这样。

要"修复"此问题并使C++应用程序代码库代码中的未修改function链接,您需要将函数原型声明为extern "C"