当您在命令行中提供库时,大多数链接器都遵循库的顺序。如果你首先用“foo1.a”链接你的程序,它将通过“foo1.a”的实现来解析你程序中funcfoo的引用。将“foo2.a”放在第二个位置,这将留下对funcfoo 的开放引用。将“foo3.a”放在第三位,这将通过第二个实现来解决。
编辑 1:
恐怕我错了。快速检查(就在睡觉之前)显示,当“foo2.a”被链接时,对funcfoo 的引用通过已经加载的“foo1.a”的实现来解决。 :-(
我会做更多的研究,但请不要屏住呼吸。
编辑 2:
好的,这花了一些时间,但在“objcopy”的帮助下,工作正常。即使在库中,您也可以使用其选项 --redefine-sym old=new 来“重命名”符号。
我准备了一个小示例来遵循这些步骤作为概念证明。在实际项目中,库已经构建,因此只需要显示列表的最后一个命令。
让我们从主要来源开始:
#include "foo1.h"
#include "foo2.h"
int main(void) {
funcfoo();
funcbar();
return 0;
}
它包括以下头文件,第一个“foo1.h”和第二个“foo2.h”:
#ifndef FOO1_H
#define FOO1_H
void funcfoo(void);
#endif
#ifndef FOO2_H
#define FOO2_H
void funcbar(void);
#endif
当然两者都有实现,第一个是“foo1.c”,第二个是“foo2.c”:
#include <stdio.h>
#include "foo1.h"
void funcfoo(void) {
puts("funcfoo() in foo1");
}
#include "foo2.h"
#include "foo3.h"
void funcbar(void) {
funcfoo();
}
第三个库“foo3”实现了和“foo1”一样的功能,先是头文件,然后是实现文件:
#ifndef FOO3_H
#define FOO3_H
void funcfoo(void);
#endif
#include <stdio.h>
#include "foo3.h"
void funcfoo(void) {
puts("funcfoo() in foo3");
}
这些是构建应用程序的命令:
gcc -c -Wall -Wextra foo1.c -o foo1.o
ar cr libfoo1.a foo1.o
gcc -c -Wall -Wextra foo2.c -o foo2.o
ar cr libfoo2.a foo2.o
gcc -c -Wall -Wextra foo3.c -o foo3.o
ar cr libfoo3.a foo3.o
# In the real prject, only the following steps are needed:
gcc -c -Wall -Wextra main.c -o main.o
objcopy --redefine-sym funcfoo=funcfoo2 libfoo2.a libfoo2n.a
objcopy --redefine-sym funcfoo=funcfoo2 libfoo3.a libfoo3n.a
gcc main.o -L. -lfoo1 -lfoo2n -lfoo3n -o app
如您所见,常用“binutils”的工具“objcopy”用于将冲突函数的名称从funcfoo重新定义为funcfoo2。我还让它创建一个新的输出库来保存原始文件。
当运行时,应用程序会打印:
funcfoo() in foo1
funcfoo() in foo3