我不种田来不种菜,不下海来不钓鱼,不会织布不裁衣,不会行医不问药,这些跟我的生存状态密切相关的技能统统不会,按理我就该饿死、馋死、冻死、病死,反正各种死,但明显我还活着,这就给今天的扯蛋留下了谈资。
上述神迹发生的原因很简单,因为我们的社会极大分工,而不是像原始社会那样自给自足。我们每个人都做一个极小领域的细活,然后在一个大系统中大家彼此依赖,每个人的专注专业加速了细分领域的效率,而协同合作又节省了大家的成本和时间,最终大家都相互受益。
这种极大减少了低效重复劳动的做法,在编程世界里面,也是必须遵循的基本原则。而这些编写出来可以被重复使用的软件模块,就是库文件。在Linux下常见的是后缀为 .a 或者 .so 的文件,在Windows下常见的是后缀为 .dll 的文件。
下面就Linux系统,简单谈谈库的来龙去脉。假设有代码 wrap1.o 和 wrap2.o,将他们做成不同的库文件:
从上面的操作看到,库文件其实都是由一堆 *.o 文件组成的集合,当我们要用到这些代码的时候,就可以不必链接这些 *.o 文件或者其源文件,而只需要链接库文件即可,比如:
gcc main.c -o main -L ./lib -lx gcc main.c -o main -L ./lib -ly
上面的例子,就是链接了 libx.a 或者 liby.so,注意,库的名字是除去前缀 lib 和后缀之后的名字。
既然有静态库和动态库,那么他们有什么区别呢? 答案很简单,静态库相当于卖书的书店,动态库相当于看书的图书馆。他们各自有各自的优缺点:
书店的优点:
书店的缺点:
完全相对应地,来看看图书馆的情况。
图书馆的优点:
图书馆的缺点:
上面的几个优缺点相互权衡后你会发现,节省图书拷贝,减少重复代码是最关键的地方,因此动态库(图书馆)就比静态库(书店)更具优势。所以你会看到动态库用的更多。另外再补充一点,因为动态库编译之后,你并没有将代码拷到你的程序里,而是等到你程序运行的时候,才又来找到动态库执行所需代码。就像你去图书馆浏览了一遍目录,找到你需要的书,你并不会带走,而只是心里有底了,下次来的时候还是要找到这本书才能看。
因此,运行一个连接动态库的程序,一般要设置环境变量LD_LIBRARY_PATH来告知系统动态库的具体位置,好让运行时能找到它。另外一种办法是编译时就告诉系统以后运行时动态库的位置。比如上述的例子,可以写成:
gcc main.c -o main -L ./lib -ly -Wl,-rpath=./lib