编译器:G++
OS:LINUX
1.link顺序
GCC Link程序在.o文件列表中查找被引用实体(函数或Class)时不设定顺序,即引用实体所在.o文件出现
在被引用实体所在的.o文件的左侧,或右侧都能通过编译,不会出现找不到引用的错误
但若从.a文件列表中搜索被引用实体,情况将不同,总是则从右向左顺序查找,因此,被引用实体所在.a
文件必需出现在引用实体所在.a文件的右侧,否则,将报“未定义引用(undefined reference)”错误
2.重复引用的处理
若同一实体分别在两个以上.o或.a文件中被实现,Link时又同时指定了这些.o或.a文件,结果会怎么样?
你可能认为这是个常识问题:编译器报多重定义的错。事实果真如此吗?正确答案:取决于你编译命令行
怎么写。
若指定.o文件列表,你的常识是对,编译器报多重定义的错(multiple definition)。
但若指定.a文件列表,你的常识将是错的,编译器并不报错,而是引用.a文件列表中,从若向左第一次出
现的实现。
引用实体和被引用实体混合出现在.o, .a的文件中时情况较复杂,大体符合.o优先的原则
引用与被引用实体分别所在的.o被打包成一个.a时,打包时.o没有顺序依赖,但当其中存在多重定义时,
情况将不同,实际被引用的是按照打包顺序,从左向右,出现在引用实体右侧的第一个实现。
测试过程如下:
1.在a.h文件中定义一个函数:
void f_a();
2.在a.cpp中提供一个实现版本
void f_a()
{
printf("hello f_a from a.cpp/n");
}
编译成a.o, 并ar rsuv a.a a.o成a.a
3.在b.cpp中提供void f_a()并一实现版本
void f_a()
{
printf("hello f_a from b.cpp/n");
}
编译成b.o, 并ar rsuv b.a b.o成b.a
4.在c.cpp中实现
void f_c()
{
printf("f_c will call f_a.../n");
f_a();
}
编译成c.o, 并ar rsuv c.a c.o成c.a
5.在main.cpp中call f_c()
int main(int argc, char **argv)
{
f_c();
return 0;
}
6.测试Link顺序
6.1 g++ -o main main.cpp a.o c.o或g++ -o main main.cpp c.o a.o将得到同样的正确的结果--被引
用实体在.o文件列表中无顺序依赖
6.2 g++ -o main main.cpp c.a a.a通过编译,得到正确结果,但g++ -o main main.cpp a.a c.a将通不
过编译,报错:undefined reference to `f_a()' -- 被引用实体在.a文件列表中有顺序依赖,被引用
实体必需出现在引用实体的左侧
7.测试多重实现
7.1 g++ -o main main.cpp a.o b.o c.o(a.o, b.o, c.o任意排列组合),编译将失败,报错:multiple
definition of `f_a()'--在.o列表中若存在多重定义,编译将失败
7.2 g++ -o main main.cpp a.a b.a c.a报错:undefined reference to `f_a()'--符合上面关于Link
顺序的测试; g++ -o main main.cpp c.a b.a a.a,通过编译,实际引用b.a中的实现; g++ -o main
main.cpp c.a a.a b.a, 通过编译,实际引用a.a中的实现。
7.3 g++ -o main main.cpp cc.a a.o b.a, 通过编译,实际引用a.o中的实现版本--.o中的实现被引用
的优先级高于.a;g++ -o main main.cpp c.a b.a a.o, 编译出错,报“多重定义(multiple definition
of `f_a()')”; g++ -o main main.cpp b.a c.a a.o或g++ -o main main.cpp b.a a.o c.a,通过编译,
实际引用a.o中的实现--引用实体与被引用实体有的出现在.a中,有的出现在.o中,且存多重定义的情形
是有些复杂的,实际工作中应谨慎处理
7.4 将多个.o打成一个.a(文件名体现打包顺序),g++ -o main main.cpp ac.a或g++ -o main main.cpp
ca.a, 通过编译; g++ -o main main.cpp cc.o ab.a,编译通过,实际引用a.o实现,g++ -o main
main.cpp cc.o ba.a,编译通过,实际引用b.o实现; g++ -o main main.cpp abc.a,通过编译,实际引用
a.o实现;g++ -o main main.cpp bac.a,通过编译,实际引用b.o实现;g++ -o main main.cpp acb.a,通
过编译,实际引用b.o实现; g++ -o main main.cpp abc.a,通过编译,实际引用a.o实现;g++ -o main
main.cpp bac.a,通过编译,实际引用b.o实现