makefile的链接顺序-c/c++的静态库链接顺序

13 篇文章 1 订阅

1.你有一个library或者是可执行文件,你可以这样查看他的依赖关系:

  • readelf -d <exe>
  • ldd  <exe>

2.查看某个. c文件引用了那些头文件

  gcc -M    :查看引用的全部头文件(包括系统头文件)

 gcc -MM :忽略系统头文件

3.对于library的查找

a.查找需要连接的符号名是 根据-L指定的路径顺序查找;从左往右找(如果符号有依赖,第一个-l库文件最先调用,如果它依赖于其它库,依赖的库应该放在它的后面,在后面继续寻找它的依赖,就像主obj依赖-l库一样;如果符号没有依赖,则第一个库最先调用,它后面的库里如果有同名符号函数则不会生效)

main_exe 依赖于->func1->func2->func3  依次对应libf1.a,libf2.a,libf3.a,也按这个顺序链接

b.不同 目录下的同名的库,只取最先调用的-l静态库(从左向右:即依次调用,最后生效的调用:即最右边的),后面同名库被忽略;

    示例1)如果几个库没有依赖。最先生效的是上层逻辑lib,最后生效的系统lib。(若有同名函数,生效的是最左边的-l库里面的函数)

    示例2)如果几个库有依赖。上层逻辑lib依赖于基础lib,那基础lib应该放到右边。

g++ ...  obj($?) -l(上层逻辑lib) -l(中间封装lib) -l(基础lib) -l(系统lib)  -o $@

4:对于符号的查找

从左向右查找,如果是主程序块和静态库,不能定位地址就报错: ‘undefined reference to: xxx’

如果是链接成动态库,则假设该符号在load 的时候地址重定位。如果找不到对应的动态库,则会在load的时候报:“undefined symbol: xxx“这样的错误。

5.在项目开发过层中尽量让lib是垂直关系,避免循环依赖;越是底层的库,越是往后面写!

正常情况下lib库是不会依赖其他lib库的,除非是静态库或者其他固定公用的库,否则会出现移植程序的时候出bug;

而强制的依赖关系是显式的写明在Makefile中,使主程序知道lib库是由依赖关系的,而不是平行调用;


main.cpp

#include <iostream>
#include "file_1.h"
using namespace std;

int main() {
    int n = func_foo1();
    cout << "ret=0x" << hex << n << endl;

    return 0;
}

file_1.cpp

#include "file_2.h"
int func_foo1(){
    int n = 1;

    n |= func_foo2();

    return n;
}

file_2.cpp

int func_foo2(){
    int n = 0x10;
    return n;
}

两个头文件file_1.h 和file_2.h里就分别只声明个函数。当然用编译宏包起来,防止重复包含。

int func_foo1();

int func_foo2();

g++ file_1.cpp -c  ; ar -crv libfile_1.a file_1.o    编静态库 libfile_1.a

g++ file_2.cpp -c  ; ar -crv libfile_2.a file_2.o    编静态库 libfile_2.a


g++ main.cpp -L. -lfile_1  会报错:

./libfile_1.a(file_1.o):在函数‘func_for1()’中:
file_1.cpp:(.text+0x10):对‘func_for2()’未定义的引用
collect2: 错误:ld 返回 1


g++ main.cpp -L. -lfile_2  报错
/tmp/ccnb6on0.o:在函数‘main’中:
main.cpp:(.text+0x9):对‘func_foo1()’未定义的引用
collect2: 错误:ld 返回 1


g++ main.cpp -L. -lfile_2 -lfile_1  这两个静态库顺序不对,会报错
./libfile_1.a(file_1.o):在函数‘func_foo1()’中:
file_1.cpp:(.text+0x10):对‘func_foo2()’未定义的引用
collect2: 错误:ld 返回 1


g++ main.cpp -L. -lfile_1 -lfile_2  可以编译成功,和静态库顺序有关。main.cpp依赖于libfile_1.a,而后者又依赖于libfile_2.a。elf文件a.out里面有file1和file2的所有符号(即使file_2里有func_unused,该符号也在nm里能看到)

./a.out  正常运行,打印ret=0x11


g++ main.cpp -L. -lfile_1 -lfile_2 -lfile_1new  假如 libfile_1new.a里面定义了同名函数func_foo1,实现不同。则本命令,最终调用的是file_1.a里面的实现。而变出来的bin文件里有file_1和file_2里面的所有符号(即使file_2里有func_unused,该符号也在nm里能看到)

g++ main.cpp -L. -lfile_1new -lfile_1 -lfile_2  ,调用的是最左边,第一个-l,最终./a.out里调用的是file_1new.a里面的实现。  只有file_1new里面的符号

g++ main.cpp -L. -lfile_2 -lfile_1new ;  两个库没依赖,交换顺序都能编过。都只有file_1new里有func_foo1,exe符号表里只有file_1new.a里面的符号,file2的符号全被抛弃了,main.cpp里用不上把整个file2的符号都抛弃了没用。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值