我目前正在用 C 构建一个依赖于多个库的复杂可执行文件。可执行文件和它使用的一些库依赖于特定的库,我们称之为 libXYZ。
我正在尝试使用较新版本的 libXYZ、libXYZ.2 构建可执行文件,而我无法重建依赖于旧的、部分二进制不兼容的 libXYZ 版本、libXYZ.1 的其他库。
我能够在可执行文件中包含 libXYZ1 和 libXYZ2 的 .so,并且代码可以编译和运行,但是当我检查生成的可执行文件时,可执行文件调用的一些选定符号是用于 libXYZ1 的,即使在编译时, header 用于 libXYZ2。
有没有办法通过链接器选项强制构建可执行文件,始终选择 libXYZ2,同时让 libXYZ1 可用于其他链接的库?我无法重建依赖于 libXYZ 的其他库,但我可以根据需要重建可执行文件和 libXYZ 本身。谢谢。
最佳答案
我对我的一条评论进行了一些扩展,以便正确地格式化和描述这个想法。这在您的场景中可能不可行。
为了简化,我们有 libx1
,它公开了两个函数:libx_api
和 libx1_api
。此版本的库由 libx1_user
使用,它公开了一个 API:libx1_user
,它使用了两个 libx1
API。
我们还有 libx2
,它公开了两个函数:libx_api
和 libx2_api
。
我们有一个程序 (prog
) 依赖于 libx1_user
和 libx2
。
我的建议是将 libx2
包装在一个动态库 libx2w
中,它公开与 libx2
相同的 API,只是名称略有不同: w_libx_api
和 w_libx2_api
(只有在 libx1
和 libx2
之间有共同名称的函数需要这个改变,但是我为两个函数添加了 w_
前缀以保持一致性)。
现在,prog
的代码已更改,因此需要使用 API 的 libx2
版本的每个地方都将实际使用 的包装器>libx2w
。这应该是一个易于自动化的更改。
代码示例(我将省略 header 的内容,那里没有什么特别的,只是函数原型(prototype)):
libx1.c
#include <stdio.h>
#include "libx1.h"
void libx_api()
{
printf("In libx_api() from libx1\n");
}
void libx1_api()
{
printf("In libx1_api()\n");
}
libx2.c
#include <stdio.h>
#include "libx2.h"
void libx_api()
{
printf("In libx_api() from libx2\n");
}
void libx2_api()
{
printf("In libx2_api()\n");
}
libx1_user.c
#include <stdio.h>
#include "libx1_user.h"
#include "libx1.h"
void libx1_user()
{
printf("Entering libx1_user()\n");
libx_api();
libx1_api();
printf("Exiting libx1_user()\n");
}
libx2_wrapper.c
#include <stdio.h>
#include "libx2wrapper.h"
#include "libx2.h"
void w_libx_api()
{
libx_api();
}
void w_libx2_api()
{
libx2_api();
}
程序.c
#include <stdio.h>
#include "libx1_user.h"
#include "libx2wrapper.h"
int main()
{
printf("Using libx1_user()\n");
libx1_user();
printf("Done!\n");
printf("Using libx2 wrappers\n");
w_libx_api(); // this was previously libx_api()
w_libx2_api(); // this was previously libx2_api()
printf("Done!\n");
return 0;
}
用于编译和链接的示例 CMakeLists.txt
我对 CMake 比 make 更熟悉,所以我发现编写相应的 CMakeLists.txt 而不是 Makefile 更容易。
project(prog)
add_library(x1 STATIC libx1.c)
add_library(x1_user STATIC libx1_user.c)
target_link_libraries(x1_user PRIVATE x1)
add_library(x2 STATIC libx2.c)
add_library(x2w SHARED libx2wrapper.c)
target_link_libraries(x2w PRIVATE x2)
add_executable(prog program.c)
target_link_libraries(prog PRIVATE x2w x1_user)
运行生成的程序
$ ./prog
Using libx1_user()
Entering libx1_user()
In libx_api() from libx1
In libx1_api()
Exiting libx1_user()
Done!
Using libx2 wrappers
In libx_api() from libx1
In libx2_api()
Done!
纳米输出
$ nm prog
0000000000003d98 d _DYNAMIC
0000000000003fa8 d _GLOBAL_OFFSET_TABLE_
0000000000002000 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
000000000000224c r __FRAME_END__
0000000000002088 r __GNU_EH_FRAME_HDR
0000000000004010 d __TMC_END__
0000000000004010 B __bss_start
w __cxa_finalize@@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000001140 t __do_global_dtors_aux
0000000000003d90 d __do_global_dtors_aux_fini_array_entry
0000000000004008 d __dso_handle
0000000000003d88 d __frame_dummy_init_array_entry
w __gmon_start__
0000000000003d90 d __init_array_end
0000000000003d88 d __init_array_start
00000000000012c0 T __libc_csu_fini
0000000000001250 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
0000000000004010 D _edata
0000000000004018 B _end
00000000000012c8 t _fini
0000000000001000 t _init
00000000000010a0 T _start
0000000000004010 b completed.8060
0000000000004000 W data_start
00000000000010d0 t deregister_tm_clones
0000000000001180 t frame_dummy
0000000000001234 T libx1_api
00000000000011e6 T libx1_user
000000000000121d T libx_api
0000000000001189 T main
U puts@@GLIBC_2.2.5
0000000000001100 t register_tm_clones
U w_libx2_api
U w_libx_api
关于c - 使可执行文件更喜欢共享对象库而不是旧版本也可在同一可执行文件中使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66338383/