Linux:库制作与原理(二)

hello,再次见面,结果上一次我们的努力,张三与学校的其他校友成功完成了老师的作业,但是此时我们也想到了另一种技术--制作动态库!!

1.动态库的定义

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

2.制作一个动态库

我们借用一下前面的静态库代码

lib

Makefile
bash 复制代码
libmyc.so : mystdio.o mystring.o
	gcc -shared -o $@ $^
mystdio.o : mystdio.c
	gcc -fPIC -c $^
mystring.o : mystring.c
	gcc -fPIC -c $^
.PHONY : clean
clean :
	rm -rf *.o *.so *.tgz lib
.PHONY : output
output : 
	mkdir ./lib 
	mkdir ./lib/include
	mkdir ./lib/mylib 
	cp *.h ./lib/include 
	cp *.so ./lib/mylib
	tar czf lib.tgz lib
mystdio.h
cpp 复制代码
#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* );
mystdio.c
cpp 复制代码
#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, "r") == 0)
    {
        flag = O_RDONLY;
        fd = open(path, flag);
    }
    else if (strcmp(mode, "a") == 0)
    {
        flag = O_CREAT | O_WRONLY | O_APPEND;
        fd = open(path, flag, 0666);
    }
    else 
    {
        //TODO
    }
    if (fd < 0)
    {
        return NULL;
    }
    return BuyFile(fd, flag);
}

void MyFclose(MyFile* file)
{
    MyFFlush(file);
}

int MyFwrite(MyFile* file, void* str, int len)
{
    //拷贝
    memcpy(file->outbuffer + file->bufferlen, str, len);
    file->bufferlen += len;
    //行刷新
    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;
    file->bufferlen = 0;
}
mystring.h
cpp 复制代码
#pragma once 

int mystrlen(const char* str);
mystring.c
cpp 复制代码
#include "mystring.h"

int mystrlen(const char* str)
{
    const char* start = str;
    while (*str)
    {
        str++;
    }
    return str - start;
}

zhangsan

code.c
cpp 复制代码
#include "mystdio.h"
#include "mystring.h"
#include <string.h>
#include <unistd.h>
int main()
{
    MyFile* filep = MyFopen("./log.txt", "a");
    if (!filep)
    {
        perror("filep open\n");
        return 1;
    }
    //char* message = (char*)"hello my_libc\n"; //带/n行刷新
    char* message = (char*)"hello my_libc!!!"; //不带就是全刷新
    //MyFwrite(filep, message, strlen(message));
    int cnt = 10;
    while (cnt--)
    {
        MyFwrite(filep, message, strlen(message));
        printf("filep->outbuffer : %s\n", filep->outbuffer);
        sleep(1);
    }
    MyFclose(filep);
    const char* str = "hello world!\n";
    printf("strlen : %d\n", mystrlen(str));
    return 0;
}

代码分析

和静态库类似,我们只需要.o文件即可(这里的.o不是一般的.o),但是静态库打包需要用到ar -rc指令,而动态库打包只需要gcc即可

具体指令

gcc -shared -o libmyc.so *.o

但是需要注意的是,这里的.o文件是需要加上fPIC进行编译的

gcc -fPIC -c *.c

命令行参数含义

shared: 表示⽣成共享库格式
fPIC:产⽣位置⽆关码(position independent code)(现在不讲,之后博客再将这个概念)
库名规则:libxxx.so

3.zhangsan运行动态库

此时张三接收到了来自我们的动态库,并且解包

我们用静态库的方法来尝试进行运行

明明我们都已经生成了code可执行文件,为什么在运行code的时候还是会显示没找到.so文件呢??我们输入命令ldd code来看看

确实没有找到!

这是因为尽管我们生成了code可执行文件,但是因为是动态链接的,所以执行的时候系统需要知道我们的libmyc.so在哪里才行,为什么静态库不需要呢,因为静态库在生成code的时候,是直接将所有库信息拷贝了一份给code,所以不需要让系统去找,那我们怎么让系统知道呢??

1.拷⻉ .so ⽂件到系统共享库路径下, ⼀般指 /usr/lib、/usr/local/lib、/lib64的库路径等

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

3.更改环境变量: LD_LIBRARY_PATH

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

这就是有关于我们自己制作静态库与动态库的博客啦,这只是实操部分,接下来的博客将带你深入理解库的原理,敬请期待啦~~

相关推荐
芝麻开门-新起点2 小时前
第17章:制图自动化与地图设计优化
运维·自动化
旖旎夜光2 小时前
Linux知识(1)(下)
linux·学习
HalvmånEver2 小时前
Linux:库制作与原理(一)
linux·运维·服务器
落羽的落羽2 小时前
【C++】深入浅出“图”——图的基本概念与存储结构
服务器·开发语言·数据结构·c++·人工智能·机器学习·图搜索算法
秋深枫叶红2 小时前
嵌入式第三十九篇——linux系统编程——信号通信、共享内存
linux·运维·服务器·学习
咸鱼加辣2 小时前
【nginx面试题】nginx虚拟
运维·nginx·github
乌萨奇也要立志学C++2 小时前
【Linux】线程互斥与互斥量全解析:原理、实践与封装
linux·服务器
hweiyu002 小时前
Linux命令:gzip
linux
老王熬夜敲代码2 小时前
IP和MAC的深入理解
linux·网络·笔记·网络协议