当前位置: 首页 > news >正文

库的制作与原理

在这里插入图片描述

前言:

(补充上一篇)

1.硬链接

[root@VM-8-2-centos lesson13]# touch test.c
[root@VM-8-2-centos lesson13]# ll
total 0
-rw-r--r-- 1 root root 0 Aug 13 14:06 test.c
[root@VM-8-2-centos lesson13]# echo "hello world">test.c
[root@VM-8-2-centos lesson13]# ll
total 4
-rw-r--r-- 1 root root 12 Aug 13 14:07 test.c
[root@VM-8-2-centos lesson13]# cat test.c
hello world
[root@VM-8-2-centos lesson13]# ls -lni
total 4
1186486 -rw-r--r-- 1 0 0 12 Aug 13 14:07 test.c
[root@VM-8-2-centos lesson13]# ls -li
total 4
1186486 -rw-r--r-- 1 root root 12 Aug 13 14:07 test.c
[root@VM-8-2-centos lesson13]# ln test.c hard//创建硬链接
[root@VM-8-2-centos lesson13]# ll
total 8
-rw-r--r-- 2 root root 12 Aug 13 14:07 hard
-rw-r--r-- 2 root root 12 Aug 13 14:07 test.c
[root@VM-8-2-centos lesson13]# ll -li
total 8
1186486 -rw-r--r-- 2 root root 12 Aug 13 14:07 hard
1186486 -rw-r--r-- 2 root root 12 Aug 13 14:07 test.c[root@VM-8-2-centos lesson13]# unlink hard//删除硬链接
[root@VM-8-2-centos lesson13]# ll
total 8-rw-r--r-- 1 root root   12 Aug 13 14:07 test.c
[root@VM-8-2-centos lesson13]# mkdir dir//创建目录
[root@VM-8-2-centos lesson13]# ll
total 8
drwxr-xr-x 2 root root 4096 Aug 13 14:11 dir
-rw-r--r-- 1 root root   12 Aug 13 14:07 test.c
[root@VM-8-2-centos lesson13]# ls -li
total 8
1186491 drwxr-xr-x 2 root root 4096 Aug 13 14:11 dir
1186486 -rw-r--r-- 1 root root   12 Aug 13 14:07 test.c
[root@VM-8-2-centos lesson13]# ln dir hard//给目录创建硬链接
ln: ‘dir’: hard link not allowed for directory//失败?!!!//硬链接只能给普通文件建立,Linux系统,不支持给目录建立硬链接![root@VM-8-2-centos lesson13]# ll
total 8
drwxr-xr-x 2 root root 4096 Aug 13 14:11 dir
-rw-r--r-- 1 root root   12 Aug 13 14:07 test.c
[root@VM-8-2-centos lesson13]# ln -s dir hard//给目录建立软链接
[root@VM-8-2-centos lesson13]# ll -li
total 8
1186491 drwxr-xr-x 2 root root 4096 Aug 13 14:11 dir
1186492 lrwxrwxrwx 1 root root    3 Aug 13 14:21 hard -> dir//成功!
1186486 -rw-r--r-- 1 root root   12 Aug 13 14:07 test.c
//软链接可以给目录创建,也可以给普通文件建立

之前有说过.和…本质就是对目录的硬连接??

[root@VM-8-2-centos lesson13]# ls dir/. -li
total 0
[root@VM-8-2-centos lesson13]# ls dir/. -dli
1186491 drwxr-xr-x 2 root root 4096 Aug 13 14:11 dir/.  //此处的inode和当前目录dir的inode是一样的
[root@VM-8-2-centos lesson13]# ls dir/.. -dli
1185980 drwxr-xr-x 3 root root 4096 Aug 13 14:21 dir/..  //此处的inode和当前路径的上级路径的inode是一样的
[root@VM-8-2-centos lesson13]# ls -lid .
1185980 drwxr-xr-x 3 root root 4096 Aug 13 14:21 .

所以这里就矛盾了。不是说不可以给目录建立硬链接吗?而这就是Linux系统自己给当前目录和上级目录建立的硬链接,除此之外,它不准任何用户给任何目录建立硬链接!

为什么?

同学们,若允许给目录建立硬链接,我们可以这样做:比如针对 Linux 系统的树状路径结构,从根目录开始,我们可以给某些节点建立硬链接。

比如,我们可以新建一个名为“hard”“my hard”之类的文件名,让它直接作为根目录的硬链接。

但问题是,若系统允许对目录(包括根目录)建立硬链接,当系统中存在大量这样的路径时,会出现什么情况呢?

容易形成路径环问题。所以不允许用户自己给目录建立硬链接了。

.和…:名字特殊,做特殊处理即可!——方便命令行操作!

为什么软链接带l,硬链接不用?

软链接(符号链接)用 ln -s 创建, -s 表明其通过路径符号指向目标,是特殊文件存路径信息;硬链接用 ln 直接创建,因共享 inode ,是为文件加新名称,属基础文件操作,无需额外标识,故软链接操作带 l ( -s 关联符号链接逻辑 ),硬链接不用 。


库的制作与原理

1.什么是库?

库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能 每个⼈的代码都从零开始,因此库的存在意义非同寻常。

本质上来说库是⼀种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:

  • 静态库 .a[Linux]、.lib[windows]
  • 动态库 .so[Linux]、.dll[windows]

2.静态库的制作

1.动静态库中,不用包含main函数。(因为我们在编译链接的时候会和自己写的main函数冲突)

2.静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中,程序运行的时候将不再需要静态库。

3.⼀个可执行程序可能用到许多的库,这些库运行有的是静态库,有的是动态库,而我们的编译默认为动态链接库,只有在该库下找不到动态.so的时候才会采用同名静态库。我们也可以使用gcc 的-static 强转设置链接静态库。

预备工作:下面是我制作静态库的一些示例代码。

