9. 目标文件放在一起-->静态库。
你的同事给出的目标文件太多了,从 one.o two.o …… …… 一直到 xxx.o。
好的,你如果真正想用,你的同事提供的这些现有的目标文件,你得做三件事:
一,查看自己的源文件,看看用到了哪些函数;
二,明确这些函数来自于哪个目标文件,本例中,很容易,因为函数的名字和目标文件的名字是对应的,比如one.o就会提供一个名称为one的函数;
三,使用 ld ,将你自己的目标文件和第二步中找到的那些目标文件链接起来,生成可执行文件。
第一步就是个很耗时的过程;
第二步其实也不简单,因为,你根本不能假设,函数的名字和目标文件的名字是对应的,本文只是举一个例子而已;
第三步嘛,也很麻烦,因为你要手动输入这些目标文件的名字,万一打错字怎么办?
所以,你的同事,将 one.o two.o …… …… 一直到 xxx.o 统一制作成一个文件,叫做 goodThings.a,这个 goodThings.a 就包含了所有的目标文件了。
你使用的时候,只需要这么做,假设你自己的目标文件叫做 main.o,
ld main.o goodThings.a -o go
简洁明了!一步成功! ld 这个命令会自动在 goodThings.a 中去查找 main.o 使用的目标文件,并链接起来。
好,正式介绍 goodThings.a 这个新“人物”。
这个东西就是静态库。(关于静态这个词,后面再讲)
说白了,就是目标文件的打包,放在一块而已。
ar 这个命令可以用来制作静态库:
ar -r goodThings.a one.o two.o three.o ………… xxx.o
这样就能把 one.o 一直到 xxx.o 放在 goodThings.a 里了。
你可以查看一个静态库文件里有哪些目标文件:
ar -t goodThings.a
不过,建议将静态库的名字叫成 libxxx.a 这样的格式,这样更符合命名规范,实际上是,这样的命名规范是有好处的。因为可以这样用:
ld main.o -L . -lxxx -o go
ld 会在本目录下去找 libxxx.a。当然,这里假设,你把 libxxx.a 放在本目录了。其中 -L . 就是说,在本目录下去找的意思。
10. 静态到动态。
前面说到了装载的概念,就是把程序从硬盘搬到内存去,从而开始执行。
可以简单的说:
静态:链接过程在装载之前已经完成。
动态:等到装载的时候再去找相应的库文件,进而链接。
关于静态,一劳永逸,所有的东西都在这里了,想什么时候执行就什么时候执行。
动态呢,不是这样,执行的时候,去找我需要什么,再链接,再装载。
讨论一下动态的好处。
举一个例子,看电视。
小明和小强都要看电视,于是他们一人背着一个电视,似乎,有点累。
小明说,把电视放到房间里吧,嗯,于是,他俩在一个房间里,打开两个电视,都在看一个台,似乎,有点浪费。
小明说,既然看一个台,那关一台,似乎,这样很好。
假如小明和小强同时用到了 one.o ,那么可以推出一个结果,小明和小强的 可执行文件里,一定都包含这个 one.o。
第一,浪费硬盘空间;(两份可执行文件都包含了 one.o )
第二,程序装载时,浪费内存。(因为 one.o 被装载了两次)
动态库,就可以解决以上两个问题。
同样的代码,硬盘上应该可以只存在一份,内存中也应该只存在一份,以达到节省的效果。
这就是为什么,动态链接,是在程序被装载的时候,才去链接。(因为早链接了,不就占硬盘空间了么)
这就是为什么,动态链接,可以节省内存。(因为相同的库,我只链接一次,放在内存里,第二份可执行文件依然可以共享这个库)