初识linux(16) 动静态库(手搓动静态库!)

目录

前导回顾

1. 手搓静态库

step1  编译获得同名.o文件

step2 ar -rc指令建立库

step3 将库安装到对应的路径下去

安装方法1:先将头文件都装到 /usr/include 路径下,再将库文件装到/lib64/ 路径下。

安装方法2:不安装到系统,在一个文件夹中使用

插曲:在makefile中完成编译与打包(便于讲解安装方法3) 

安装方法3:打包到其他文件夹使用

2. 手搓动态库

两种方法解决库运⾏搜索路径

1.在lib64中添加对应的.so库

2. 直接添加环境变量


前导回顾

什么是库
库是写好的现有的,成熟的,可以复⽤的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个⼈的代码都从零开始,因此库的存在意义⾮同寻常。
比如我们的<iostream>,<cstdlib>等等都是我们对库复用的体现。
静态库与动态库
举个例子,在写论文的时候,引用一句话,但是不将整篇文章都抄进去,而是将出处写在末尾,这就是动态库;但是如果将整篇文章都直接复制进去了,就是静态库
由此可见,静态库空间更大更笨,但是是在编译时直接编译好的,形成一个可执行程序,编译好之后就不依赖外部实现;动态库更省空间,但是是在程序运行时需要使用这个库的时候再去链接,依赖外部实现。

库文件的格式

静态库 .a[Linux] .lib[windows]
动态库 .so[Linux] .dll[windows]
注意, 本质上来说库是⼀种可执⾏代码的⼆进制形式,可以被操作系统载⼊内存执⾏。
因此库一定不是.c文件,而是.o文件的一个“集合”。

1. 手搓静态库

初识Linux(13) 由基础IO知识简易封装stdio.h中的FILE-优快云博客

(FILE就是C语言中描述文件的结构体,常用于:FILE* fp = fopen("log.txt","w" )等等,借助我们之前实现的库来完成以下操作) 

学习指令: 

$ ar   -rc   libmystdio.a   my_stdio.o my_string.o

ar是gnu下的归类工具,专门用于创建、修改和管理静态库(archive)的工具

r和c表示replace和create,也可以使用t指令来查看库的情况。

总的来说,库必须使用.o文件作为成员文件,避免了暴露源代码。

step1  编译获得同名.o文件

step2 ar -rc指令建立库

库的名字必须是lib开头,.a结束,.a结束后面可以跟版本等信息

如果多个文件:

如果一个文件:

step3 将库安装到对应的路径下去

安装方法1:先将头文件都装到 /usr/include 路径下,再将库文件装到/lib64/ 路径下。

                 

此时vim 一个main.c,已经能查看到我们自己的头文件可以使用了

             

假设此函数中国,我们只使用mfopen,退出vim后开始编译

出现一个链接式报错!

此时应该在gcc时加上-l指令

这是常见错误。

库的名字要去掉前缀和后缀,就能正常编译了。

也可以继续沿用刚刚的指令。

gcc -l

引入指定名字的第三方库。

-l后面直接接库名字,l表示link


安装方法2:不安装到系统,在一个文件夹中使用

如果不安装到系统中,只是 在一个文件夹中想使用:

首先是认不到头文件(因为没有放到/usr/include里!),

<>改" ",表示去包含当前路径下的自己实现的头文件。

                           

依然找不到,因为:gcc -l在查的时候默认在系统路径下找。

引入: gcc -L,告诉gcc查找库的时候也在-L后面的路径中找。


插曲:在makefile中完成编译与打包(便于讲解安装方法3) 

形成库与清理:

                                         

发布:

将写好的库和头文件打包到一个文件夹中去。

还可以再压缩一下:

  1 ibmstdio.a:mstdio.o
  2   @ar -rc $@ $^
  3 %.o:%.c
  4   @gcc -c $<
  5 
  6 .PHONY:
  7 clean:
  8   @rm -rf *.a *.o stdc
  9   @echo "clean done"
 10 
 11 .PHONY:
 12 output:
 13   @mkdir -p stdc/include
 14   @mkdir -p stdc/lib 
 15   @cp -f *.h stdc/include
 16   @cp -f *.a stdc/lib 
 17   @tar -czf stdc.tgz stdc   

模拟真实使用情景。

安装方法3:打包到其他文件夹使用

这样,在其他文件夹中,可以通过拷贝直接使用了:

将stdc.tar拷贝到一个新文件夹other中,先解压,不过当前的main函数和stdc中的内容还不在一个目录下。

             

因此,在main中想通过"mstdio"去找头文件也不现实。

引入gcc -I(大写i),在指定路径下去找头文件;-L只能告诉要在哪个文件夹里面链接,-l说明具体链哪个库。一个-I(大i)就能直接让gcc去里面找头文件

[lsnm]$ gcc main.c -Istdc/include -Lstdc/lib -lmstdio -o myexe

小结gcc在编译库三个问题:

头文件路径找不到(-I),库路径找不到(-L),库名称找不到(-l)


2. 手搓动态库

动态库(.so):程序在运⾏的时候才去链接动态库的代码,多个程序共享使⽤库的代码。
⼀个与动态库链接的可执⾏⽂件仅仅包含它⽤到的函数⼊⼝地址的⼀个表,⽽不是外部函数所在⽬标⽂件的整个机器码
在可执⾏⽂件开始运⾏以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中, 这个过程称为动态链接(dynamic linking)
        动态库可以在多个程序间共享,所以动态链接使得可执⾏⽂件更⼩,节省了磁盘空间。操作系统采⽤虚拟内存机制允许物理内存中的⼀份动态库被要⽤到该库的所有进程共⽤,节省了内存和磁盘空间。

动态库的命名一样,必须前缀lib开头,后缀是.so

形成库文件的时候直接用gcc,我们在之前静态库的makefile的基础上直接改写:

gcc -shared

gcc -fPIC

                     

-shared告诉gcc,生成的是一个.so动态库。而不是一个可执行程序

-fPIC让.o的链接信息里包含“位置无关码”(知道即可)

同样的三种方法:

直接拷进系统:

 就在本地使用:

顺便可以使用ldd查依赖的库,或测试一下动态库的特点:生成可执行程序之后删库,看一下是否还能运行。

不如果是静态库的话,只要实现了可执行程序,删库也一样能跑

动态库的编译和静态库一致,就算在同一文件下, 也要先说明-L.(在当前路径下找库),-l mystdio(在路径中找哪个库)

拷贝解压之后其他目录下使用:

gcc main.c -o myexe -Istdc/include -Lstdc/lib -lmstdio

编译成功,但却跑不起来。

因为系统找不到.so库!刚刚的操作是让编译器找到了.so库,执行程序时,操作系统将程序加载到内存,此时找不到了。

两种方法解决库运⾏搜索路径

如何告诉系统查找自己动态库的路径呢?系统通过查以下环境变量来确定找库的路径

环境变量:LOAD_LIBARY_PATH(整个环境变量中最长最大的那一个!)

使用env指令查看:

LOAD_LIBARY_PATH中包含了/lib64以及当前路径 

也就是对应的第一种和第二种安装方法都是可行的

1.在lib64中添加对应的.so库

除了可以直接拷贝,也可以使用一个软链接的方式将当前的libmstdio.so给ln到/lib64中

这个时候ldd就能查到库对应的信息了。

采用unlink再回到刚刚的状态,便于后续实验。

2. 直接添加环境变量

直接export,将希望的路径给加进去

偏底层的路径,建议都使用绝对路径!!


在以前提到过,如果动静态库同时存在,系统会使用动态库。

强制静态库:在编译的时候加一个-static


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值