[root@VM-8-2-centos my_stdio]#  ll
total 16
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   44 Aug 13 21:49 mystring.h
//mystdio.c
#include "mystdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>static MyFile *BuyFile(int fd, int flag)
{MyFile *f = (MyFile*)malloc(sizeof(MyFile));if(f == NULL) return NULL;f->bufferlen = 0;f->fileno = fd;f->flag = flag;f->flush_method = LINE_FLUSH;memset(f->outbuffer, 0, sizeof(f->outbuffer));return f;
}MyFile *MyFopen(const char *path, const char *mode)
{int fd = -1;int flag = 0;if(strcmp(mode, "w") == 0){flag = O_CREAT | O_WRONLY | O_TRUNC;fd = open(path, flag, 0666);}else if(strcmp(mode, "a") == 0){flag = O_CREAT | O_WRONLY | O_APPEND;fd = open(path, flag, 0666);}else if(strcmp(mode, "r") == 0){flag = O_RDWR;fd = open(path, flag);}else{//TODO}if(fd < 0) return NULL;return BuyFile(fd, flag);
}
void MyFclose(MyFile *file)
{if(file->fileno < 0) return;MyFFlush(file);close(file->fileno);free(file);
}
int MyFwrite(MyFile *file, void *str, int len)
{// 1. 拷贝memcpy(file->outbuffer+file->bufferlen, str, len);file->bufferlen += len;// 2. 尝试判断是否满足刷新条件!if((file->flush_method & LINE_FLUSH) && file->outbuffer[file->bufferlen-1] == '\n'){MyFFlush(file);}return 0;
}
void MyFFlush(MyFile *file)
{if(file->bufferlen <= 0) return;// 把数据从用户拷贝到内核文件缓冲区中int n = write(file->fileno, file->outbuffer, file->bufferlen);(void)n;fsync(file->fileno);file->bufferlen = 0;}
//mystdio.h
#pragma once
#include<stdio.h>
#define MAX 1024#define NONE_FLUSH (1<<0)
#define LINE_FLUSH (1<<1)
#define FULL_FLUSH (1<<2)typedef struct IO_FILE
{int fileno;int flag;char outbuffer[MAX];int bufferlen;int flush_method;
}MyFile;MyFile* MyFopen(const char* path,const char* mode);
void MyFclose(MyFile*);
int MyFwrite(MyFile*,void* str,int len);
void MyFFlush(MyFile*);
//mystring.c
#include "mystring.h"
int my_strlen(const char*s)
{const char* start=s;while(*s){s++;}return s-start;
}
//mystring.h
#pragma once;
int my_strlen(const char*s);

假设上面的代码是今天老师布置的作业,要求大家自己实现几个C语言库函数,你按要求在mystdio.c和mystring.c中写了接口的实现,在mystdio.h和mystring.h写了接口的声明。

你的同桌张三,得知你写完了,让你把代码拷贝给他,你就把当前目录下的所有相关内容都拷贝到了他的目录下。

张三拿到你的代码后,觉得老师只看最终结果,于是自己写了一个调用这些接口的文件usercode.c,用来完成作业。

// usercode.c
#include "mystdio.h"
#include "mystring.h"
#include <string.h>
#include <unistd.h>int main()
{MyFile* filep=MyFopen("./log.txt","a");if(!filep){printf("fopen error!\n");return 1;}int cnt=10;while(cnt--){char* msg=(char*)"hello myfile!!!!";MyFwrite(filep,msg,strlen(msg));MyFFlush(filep);printf("buffer:%s\n",filep->outbuffer);sleep(1);}MyFclose(filep);//FILE* fpconst char* str="hello world!\n";printf("strlen:%d\n",my_strlen(str));return 0;
}
[root@VM-8-2-centos zhangsan]# ll	//张三给老师展示的内容
total 20
-rw-r--r-- 1 root root 1700 Aug 13 22:08 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 22:08 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 22:08 mystring.c
-rw-r--r-- 1 root root   44 Aug 13 22:08 mystring.h
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# gcc *.c	//编译
[root@VM-8-2-centos zhangsan]# ll
total 36
-rwxr-xr-x 1 root root 13336 Aug 14 11:17 a.out  //形成一个可执行程序
-rw-r--r-- 1 root root  1700 Aug 13 22:08 mystdio.c
-rw-r--r-- 1 root root   392 Aug 13 22:08 mystdio.h
-rw-r--r-- 1 root root   126 Aug 13 22:08 mystring.c
-rw-r--r-- 1 root root    43 Aug 14 11:17 mystring.h
-rw-r--r-- 1 root root   529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# ./a.out  //运行
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
^C
[root@VM-8-2-centos zhangsan]# ll
total 40
-rwxr-xr-x 1 root root 13336 Aug 14 11:17 a.out
-rw-r--r-- 1 root root    80 Aug 14 11:18 log.txt
-rw-r--r-- 1 root root  1700 Aug 13 22:08 mystdio.c
-rw-r--r-- 1 root root   392 Aug 13 22:08 mystdio.h
-rw-r--r-- 1 root root   126 Aug 13 22:08 mystring.c
-rw-r--r-- 1 root root    43 Aug 14 11:17 mystring.h
-rw-r--r-- 1 root root   529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# cat log.txt
hello myfile!!!!hello myfile!!!!hello myfile!!!!hello myfile!!!!hello myfile!!!!

老师觉得张三写的挺好的,想看一下张三的源文件。

结果露馅了,然后就发现张三是抄你的。

又过了一段时间,老师又让写一部分库的封装。然后你想起了张三请你吃了那么多次饭,然后你脸皮薄,不好意思拒绝他。老是要你写的东西,但是上次又连累你扣了那么多分儿,那怎么办呢??

这样吧,我有个办法,我不想把我的源文件给他,因为一给源文件就暴露了,我下面这样。

[root@VM-8-2-centos my_stdio]# gcc -c mystdio.c //-C就是把我们的源文件经过预处理、编译和汇编变成同名的.O文件。
[root@VM-8-2-centos my_stdio]# ll
total 20
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3104 Aug 14 11:32 mystdio.o	//目标文件
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   44 Aug 13 21:49 mystring.h
[root@VM-8-2-centos my_stdio]# gcc -c mystring.c	//同上
[root@VM-8-2-centos my_stdio]# ll
total 24
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3104 Aug 14 11:32 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 14 11:35 mystring.o

我之前文章有提到过,一旦有多文件,把所有的多文件编译成.o,然后把.o文件最后经过链接,就可以形成可执行程序。其实我们把.o文件交给张三,最后就可以形成可执行程序,我们这样就不会暴露我们的源代码了。

[root@VM-8-2-centos my_stdio]# mv *.o ../zhangsan/
[root@VM-8-2-centos my_stdio]# cd ../zhangsan/
[root@VM-8-2-centos zhangsan]# ll
total 12
-rw-r--r-- 1 root root 3104 Aug 14 11:32 mystdio.o
-rw-r--r-- 1 root root 1272 Aug 14 11:35 mystring.o
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c

但张三看着.o文件不知道能干啥,也有点蒙圈了,然后他打开.o的里面发现都是乱码,就回去找你要个交代。

你然后才想起来,自己只告诉了张三.o里面有对应的方法,但是没告诉张三这个怎么用,让张三等一下。

[root@VM-8-2-centos my_stdio]# ll
total 16
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
[root@VM-8-2-centos my_stdio]# cp *.h ../zhangsan/ -f	//把头文件拷贝给张三
[root@VM-8-2-centos my_stdio]# ll
total 16
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
[root@VM-8-2-centos my_stdio]# cd ../zhangsan/
[root@VM-8-2-centos zhangsan]# ll
total 20
-rw-r--r-- 1 root root  392 Aug 14 11:46 mystdio.h
-rw-r--r-- 1 root root 3104 Aug 14 11:32 mystdio.o
-rw-r--r-- 1 root root   43 Aug 14 11:46 mystring.h
-rw-r--r-- 1 root root 1272 Aug 14 11:35 mystring.o
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
//张三一看果然多了两个头文件

张三还是不太懂,问你给.h有什么用呢?

然后你就说:你不是不会用吗?.h包含了我用的方法的声明,什么参数列表、返回值你都有了,结构类型也都有了。后面你要过老师这一关,你照我的.h调函数就可以了。

这里我们理解头文件有了一个全新视角:头文件的本质其实是对源文件的方法说明文档。

张三懂了!所以他不再需要所谓的源文件了,你把.h给他,他就知道怎么用了,要形成可执行程序,把.o给他,这样老师就发现不了了。张三在写自己代码时,用到哪些方法,把头文件包进来就可以。

那要怎么编呢?把所有的文件变成.o,做个链接不就行了。

[root@VM-8-2-centos zhangsan]# gcc -c usercode.c	//张三先把他写的文件-c变成.o
[root@VM-8-2-centos zhangsan]# ll
total 24
-rw-r--r-- 1 root root  392 Aug 14 11:46 mystdio.h
-rw-r--r-- 1 root root 3104 Aug 14 11:32 mystdio.o
-rw-r--r-- 1 root root   43 Aug 14 11:46 mystring.h
-rw-r--r-- 1 root root 1272 Aug 14 11:35 mystring.o
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
-rw-r--r-- 1 root root 2376 Aug 14 11:58 usercode.o
//从这可以看出来,我们在预处理、编译和汇编的时候,根本不需要任何源文件,只需要各种编你自己的,跟别人没关系,只有链接时才有关系
[root@VM-8-2-centos zhangsan]# gcc *.o	//把所有的.o我们gcc链接一下
[root@VM-8-2-centos zhangsan]# ll
total 40
-rwxr-xr-x 1 root root 13336 Aug 14 11:59 a.out		//可执行程序形成
-rw-r--r-- 1 root root   392 Aug 14 11:46 mystdio.h
-rw-r--r-- 1 root root  3104 Aug 14 11:32 mystdio.o
-rw-r--r-- 1 root root    43 Aug 14 11:46 mystring.h
-rw-r--r-- 1 root root  1272 Aug 14 11:35 mystring.o
-rw-r--r-- 1 root root   529 Aug 14 10:59 usercode.c
-rw-r--r-- 1 root root  2376 Aug 14 11:58 usercode.o
[root@VM-8-2-centos zhangsan]# ./a.out
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
^C
[root@VM-8-2-centos zhangsan]# ll
total 44
-rwxr-xr-x 1 root root 13336 Aug 14 11:59 a.out
-rw-r--r-- 1 root root   176 Aug 14 11:59 log.txt
-rw-r--r-- 1 root root   392 Aug 14 11:46 mystdio.h
-rw-r--r-- 1 root root  3104 Aug 14 11:32 mystdio.o
-rw-r--r-- 1 root root    43 Aug 14 11:46 mystring.h
-rw-r--r-- 1 root root  1272 Aug 14 11:35 mystring.o
-rw-r--r-- 1 root root   529 Aug 14 10:59 usercode.c
-rw-r--r-- 1 root root  2376 Aug 14 11:58 usercode.o

我懂了!原来只要把我所对应的.o文件和.h文件打包交给别人就可以实现库的效果。所以,我们经常说头文件包含了方法的声明,库包含了方法的实现——原来所有的库(无论是动还是静),本质都是源文件对应的.o!

这样不是挺好的嘛,那静态库产生的缘由是什么?

一开始,张三觉得不用认真写代码方法,只写调用逻辑就行,因为他觉得老师不查。但后来老师布置的作业越来越多,涉及上千个.c和.h文件。

有一次,张三需要紧急拿着作业去老师办公室验收,就让李四把写的库给他。可李四有几千个文件,得一个个通过QQ发给张三,这让张三特别麻烦,边下载边抱怨。

这是因为库通常较大,.o文件很多,且缺一不可,少一个方法就调用不起来;而.h文件是明文,供用户查看方法调用方式,可用直接给张三。

于是,为了解决这个问题,就有了将所有.o文件打包的办法,形成静态库,这样你再给张三提供库时就方便多了。

静态库本质,就是.o打了一个包!!

我们的Linux系统给我们提供了一个方法,这个方法就是给我们提供一个工具,可以把所有.o文件打包成一个压缩的文件,可以被gcc直接识别, 也就是不用解包,直接gcc链接它,就直接能用了。

[root@VM-8-2-centos my_stdio]# ll
total 16
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
[root@VM-8-2-centos my_stdio]# gcc -c *.c
[root@VM-8-2-centos my_stdio]# ll
total 24
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3104 Aug 14 13:55 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 14 13:55 mystring.o
[root@VM-8-2-centos my_stdio]# ar -rc libmyc.a *.o
[root@VM-8-2-centos my_stdio]# ll
total 32
-rw-r--r-- 1 root root 4634 Aug 14 14:06 libmyc.a
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3104 Aug 14 13:55 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 14 13:55 mystring.o

ar(Archive的简称,静态库就是一个归档文件)

.a静态库,本质是一种归档文件,不需要使用者解包,而用gcc/g++直接进行链接即可!

-rc:replace and create (需要替换的替换,需要新增的新增)

静态库的命名一般以lib为开头,以.a为结尾。真正的名字是夹在中间的部分例如myc。

接下来,张三又给你要库的时候,直接拷贝我们准备好的库给张三即可。

[root@VM-8-2-centos zhangsan]# ll
total 4
-rw-r--r-- 1 root root 529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# cp ../my_stdio/*.a .		
[root@VM-8-2-centos zhangsan]# ll
total 12
-rw-r--r-- 1 root root 4634 Aug 14 19:22 libmyc.a
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c

张三问你这怎么用啊?

你说不会用正常哈,是因为库里的实现在库里打包好了,我现在把我的手册给你。

[root@VM-8-2-centos zhangsan]# cp ../my_stdio/*.h .
[root@VM-8-2-centos zhangsan]# ll
total 20
-rw-r--r-- 1 root root 4634 Aug 14 19:22 libmyc.a
-rw-r--r-- 1 root root  392 Aug 14 19:27 mystdio.h
-rw-r--r-- 1 root root   43 Aug 14 19:27 mystring.h
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c

你说,张三,从今天开始,我自己实现的方法都在.h里。

[root@VM-8-2-centos zhangsan]# vim usercode.c
[root@VM-8-2-centos zhangsan]# gcc -c usercode.c
[root@VM-8-2-centos zhangsan]# ll
total 24
-rw-r--r-- 1 root root 4634 Aug 14 19:22 libmyc.a
-rw-r--r-- 1 root root  392 Aug 14 19:27 mystdio.h
-rw-r--r-- 1 root root   43 Aug 14 19:27 mystring.h
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
-rw-r--r-- 1 root root 2376 Aug 14 19:30 usercode.o

要用的话正常调用就行,可是。。。

[root@VM-8-2-centos zhangsan]#  gcc -o usercode usercode.o
usercode.o: In function `main':
usercode.c:(.text+0x13): undefined reference to `MyFopen'
usercode.c:(.text+0x64): undefined reference to `MyFwrite'
usercode.c:(.text+0x70): undefined reference to `MyFFlush'
usercode.c:(.text+0xad): undefined reference to `MyFclose'
usercode.c:(.text+0xc1): undefined reference to `my_strlen'
collect2: error: ld returned 1 exit status

这里出现了链接式报错。为什么呢?原来它找不到这些库文件。

[root@VM-8-2-centos zhangsan]# gcc -o usercode usercode.o -llibmyc.a	//-l关联库
/usr/bin/ld: cannot find -llibmyc.a
collect2: error: ld returned 1 exit status
[root@VM-8-2-centos zhangsan]# gcc -o usercode usercode.o -lmyc		//库名规范是libXXX.a,则用-lXXX
/usr/bin/ld: cannot find -lmyc
collect2: error: ld returned 1 exit status
[root@VM-8-2-centos zhangsan]# ll
total 24
-rw-r--r-- 1 root root 4634 Aug 14 19:22 libmyc.a	//生成成功
-rw-r--r-- 1 root root  392 Aug 14 19:27 mystdio.h
-rw-r--r-- 1 root root   43 Aug 14 19:27 mystring.h
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
-rw-r--r-- 1 root root 2376 Aug 14 19:30 usercode.o
[root@VM-8-2-centos zhangsan]# gcc -o usercode usercode.o -lmyc
/usr/bin/ld: cannot find -lmyc	//找不到!?
collect2: error: ld returned 1 exit status
[root@VM-8-2-centos zhangsan]# gcc -o usercode usercode.o -L. -lmyc		//我们还要-L指定库路径,这里是在当前文件
[root@VM-8-2-centos zhangsan]# ll
total 40
-rw-r--r-- 1 root root  4634 Aug 14 19:22 libmyc.a
-rw-r--r-- 1 root root   392 Aug 14 19:27 mystdio.h
-rw-r--r-- 1 root root    43 Aug 14 19:27 mystring.h
-rwxr-xr-x 1 root root 13336 Aug 14 19:42 usercode
-rw-r--r-- 1 root root   529 Aug 14 10:59 usercode.c
-rw-r--r-- 1 root root  2376 Aug 14 19:30 usercode.o
[root@VM-8-2-centos zhangsan]# ./usercode
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
^C

在gcc -o usercode usercode.o -L. -lmyc中,-L代表去哪里找库,-l代表找什么库!命令中带空格也可以。

[root@VM-8-2-centos zhangsan]# gcc -o usercode usercode.o -L . -l myc
[root@VM-8-2-centos zhangsan]# ll
total 44
-rw-r--r-- 1 root root  4634 Aug 14 19:22 libmyc.a
-rw-r--r-- 1 root root    64 Aug 14 19:42 log.txt
-rw-r--r-- 1 root root   392 Aug 14 19:27 mystdio.h
-rw-r--r-- 1 root root    43 Aug 14 19:27 mystring.h
-rwxr-xr-x 1 root root 13336 Aug 14 19:45 usercode
-rw-r--r-- 1 root root   529 Aug 14 10:59 usercode.c
-rw-r--r-- 1 root root  2376 Aug 14 19:30 usercode.o

如果我们要连接任何非C/C++标准库(包括其他外部或者我们自己写的),都需要指明-L -l,来告诉别人,我要去哪里找这个库(路径),我要找什么库(库名)。

后来你变得越来越专业了,你想起还有很多人也找你要作业,每次你都要给他们发一大堆.h和.a。而且我们已经构建出一个库的概念,每次要都要给他们解释头文件在哪,是干啥的,库文件在哪,是干啥的。

从现在开始,你要定标准了。

[root@VM-8-2-centos my_stdio]# ll
total 32
-rw-r--r-- 1 root root 4634 Aug 14 14:06 libmyc.a
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3104 Aug 14 13:55 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 14 13:55 mystring.o
[root@VM-8-2-centos my_stdio]# mkdir lib	//创建一个空目录
[root@VM-8-2-centos my_stdio]# ll
total 36
drwxr-xr-x 2 root root 4096 Aug 14 20:11 lib
-rw-r--r-- 1 root root 4634 Aug 14 14:06 libmyc.a
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3104 Aug 14 13:55 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 14 13:55 mystring.o
[root@VM-8-2-centos my_stdio]# mkdir -p lib/include	//创建一个路径lib/include
[root@VM-8-2-centos my_stdio]# mkdir -p lib/mylib	//创建一个路径lib/mylib
[root@VM-8-2-centos my_stdio]# tree lib	//显示一下
lib
|-- include
`-- mylib2 directories, 0 files
[root@VM-8-2-centos my_stdio]# cp *.h lib/include/	//把当前所有的.h文件放在lib/include1的路径下
[root@VM-8-2-centos my_stdio]# cp *.a lib/mylib	//把当前所有的.a文件放在放在lib/mylib文件下
[root@VM-8-2-centos my_stdio]# tree lib	//显示一下
lib
|-- include
|   |-- mystdio.h
|   `-- mystring.h
`-- mylib`-- libmyc.a2 directories, 3 files
[root@VM-8-2-centos my_stdio]# ll
total 36
drwxr-xr-x 4 root root 4096 Aug 14 20:12 lib
-rw-r--r-- 1 root root 4634 Aug 14 14:06 libmyc.a
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3104 Aug 14 13:55 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 14 13:55 mystring.o
[root@VM-8-2-centos my_stdio]# tree . 	//显示当前路径
.
|-- lib
|   |-- include
|   |   |-- mystdio.h
|   |   `-- mystring.h
|   `-- mylib
|       `-- libmyc.a
|-- libmyc.a
|-- mystdio.c
|-- mystdio.h
|-- mystdio.o
|-- mystring.c
|-- mystring.h
`-- mystring.o3 directories, 10 files
[root@VM-8-2-centos my_stdio]# tar czf lib.tgz lib 	//压缩lib目录
[root@VM-8-2-centos my_stdio]# ll
total 40
drwxr-xr-x 4 root root 4096 Aug 14 20:12 lib
-rw-r--r-- 1 root root 4634 Aug 14 14:06 libmyc.a
-rw-r--r-- 1 root root 1806 Aug 14 20:14 lib.tgz
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3104 Aug 14 13:55 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 14 13:55 mystring.o

你把所有的文件放在一个目录里,压缩,从此上传到官网,不再解释。

知道你把代码公开后,张三就不再来找你,他直接去官网下载代码。

[root@VM-8-2-centos zhangsan]# ll
total 4
-rw-r--r-- 1 root root 529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# cp ../my_stdio/lib.tgz .		//下载
[root@VM-8-2-centos zhangsan]# ll
total 8
-rw-r--r-- 1 root root 1806 Aug 14 20:20 lib.tgz
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# tar xzf lib.tgz		//解包
[root@VM-8-2-centos zhangsan]# ll
total 12
drwxr-xr-x 4 root root 4096 Aug 14 20:12 lib
-rw-r--r-- 1 root root 1806 Aug 14 20:20 lib.tgz
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# rm lib.tgz -rf	//解包之后,之前的压缩包就可以删了
[root@VM-8-2-centos zhangsan]# ll
total 8
drwxr-xr-x 4 root root 4096 Aug 14 20:12 lib
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# tree .
.
|-- lib
|   |-- include
|   |   |-- mystdio.h
|   |   `-- mystring.h
|   `-- mylib
|       `-- libmyc.a
`-- usercode.c3 directories, 4 files

但是?!!他写好代码后,发现他的源文件都编不成.o了??why?

[root@VM-8-2-centos zhangsan]# vim usercode.c
[root@VM-8-2-centos zhangsan]# gcc -c usercode.c
usercode.c:1:21: fatal error: mystdio.h: No such file or directory#include "mystdio.h"^
compilation terminated.

发现文件找不到头文件, 张三提供的这个库下的.h,既不在当前路径下,也不在系统里。他这个系统属于用户自定义路径下。那么我们需要告诉张三的代码找头文件需要去哪里找,所以我们要学-I(指定头文件搜索路径)。

[root@VM-8-2-centos zhangsan]# gcc -c usercode.c -I ./lib/include
[root@VM-8-2-centos zhangsan]# ll
total 12
drwxr-xr-x 4 root root 4096 Aug 14 20:12 lib
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
-rw-r--r-- 1 root root 2376 Aug 14 20:43 usercode.o

此时,系统不仅要在当前路径下和系统默认路径找,也要去-I后面的路径下找所需的头文件。

如果我们想一次性的形成可执行程序我们可以用下面的这些命令。

[root@VM-8-2-centos zhangsan]# gcc -o usercode usercode.c -I ./lib/include -L ./lib/mylib/ -l myc
[root@VM-8-2-centos zhangsan]# ll
total 28
drwxr-xr-x 4 root root  4096 Aug 14 20:12 lib
-rwxr-xr-x 1 root root 13336 Aug 14 20:49 usercode
-rw-r--r-- 1 root root   529 Aug 14 10:59 usercode.c
-rw-r--r-- 1 root root  2376 Aug 14 20:43 usercode.o
[root@VM-8-2-centos zhangsan]# ./usercode
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
^C

如果我们写头文件的时候可以直接带上路径吗?

在这里插入图片描述

可以!如果这样写,就不需要再带-I了。

库,也是要被安装到系统中的!!

任何人所写的库,将来也是要被安装到系统里的。

Windows一样。

问题核心:gcc默认情况下找不到对应的库文件和头文件,需要手动添加大量选项才能编译链接。

系统默认搜索路径:

  • 头文件默认搜索路径:user/include目录。
  • 库文件默认搜索路径:系统目录(如lib64目录)。

解决方法:

  • 将第三方库的头文件拷贝到系统的user include目录,使其被系统默认搜索到。

  • 将库文件(如.lib、.a文件)拷贝到系统的库文件目录(如lib64目录),让系统能默认找到。

效果:完成上述拷贝后,使用该第三方库时,无需再手动指定库和头文件路径,gcc可直接编译链接代码(如编译.c文件生成可执行程序)。

[root@VM-8-2-centos zhangsan]# ll
total 32
drwxr-xr-x 4 root root  4096 Aug 14 20:12 lib
-rw-r--r-- 1 root root    64 Aug 14 21:17 log.txt
-rwxr-xr-x 1 root root 13336 Aug 14 20:49 usercode
-rw-r--r-- 1 root root   529 Aug 14 10:59 usercode.c
-rw-r--r-- 1 root root  2376 Aug 14 20:43 usercode.o
[root@VM-8-2-centos zhangsan]# tree lib/
lib/
|-- include
|   |-- mystdio.h
|   `-- mystring.h
`-- mylib`-- libmyc.a2 directories, 3 files
[root@VM-8-2-centos zhangsan]# sudo cp lib/include/* /usr/include/	
[root@VM-8-2-centos zhangsan]# ls /usr/include/my*
/usr/include/mystdio.h  /usr/include/mystring.h
[root@VM-8-2-centos zhangsan]# sudo cp lib/mylib/libmyc.a /lib64
[root@VM-8-2-centos zhangsan]# ls /lib64/libmy*
/lib64/libmyc.a

在试着编一下。

[root@VM-8-2-centos zhangsan]# ll
total 4
-rw-r--r-- 1 root root 529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# gcc usercode.c/tmp/cceSxZM5.o: In function `main':
usercode.c:(.text+0x13): undefined reference to `MyFopen'
usercode.c:(.text+0x64): undefined reference to `MyFwrite'
usercode.c:(.text+0x70): undefined reference to `MyFFlush'
usercode.c:(.text+0xad): undefined reference to `MyFclose'
usercode.c:(.text+0xc1): undefined reference to `my_strlen'
collect2: error: ld returned 1 exit status
[root@VM-8-2-centos zhangsan]# gcc usercode.c -lmyc
//以前使用c语言的时候不需要带任何选项了,但你今天要链接的库仍然是一个第三方库。
[root@VM-8-2-centos zhangsan]# ll
total 20
-rwxr-xr-x 1 root root 13336 Aug 14 21:54 a.out
-rw-r--r-- 1 root root   529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# ./a.out
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
^C

对于库所谓的安装,其实就是把库,对应的头文件和库文件拷贝到系统指定路径下,那么将来等你编译代码时,只要链接指明库名称,gcc就自动找你的头文件,对应的库文件,进而链接形成可执行。

[root@VM-8-2-centos zhangsan]# ldd a.outlinux-vdso.so.1 =>  (0x00007ffce2f42000)libc.so.6 => /lib64/libc.so.6 (0x00007fcefab23000)/lib64/ld-linux-x86-64.so.2 (0x00007fcefaef1000)
//ldd这个命令是为了查看一个可执行程序关于哪个库的
[root@VM-8-2-centos zhangsan]# ls /lib64/libc.a
/lib64/libc.a//这是我们c语言的静态库。可是为什么我们在链接c语言的时候,不需要指明-lc呢?那是因为gcc/g++默认就能认识c语言标准库,因为gcc/g++默认就是c/c++的编译器
//而我们写的,它们不认识,所以要告诉编译器我们要链接这个库

我们不用了,记得删掉,不要污染我们系统默认的路径

[root@VM-8-2-centos my_stdio]# sudo rm -f /usr/include/mystdio.h
[root@VM-8-2-centos my_stdio]# sudo rm -f /usr/include/mystring.h
[root@VM-8-2-centos my_stdio]# sudo rm -f /lib64/libmyc.a

ldd就是查看当前你这个用户所依赖的库,查的时候,我们发现并没有我们刚刚所设置的库。
why? 因为静态库的代码会被完整“拷贝”并合并到最终的可执行程序(如a.out)里,如果使用gcc编译时,要实现完全静态链接,需要使用-static选项,没加的话,编译器默认采用动态链接的方式,或部分静态链接。

[root@VM-8-2-centos zhangsan]# ldd a.outlinux-vdso.so.1 =>  (0x00007ffcc03dd000)libc.so.6 => /lib64/libc.so.6 (0x00007f97564b9000)/lib64/ld-linux-x86-64.so.2 (0x00007f9756887000)

我是一个库的制作者,我要制作一个静态库,这个静态库可不是只有静态库交给别人,我要给别人把我要做的工作全都弄好。所以在这里我们就需要给大家演示一下。

[root@VM-8-2-centos my_stdio]# ll
total 16
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
[root@VM-8-2-centos my_stdio]# touch Makefile
[root@VM-8-2-centos my_stdio]# ll
total 16
-rw-r--r-- 1 root root    0 Aug 15 00:06 Makefile
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
[root@VM-8-2-centos my_stdio]# vim Makefile
[root@VM-8-2-centos my_stdio]# ls * >> Makefile
[root@VM-8-2-centos my_stdio]# ll
total 20
-rw-r--r-- 1 root root   61 Aug 15 00:08 Makefile
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
[root@VM-8-2-centos my_stdio]# vim Makefile
[root@VM-8-2-centos my_stdio]# cat Makefile
libmyc.a:mystdio.o mystring.oar -rc $@ $^
mystdio.o:mystdio.cgcc -c $<
mystring.o:mystring.cgcc -c $<.PHONY:clean
clean:rm -rf *.o libmyc.a
[root@VM-8-2-centos my_stdio]# make
gcc -c mystdio.c
gcc -c mystring.c
ar -rc libmyc.a mystdio.o mystring.o
[root@VM-8-2-centos my_stdio]# ll
total 36
-rw-r--r-- 1 root root 4634 Aug 15 00:14 libmyc.a
-rw-r--r-- 1 root root  150 Aug 15 00:13 Makefile
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3104 Aug 15 00:14 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 15 00:14 mystring.o
[root@VM-8-2-centos my_stdio]# make clean
rm -rf *.o libmyc.a
[root@VM-8-2-centos my_stdio]# ll
total 20
-rw-r--r-- 1 root root  150 Aug 15 00:13 Makefile
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h

而我们作为一个库的设计者,我们想的是要让别人能够最终把我们对应的库拿过去直接用,所以我们需要一个发布的过程。

[root@VM-8-2-centos my_stdio]#  ll
total 20
-rw-r--r-- 1 root root  150 Aug 15 00:13 Makefile
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
[root@VM-8-2-centos my_stdio]# vim Makefile
[root@VM-8-2-centos my_stdio]# cat Makefile
libmyc.a:mystdio.o mystring.oar -rc $@ $^
mystdio.o:mystdio.cgcc -c $<
mystring.o:mystring.cgcc -c $<.PHONY:output
output:mkdir -p lib/includemkdir -p lib/mylibcp -f *.h lib/includecp -f *.a lib/mylibtar czf lib.tgz lib.PHONY:clean
clean:rm -rf *.o libmyc.a lib lib.tgz
[root@VM-8-2-centos my_stdio]# make
gcc -c mystdio.c
gcc -c mystring.c
ar -rc libmyc.a mystdio.o mystring.o
[root@VM-8-2-centos my_stdio]# ll
total 36
-rw-r--r-- 1 root root 4634 Aug 15 00:25 libmyc.a
-rw-r--r-- 1 root root  292 Aug 15 00:24 Makefile
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3104 Aug 15 00:25 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 15 00:25 mystring.o
[root@VM-8-2-centos my_stdio]# make output
mkdir -p lib/include
mkdir -p lib/mylib
cp -f *.h lib/include
cp -f *.a lib/mylib
tar czf lib.tgz lib
[root@VM-8-2-centos my_stdio]# ll
total 44
drwxr-xr-x 4 root root 4096 Aug 15 00:26 lib
-rw-r--r-- 1 root root 4634 Aug 15 00:25 libmyc.a
-rw-r--r-- 1 root root 1792 Aug 15 00:26 lib.tgz
-rw-r--r-- 1 root root  292 Aug 15 00:24 Makefile
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3104 Aug 15 00:25 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 15 00:25 mystring.o
[root@VM-8-2-centos zhangsan]# cp ../my_stdio/lib.tgz .
[root@VM-8-2-centos zhangsan]# ll
total 12
-rw-r--r-- 1 root root 1792 Aug 15 00:29 lib.tgz
-rw-r--r-- 1 root root   64 Aug 14 21:54 log.txt
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# tar xzf lib.tgz
[root@VM-8-2-centos zhangsan]# ll
total 16
drwxr-xr-x 4 root root 4096 Aug 15 00:26 lib
-rw-r--r-- 1 root root 1792 Aug 15 00:29 lib.tgz
-rw-r--r-- 1 root root   64 Aug 14 21:54 log.txt
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# gcc usercode.c -I ./lib/include/ -L ./lib/mylib/ -l myc
[root@VM-8-2-centos zhangsan]# ll
total 32
-rwxr-xr-x 1 root root 13336 Aug 15 00:32 a.out
drwxr-xr-x 4 root root  4096 Aug 15 00:26 lib
-rw-r--r-- 1 root root  1792 Aug 15 00:29 lib.tgz
-rw-r--r-- 1 root root    64 Aug 14 21:54 log.txt
-rw-r--r-- 1 root root   529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# ./a.out
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
^C

3.动态库的制作

接下来我们来讨论动态库。动态库的原理几乎和静态库一模一样。只不过,相比于静态库,把我们的源代码打包成动态库,是更为常见和常规的操作。

动态库(.so 文件)的核心特性和工作机制:

  1. 动态库的链接时机:运行时链接

动态库与程序的链接过程并非在编译阶段完成,而是程序运行时才会去链接动态库中的代码
这与静态库(编译时将代码拷贝到程序中)有本质区别 —— 动态库的代码不会提前 “嵌入” 到可执行文件里,而是在程序启动或执行过程中按需加载。

  1. 可执行文件与动态库的关系:仅包含入口地址表

一个与动态库链接的可执行文件,并不会包含动态库中外部函数的完整机器码,而只记录了它所用到的函数的入口地址表(类似 “索引”)。
举个例子:如果程序调用了动态库中的add()函数,可执行文件里不会有add()的具体实现代码,只会保存 “去哪里找add()函数” 的地址信息。

  1. 动态链接的过程:运行前加载代码

在可执行文件开始运行前,操作系统会负责将动态库中程序所需的外部函数的机器码,从磁盘上的动态库文件(.so)复制到内存中,并通过可执行文件中的 “入口地址表” 建立关联,这个过程称为动态链接
简单说,就是程序运行前,操作系统 “帮它找到并加载” 需要的动态库代码。

  1. 动态库的优势:节省空间(磁盘 + 内存)
  • 节省磁盘空间:多个程序可以共享同一个动态库文件,无需像静态库那样每个程序都拷贝一份库代码,因此可执行文件体积更小,整体占用的磁盘空间更少。
  • 节省内存空间:操作系统通过虚拟内存机制,让物理内存中仅存一份动态库代码,供所有需要它的进程共享使用(而非每个进程都加载一份副本),极大减少了内存消耗。

总结:

动态库的核心特点是 “运行时链接、共享代码”,通过延迟链接时机和共享机制,既减小了可执行文件的体积,又节省了磁盘和内存资源,是操作系统中实现代码复用和资源优化的重要方式。

[root@VM-8-2-centos my_stdio]# ll
total 20
-rw-r--r-- 1 root root  292 Aug 15 00:24 Makefile
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
[root@VM-8-2-centos my_stdio]# gcc -fPIC -c *.c	//fPIC:产生位置无关码,它的作用是让编译器生成的机器码不依赖于具体的内存地址,能够在内存的任何位置被加载和执行。
[root@VM-8-2-centos my_stdio]# ll
total 28
-rw-r--r-- 1 root root  292 Aug 15 00:24 Makefile
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3160 Aug 15 01:04 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 15 01:04 mystring.o
[root@VM-8-2-centos my_stdio]# gcc -shared -o libmyc.so *.o	
//动态库中,gcc既可以形成可执行程序,又可以形成动态库文件
[root@VM-8-2-centos my_stdio]# ll
total 40
-rwxr-xr-x 1 root root 8656 Aug 15 01:05 libmyc.so
-rw-r--r-- 1 root root  292 Aug 15 00:24 Makefile
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3160 Aug 15 01:04 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 15 01:04 mystring.o
[root@VM-8-2-centos my_stdio]# file libmyc.so
//查看该文件的详细类型
libmyc.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=9c209c1e99017aee6cb83288ed31164ff91c2eca, not stripped
[root@VM-8-2-centos my_stdio]# make	//同样我们再次形成静态库
ar -rc libmyc.a mystdio.o mystring.o
[root@VM-8-2-centos my_stdio]# ll
total 48
-rw-r--r-- 1 root root 4690 Aug 15 01:06 libmyc.a
-rwxr-xr-x 1 root root 8656 Aug 15 01:05 libmyc.so
-rw-r--r-- 1 root root  292 Aug 15 00:24 Makefile
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3160 Aug 15 01:04 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 15 01:04 mystring.o
[root@VM-8-2-centos my_stdio]# file libmyc.a	
//查看静态库的类型
libmyc.a: current ar archive	//归档文件即静态库
[root@VM-8-2-centos my_stdio]# make clean
rm -rf *.o libmyc.a lib lib.tgz
[root@VM-8-2-centos my_stdio]# ll
total 32
-rwxr-xr-x 1 root root 8656 Aug 15 01:05 libmyc.so
-rw-r--r-- 1 root root  292 Aug 15 00:24 Makefile
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
  • shared:在编译链接时指定该选项,用于生成共享库(如 Linux 下的.so文件),这种库可被多个程序动态链接共享,减小可执行文件体积并节省内存。
  • fPIC:即 “生成位置无关代码”,指编译出的机器码不依赖于特定内存位置,能被加载到内存任意地址执行,确保共享库在被多个进程共享时,可在各自地址空间正确运行,是生成共享库的必要条件。
[root@VM-8-2-centos my_stdio]# ll
total 36
-rwxr-xr-x 1 root root 8656 Aug 15 01:13 libmyc.so
-rw-r--r-- 1 root root  315 Aug 15 01:12 Makefile
-rw-r--r-- 1 root root  292 Aug 15 01:08 Makefile-bak
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
[root@VM-8-2-centos my_stdio]# vim Makefile
[root@VM-8-2-centos my_stdio]# cat Makefile
libmyc.so:mystdio.o mystring.ogcc -shared -o $@ $^
mystdio.o:mystdio.cgcc -fPIC -c $<
mystring.o:mystring.cgcc -fPIC -c $<.PHONY:output
output:mkdir -p lib/includemkdir -p lib/mylibcp -f *.h lib/includecp -f *.so lib/mylibtar czf lib.tgz lib.PHONY:clean
clean:rm -rf *.o libmyc.so lib lib.tgz
[root@VM-8-2-centos my_stdio]# make clean
rm -rf *.o libmyc.so lib lib.tgz
[root@VM-8-2-centos my_stdio]# ll
total 24
-rw-r--r-- 1 root root  315 Aug 15 01:12 Makefile
-rw-r--r-- 1 root root  292 Aug 15 01:08 Makefile-bak
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
[root@VM-8-2-centos my_stdio]# make
gcc -fPIC -c mystdio.c
gcc -fPIC -c mystring.c
gcc -shared -o libmyc.so mystdio.o mystring.o
[root@VM-8-2-centos my_stdio]# make output
mkdir -p lib/include
mkdir -p lib/mylib
cp -f *.h lib/include
cp -f *.so lib/mylib
tar czf lib.tgz lib
[root@VM-8-2-centos my_stdio]# ll
total 52
drwxr-xr-x 4 root root 4096 Aug 15 10:36 lib
-rwxr-xr-x 1 root root 8656 Aug 15 10:36 libmyc.so
-rw-r--r-- 1 root root 3458 Aug 15 10:36 lib.tgz
-rw-r--r-- 1 root root  315 Aug 15 01:12 Makefile
-rw-r--r-- 1 root root  292 Aug 15 01:08 Makefile-bak
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3160 Aug 15 10:36 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 15 10:36 mystring.o
[root@VM-8-2-centos my_stdio]# tree lib
lib
|-- include
|   |-- mystdio.h
|   `-- mystring.h
`-- mylib`-- libmyc.so2 directories, 3 files
[root@VM-8-2-centos zhangsan]# ll
total 4
-rw-r--r-- 1 root root 529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# cp ../my_stdio/lib.tgz .
[root@VM-8-2-centos zhangsan]# ll
total 8
-rw-r--r-- 1 root root 3458 Aug 15 11:20 lib.tgz
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# tar xzf lib.tgz
[root@VM-8-2-centos zhangsan]# ll
total 12
drwxr-xr-x 4 root root 4096 Aug 15 10:36 lib
-rw-r--r-- 1 root root 3458 Aug 15 11:20 lib.tgz
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# tree lib
lib
|-- include
|   |-- mystdio.h
|   `-- mystring.h
`-- mylib`-- libmyc.so2 directories, 3 files
[root@VM-8-2-centos zhangsan]# vim usercode.c
[root@VM-8-2-centos zhangsan]# gcc -o usercode usercode.c 	//编译
usercode.c:1:21: fatal error: mystdio.h: No such file or directory#include "mystdio.h" ^
compilation terminated.
//找不到头文件,报错
[root@VM-8-2-centos zhangsan]# gcc -o usercode usercode.c -I lib/include/ //	指明头文件搜索路径
/tmp/ccbkMLiy.o: In function `main':
usercode.c:(.text+0x13): undefined reference to `MyFopen'
usercode.c:(.text+0x64): undefined reference to `MyFwrite'
usercode.c:(.text+0x70): undefined reference to `MyFFlush'
usercode.c:(.text+0xad): undefined reference to `MyFclose'
usercode.c:(.text+0xc1): undefined reference to `my_strlen'
collect2: error: ld returned 1 exit status
//链接式报错,未指明库名
[root@VM-8-2-centos zhangsan]# gcc -o usercode usercode.c -I lib/include/ -l myc
/usr/bin/ld: cannot find -lmyc
collect2: error: ld returned 1 exit status	//记得指定库路径
[root@VM-8-2-centos zhangsan]# gcc -o usercode usercode.c -I lib/include/ -L lib/mylib/ -l myc
[root@VM-8-2-centos zhangsan]# ll
total 24
drwxr-xr-x 4 root root 4096 Aug 15 10:36 lib
-rw-r--r-- 1 root root 3458 Aug 15 11:20 lib.tgz
-rwxr-xr-x 1 root root 8720 Aug 15 11:24 usercode
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# ./usercode
./usercode: error while loading shared libraries: libmyc.so: cannot open shared object file: No such file or directory
[root@VM-8-2-centos zhangsan]# 
//报错了!??

我不是已经告诉系统去那个路径找吗?why is not found?

[root@VM-8-2-centos zhangsan]# ldd usercodelinux-vdso.so.1 =>  (0x00007ffca23be000)libmyc.so => not foundlibc.so.6 => /lib64/libc.so.6 (0x00007f10317b3000)/lib64/ld-linux-x86-64.so.2 (0x00007f1031b81000)

哦哦!!原来我只告诉了gcc !!

而系统!=gcc

那静态库怎么没有这个问题??

原来静态库在链接时是直接把库的实现拷贝到可执行程序里,一旦形成可执行程序,可执行程序不再依赖静态库。静态库不存在运行找不到的问题,只要编译成功,就一定能运行。

关于动态库的制作上,它与静态库的制作只有操作上的差别,没有本质差别。回归正题,那要怎么办?我们可以把动态库拷贝到系统中!

1.拷贝.so 文件到系统共享库路径下

[root@VM-8-2-centos zhangsan]# tree lib
lib
|-- include
|   |-- mystdio.h
|   `-- mystring.h
`-- mylib`-- libmyc.so2 directories, 3 files
[root@VM-8-2-centos zhangsan]# ls /usr/local/
bin  games    lib    libexec  sbin   src
etc  include  lib64  qcloud   share
[root@VM-8-2-centos zhangsan]# ls /usr/local/lib64/^C
[root@VM-8-2-centos zhangsan]# ll
total 24
drwxr-xr-x 4 root root 4096 Aug 15 10:36 lib
-rw-r--r-- 1 root root 3458 Aug 15 11:20 lib.tgz
-rwxr-xr-x 1 root root 8720 Aug 15 11:24 usercode
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# sudo cp lib/mylib/libmyc.so /lib64
[root@VM-8-2-centos zhangsan]# ls /lib64/libmyc.so
/lib64/libmyc.so
[root@VM-8-2-centos zhangsan]# ./usercode
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
^C
[root@VM-8-2-centos zhangsan]# ldd usercodelinux-vdso.so.1 =>  (0x00007ffd997d1000)libmyc.so => /lib64/libmyc.so (0x00007f5be0d77000)libc.so.6 => /lib64/libc.so.6 (0x00007f5be09a9000)/lib64/ld-linux-x86-64.so.2 (0x00007f5be0f79000)

那还有其他的办法吗?有,向系统共享库路径下建立同名软连接。

2.软链接

[root@VM-8-2-centos zhangsan]# pwd
/root/File1/lesson13/zhangsan[root@VM-8-2-centos zhangsan]# sudo ln -fs /root/File1/lesson13/zhangsan/lib/mylib/libmyc.so /lib64/libmyc.so
[root@VM-8-2-centos zhangsan]# ll /lib64/libmyc.so
lrwxrwxrwx 1 root root 49 Aug 15 11:51 /lib64/libmyc.so -> /root/File1/lesson13/zhangsan/lib/mylib/libmyc.so
[root@VM-8-2-centos zhangsan]# ll
total 28
drwxr-xr-x 4 root root 4096 Aug 15 10:36 lib
-rw-r--r-- 1 root root 3458 Aug 15 11:20 lib.tgz
-rw-r--r-- 1 root root   48 Aug 15 11:40 log.txt
-rwxr-xr-x 1 root root 8720 Aug 15 11:24 usercode
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# ./usercode
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
^C
[root@VM-8-2-centos zhangsan]# ldd usercodelinux-vdso.so.1 =>  (0x00007ffdd4be3000)libmyc.so => /lib64/libmyc.so (0x00007f89a2258000)libc.so.6 => /lib64/libc.so.6 (0x00007f89a1e8a000)/lib64/ld-linux-x86-64.so.2 (0x00007f89a245a000)[root@VM-8-2-centos zhangsan]# sudo unlink /lib64/libmyc.so		//删掉软链接
[root@VM-8-2-centos zhangsan]# ll
total 28
drwxr-xr-x 4 root root 4096 Aug 15 10:36 lib
-rw-r--r-- 1 root root 3458 Aug 15 11:20 lib.tgz
-rw-r--r-- 1 root root  112 Aug 15 14:35 log.txt
-rwxr-xr-x 1 root root 8720 Aug 15 11:24 usercode
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# ldd usercodelinux-vdso.so.1 =>  (0x00007ffc65bc8000)libmyc.so => not found	//发现又找不到了libc.so.6 => /lib64/libc.so.6 (0x00007fb718887000)/lib64/ld-linux-x86-64.so.2 (0x00007fb718c55000)

我们还有第三种做法——更改环境变量: LD_LIBRARY_PATH。

3.更改环境变量

[root@VM-8-2-centos zhangsan]# echo $LD_LIBRARY_PATH
:/root/.VimForCpp/vim/bundle/YCM.so/el7.x86_64

os运行程序,要查找动态库,也会在该环境变量下查找动态库(LD_LIBRARY_PATH,经常都是空的)

[root@VM-8-2-centos zhangsan]# ldd usercodelinux-vdso.so.1 =>  (0x00007ffff735d000)libmyc.so => not foundlibc.so.6 => /lib64/libc.so.6 (0x00007fc8b519c000)/lib64/ld-linux-x86-64.so.2 (0x00007fc8b556a000)
[root@VM-8-2-centos zhangsan]# echo $LD_LIBRARY_PATH
:/root/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
[root@VM-8-2-centos zhangsan]# pwd
/root/File1/lesson13/zhangsan
[root@VM-8-2-centos zhangsan]# export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/root/File1/lesson13/zhangsan/lib/mylib
[root@VM-8-2-centos zhangsan]# echo ${LD_LIBRARY_PATH}
:/root/.VimForCpp/vim/bundle/YCM.so/el7.x86_64:/root/File1/lesson13/zhangsan/lib/mylib
[root@VM-8-2-centos zhangsan]# ldd usercodelinux-vdso.so.1 =>  (0x00007ffc6eddd000)libmyc.so => /root/File1/lesson13/zhangsan/lib/mylib/libmyc.so (0x00007fcc72bfd000)libc.so.6 => /lib64/libc.so.6 (0x00007fcc7282f000)/lib64/ld-linux-x86-64.so.2 (0x00007fcc72dff000)
[root@VM-8-2-centos zhangsan]# ./usercode
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
^C

export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/root/File1/lesson13/zhangsan/lib/mylib含义:

  1. LD_LIBRARY_PATH
    这是 Linux 系统中专门用于指定动态库(.so 文件)搜索路径的环境变量。当程序运行时,操作系统会在这个变量指定的路径中查找所需的动态库。
  2. ${LD_LIBRARY_PATH}
    表示 “获取当前 LD_LIBRARY_PATH 环境变量的值”(保留已有路径,避免覆盖)。
  3. :/root/File1/lesson13/zhangsan/lib/mylib
    表示 “在已有路径后追加新的路径”,其中:
    • : 是路径分隔符,用于分隔多个路径;
    • /root/File1/lesson13/zhangsan/lib/mylib 是新增的动态库搜索路径,即告诉系统:“在这个目录下也可以找动态库”。
  4. export
    用于将设置好的变量导出为环境变量,使其在当前 shell 及子进程中生效。

要是我们把Xshell重启,打开之后又会找不到了。

[root@VM-8-2-centos zhangsan]# ll
total 28
drwxr-xr-x 4 root root 4096 Aug 15 10:36 lib
-rw-r--r-- 1 root root 3458 Aug 15 11:20 lib.tgz
-rw-r--r-- 1 root root  160 Aug 15 14:50 log.txt
-rwxr-xr-x 1 root root 8720 Aug 15 11:24 usercode
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# ./usercode
./usercode: error while loading shared libraries: libmyc.so: cannot open shared object file: No such file or directory
[root@VM-8-2-centos zhangsan]# ldd usercodelinux-vdso.so.1 =>  (0x00007fffa4bed000)libmyc.so => not foundlibc.so.6 => /lib64/libc.so.6 (0x00007f228c9aa000)/lib64/ld-linux-x86-64.so.2 (0x00007f228cd78000)

原因是我们导的LD_LIBRARY_PATH这个环境变量是内存级的,所以你把它导入成功之后,终端一关它就没了。如果要这个环境变量一直有效,就要把它写到配置文件里。

我们的第四种做法——配置/ etc/ld.so.conf.d/ ,ldconfig更新。这种方案是永久生效的,且属于系统级配置。

4.ldconfig方案

  1. 配置文件路径:/etc/ld.so.conf.d/

系统会自动自动扫描 /etc/ld.so.conf.d/ 目录下的所有 .conf 后缀文件,这些文件中存放着动态库的搜索路径。
用户只需在此目录下创建一个自定义配置文件(例如 mylib.conf),并在文件中写入动态库所在的目录路径(如 /root/File1/lesson13/zhangsan/lib/mylib),即可将该路径添加为系统级的动态库搜索路径。

  1. ldconfig 命令的作用

修改配置文件后,需要执行 sudo ldconfig 命令:

  • 它会重新扫描所有配置文件中指定的路径,更新系统的动态库缓存(存储在 /etc/ld.so.cache 中);
  • 让新添加的动态库路径生效,程序运行时就能自动找到这些路径下的 .so 文件。
[root@VM-8-2-centos zhangsan]# ls /etc/ld.so.conf
/etc/ld.so.conf
[root@VM-8-2-centos zhangsan]# pwd
/root/File1/lesson13/zhangsan
[root@VM-8-2-centos zhangsan]# ls /etc/ld.so.conf.d/
1111111.cnf              kernel-3.10.0-1160.119.1.el7.x86_64.conf
bind-export-x86_64.conf  mysql-x86_64.conf
dyninst-x86_64.conf
[root@VM-8-2-centos zhangsan]# pwd
/root/File1/lesson13/zhangsan
[root@VM-8-2-centos zhangsan]# ls /root/File1/lesson13/zhangsan/lib/mylib/
libmyc.so
[root@VM-8-2-centos zhangsan]# ldd usercodelinux-vdso.so.1 =>  (0x00007ffe70bfd000)libmyc.so => not foundlibc.so.6 => /lib64/libc.so.6 (0x00007fdfd6382000)/lib64/ld-linux-x86-64.so.2 (0x00007fdfd6750000)
[root@VM-8-2-centos zhangsan]# sudo touch /etc/ld.so.conf.d/111_222.conf
[root@VM-8-2-centos zhangsan]# ls /etc/ld.so.conf.d/ -l
total 20
-rw-r--r-- 1 root root 634 Jul 25 04:50 1111111.cnf
-rw-r--r-- 1 root root   0 Aug 15 15:22 111_222.conf
-rw-r--r-- 1 root root  26 Jun 11  2024 bind-export-x86_64.conf
-rw-r--r-- 1 root root  19 Aug  9  2019 dyninst-x86_64.conf
-r--r--r-- 1 root root  63 Jun  4  2024 kernel-3.10.0-1160.119.1.el7.x86_64.conf
-rw-r--r-- 1 root root  17 Oct 11  2023 mysql-x86_64.conf
[root@VM-8-2-centos zhangsan]# ll
total 28
drwxr-xr-x 4 root root 4096 Aug 15 10:36 lib
-rw-r--r-- 1 root root 3458 Aug 15 11:20 lib.tgz
-rw-r--r-- 1 root root  160 Aug 15 14:50 log.txt
-rwxr-xr-x 1 root root 8720 Aug 15 11:24 usercode
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# ldd usercodelinux-vdso.so.1 =>  (0x00007ffe6c5cc000)libmyc.so => not foundlibc.so.6 => /lib64/libc.so.6 (0x00007f01d300d000)/lib64/ld-linux-x86-64.so.2 (0x00007f01d33db000)
[root@VM-8-2-centos zhangsan]# sudo vim /etc/ld.so.conf.d/111_222.conf 
YouCompleteMe unavailable: requires Vim 7.4.1578+.
Press ENTER or type command to continue
[root@VM-8-2-centos zhangsan]# cat /etc/ld.so.conf.d/111_222.conf
/root/File1/lesson13/zhangsan/lib/mylib/
[root@VM-8-2-centos zhangsan]# ldd usercodelinux-vdso.so.1 =>  (0x00007ffe5cdbc000)libmyc.so => not foundlibc.so.6 => /lib64/libc.so.6 (0x00007f653a328000)/lib64/ld-linux-x86-64.so.2 (0x00007f653a6f6000)
[root@VM-8-2-centos zhangsan]# ls /etc/ld.so.conf.d/
1111111.cnf              dyninst-x86_64.conf
111_222.conf             kernel-3.10.0-1160.119.1.el7.x86_64.conf
bind-export-x86_64.conf  mysql-x86_64.conf
[root@VM-8-2-centos zhangsan]# sudo ldconfig //更新
[root@VM-8-2-centos zhangsan]# ldd usercodelinux-vdso.so.1 =>  (0x00007fffe2283000)libmyc.so => /root/File1/lesson13/zhangsan/lib/mylib/libmyc.so (0x00007ff659b53000)libc.so.6 => /lib64/libc.so.6 (0x00007ff659785000)/lib64/ld-linux-x86-64.so.2 (0x00007ff659d55000)
[root@VM-8-2-centos zhangsan]# ./usercode
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
^C

综上,一个四种解决方案

1.拷贝.so 文件到系统共享库路径下,⼀般指 /usr/lib、/usr/local/lib、/lib64 或者开 篇指明的库路径等

2.向系统共享库路径下建立同名软连接

3.更改环境变量: LD_LIBRARY_PATH

4.ldconfig方案:配置/ etc/ld.so.conf.d/ ,ldconfig更新

学到这里,我们或多或少会产生一些问题?比如,动静态库能否同时存在呢?

[root@VM-8-2-centos my_stdio]# ll
total 24
-rw-r--r-- 1 root root  315 Aug 15 01:12 Makefile
-rw-r--r-- 1 root root  292 Aug 15 01:08 Makefile-bak
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
[root@VM-8-2-centos my_stdio]# mv Makefile Makefile-DY
[root@VM-8-2-centos my_stdio]# ll
total 24
-rw-r--r-- 1 root root  292 Aug 15 01:08 Makefile-bak
-rw-r--r-- 1 root root  315 Aug 15 01:12 Makefile-DY
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
[root@VM-8-2-centos my_stdio]# mv Makefile-bak Makefile
[root@VM-8-2-centos my_stdio]# ll
total 24
-rw-r--r-- 1 root root  292 Aug 15 01:08 Makefile
-rw-r--r-- 1 root root  315 Aug 15 01:12 Makefile-DY
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
[root@VM-8-2-centos my_stdio]# make
gcc -c mystdio.c
gcc -c mystring.c
ar -rc libmyc.a mystdio.o mystring.o
[root@VM-8-2-centos my_stdio]# ll
total 40
-rw-r--r-- 1 root root 4634 Aug 15 15:41 libmyc.a
-rw-r--r-- 1 root root  292 Aug 15 01:08 Makefile
-rw-r--r-- 1 root root  315 Aug 15 01:12 Makefile-DY
-rw-r--r-- 1 root root 1700 Aug 13 21:39 mystdio.c
-rw-r--r-- 1 root root  392 Aug 13 21:39 mystdio.h
-rw-r--r-- 1 root root 3104 Aug 15 15:41 mystdio.o
-rw-r--r-- 1 root root  126 Aug 13 21:53 mystring.c
-rw-r--r-- 1 root root   43 Aug 14 11:35 mystring.h
-rw-r--r-- 1 root root 1272 Aug 15 15:41 mystring.o
[root@VM-8-2-centos my_stdio]# cp libmyc.a ../zhangsan/lib/mylib/
[root@VM-8-2-centos my_stdio]# cd ../zhangsan/
[root@VM-8-2-centos zhangsan]# ll
total 20
drwxr-xr-x 4 root root 4096 Aug 15 10:36 lib
-rw-r--r-- 1 root root 4634 Aug 15 15:43 libmyc.a
-rw-r--r-- 1 root root  208 Aug 15 15:31 log.txt
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# tree .
.
|-- lib
|   |-- include
|   |   |-- mystdio.h
|   |   `-- mystring.h
|   `-- mylib
|       |-- libmyc.a
|       `-- libmyc.so
|-- libmyc.a
|-- log.txt
`-- usercode.c3 directories, 7 files
[root@VM-8-2-centos zhangsan]# gcc -o code usercode.c -I lib/include/ -L lib/mylib/ -lmyc
[root@VM-8-2-centos zhangsan]# ll
total 32
-rwxr-xr-x 1 root root 8720 Aug 15 15:47 code
drwxr-xr-x 4 root root 4096 Aug 15 10:36 lib
-rw-r--r-- 1 root root 4634 Aug 15 15:43 libmyc.a
-rw-r--r-- 1 root root  208 Aug 15 15:31 log.txt
-rw-r--r-- 1 root root  529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# ./code
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
^C
[root@VM-8-2-centos zhangsan]# ldd codelinux-vdso.so.1 =>  (0x00007fff82944000)libmyc.so => /root/File1/lesson13/zhangsan/lib/mylib/libmyc.so (0x00007fed12017000)libc.so.6 => /lib64/libc.so.6 (0x00007fed11c49000)/lib64/ld-linux-x86-64.so.2 (0x00007fed12219000)
[root@VM-8-2-centos zhangsan]# file code
code: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=54df67036b86d510e946a95885c19bef736cc410, not stripped

结论一:根据上面的实践,我们知道,动静态库可以同时存在,但运行时gcc/g++默认使用动态库!

如果非要使用静态库,我们只能-static。

[root@VM-8-2-centos zhangsan]# gcc -o code usercode.c -I lib/include/ -L lib/mylib/ -l myc -static
[root@VM-8-2-centos zhangsan]# ll
total 868
-rwxr-xr-x 1 root root 866048 Aug 15 17:04 code
drwxr-xr-x 4 root root   4096 Aug 15 10:36 lib
-rw-r--r-- 1 root root   4634 Aug 15 15:43 libmyc.a
-rw-r--r-- 1 root root    256 Aug 15 15:48 log.txt
-rw-r--r-- 1 root root    529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# ./code
buffer:hello myfile!!!!
buffer:hello myfile!!!!
buffer:hello myfile!!!!
^C
[root@VM-8-2-centos zhangsan]# ldd codenot a dynamic executable

如果没有静态库,我们-static会怎么样?实验一下。

[root@VM-8-2-centos zhangsan]# tree .
.
|-- code
|-- lib
|   |-- include
|   |   |-- mystdio.h
|   |   `-- mystring.h
|   `-- mylib
|       `-- libmyc.so
|-- log.txt
`-- usercode.c3 directories, 6 files
[root@VM-8-2-centos zhangsan]# gcc -o code usercode.c -I lib/include/ -L lib/mylib/ -l myc -static
/usr/bin/ld: cannot find -lmyc
collect2: error: ld returned 1 exit status

我们发现报错了,说明你想静态链接就必须提供静态库才能用-static。一旦-static,就必须存在对应的静态库。

当只有静态库时带-static没问题我们知道会正常运行,那没-static呢?也可以!

[root@VM-8-2-centos zhangsan]# tree lib/
lib/
|-- include
|   |-- mystdio.h
|   `-- mystring.h
`-- mylib|-- libmyc.a`-- libmyc.so2 directories, 4 files
[root@VM-8-2-centos zhangsan]# rm lib/mylib/*.so
rm: remove regular file ‘lib/mylib/libmyc.so’? y
[root@VM-8-2-centos zhangsan]# gcc -o code usercode.c -I lib/include/ -L lib/mylib/ -l myc -static
[root@VM-8-2-centos zhangsan]# ll
total 860
-rwxr-xr-x 1 root root 866048 Aug 15 17:16 code
drwxr-xr-x 4 root root   4096 Aug 15 10:36 lib
-rw-r--r-- 1 root root    304 Aug 15 17:04 log.txt
-rw-r--r-- 1 root root    529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# ./code
buffer:hello myfile!!!!
buffer:hello myfile!!!!
^C
[root@VM-8-2-centos zhangsan]# gcc -o code usercode.c -I lib/include/ -L lib/mylib/ -l myc
[root@VM-8-2-centos zhangsan]# ll
total 28
-rwxr-xr-x 1 root root 13336 Aug 15 17:17 code
drwxr-xr-x 4 root root  4096 Aug 15 10:36 lib
-rw-r--r-- 1 root root   336 Aug 15 17:16 log.txt
-rw-r--r-- 1 root root   529 Aug 14 10:59 usercode.c
[root@VM-8-2-centos zhangsan]# ./code
buffer:hello myfile!!!!
buffer:hello myfile!!!!
^C
[root@VM-8-2-centos zhangsan]# ldd codelinux-vdso.so.1 =>  (0x00007fff449b2000)libc.so.6 => /lib64/libc.so.6 (0x00007f882165c000)/lib64/ld-linux-x86-64.so.2 (0x00007f8821a2a000)

只存在静态库,可执行程序,对于该库,只能静态链接了!

结论二:在linux系统下,默认情况安装的大部分库,默认都优先安装的是动态库!

结论三:库:应用程序=1:n。

结论四:vs不仅仅形成可执行程序,也能形成动静态库

http://www.lryc.cn/news/622757.html

相关文章:

  • Navicat 为 SQLite 数据库设置密码指南
  • 如何使用 Git 修改已推送 Commit 的用户名和邮箱
  • 从废弃到珍宝——旧物二手回收小程序系统的价值发现之旅
  • 配置 Docker 镜像加速,解决 docker pull 拉取镜像失败、docker search 查询镜像失败等问题
  • 外出业务员手机自动添加报价单​——仙盟创梦IDE
  • PostgreSQL——事务处理与并发控制
  • 关于casdoor重定向问题
  • 力扣(最小覆盖子串)
  • Java设计模式之《工厂模式》
  • 【Java web】HTTP 协议详解
  • PO BO VO DTO POJO DAO DO概念
  • Linux第十四讲:网络基础概念
  • Jenkins Pipeline中参数化构建
  • Android 移动端 UI 设计:前端常用设计原则总结
  • 后台管理系统-3-vue3之左侧菜单栏和头部导航栏的静态搭建
  • flowable汇总查询方式
  • SAP-FI配置与业务解析之内部交易核算
  • 双向SSL认证之Apache实战配置
  • 3 种方式玩转网络继电器!W55MH32 实现网页 + 阿里云 + 本地控制互通
  • 数据清洗与机器学习贷款偿还预测建模
  • (职业分析)讨好型人格适合什么职业?
  • 【LLM微调】
  • 每日算法刷题Day62:8.16:leetcode 堆8道题,用时2h30min
  • java项目中什么时候使用static、final
  • Docker数据卷挂载和本地目录挂载
  • 暴雨服务器:以定制化满足算力需求多样化
  • dify 调用本地的 stable diffusion api生成图片的工作流搭建
  • 掌握长尾关键词优化SEO技巧
  • 神经网络 常见分类
  • 分布式存储与存储阵列:从传统到现代的存储革命