一,引言
在编写C/C++代码时一定要使用到库相关的知识。本篇博客主要讲解自己如何编辑动静态库,以及自己所写的动静态库是如何进行链接的;有那些方法可以进行链接。
在进行封装动静态库之前,还需要一份代码模拟实现库的工作,提供如下代码:
函数实现部分:my_stdio.c
cpp
#include "my_stdio.h"
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
mFILE *mfopen(const char *filename, const char *mode)
{
int fd = -1;
if(strcmp(mode, "r") == 0)
{
fd = open(filename, O_RDONLY);
}
else if(strcmp(mode, "w")== 0)
{
fd = open(filename, O_CREAT|O_WRONLY|O_TRUNC, 0666);
}
else if(strcmp(mode, "a") == 0)
{
fd = open(filename, O_CREAT|O_WRONLY|O_APPEND, 0666);
}
if(fd < 0) return NULL;
mFILE *mf = (mFILE*)malloc(sizeof(mFILE));
if(!mf)
{
close(fd);
return NULL;
}
mf->fileno = fd;
mf->flag = FLUSH_LINE;
mf->size = 0;
mf->cap = SIZE;
return mf;
}
void mfflush(mFILE *stream)
{
if(stream->size > 0)
{
// 写到内核⽂件的⽂件缓冲区中!
write(stream->fileno, stream->outbuffer, stream->size);
// 刷新到外设
fsync(stream->fileno);
stream->size = 0;
}
}
int mfwrite(const void *ptr, int num, mFILE *stream)
{
// 1. 拷⻉
memcpy(stream->outbuffer+stream->size, ptr, num);
stream->size += num;
// 2. 检测是否要刷新
if(stream->flag == FLUSH_LINE && stream->size > 0 && stream->outbuffer[stream->size-1]== '\n')
{
mfflush(stream);
}
return num;
}
void mfclose(mFILE *stream)
{
if(stream->size > 0)
{
mfflush(stream);
}
close(stream->fileno);
}
函数接口部分:my_stdio.h
cpp
#pragma once
#define SIZE 1024
#define FLUSH_NONE 0
#define FLUSH_LINE 1
#define FLUSH_FULL 2
struct IO_FILE
{
int flag; // 刷新⽅式
int fileno; // ⽂件描述符
char outbuffer[SIZE];
int cap;
int size;
// TODO
};
typedef struct IO_FILE mFILE;
mFILE *mfopen(const char *filename, const char *mode);
int mfwrite(const void *ptr, int num, mFILE *stream);
void mfflush(mFILE *stream);
void mfclose(mFILE *stream);
函数实现部分:my_string.c
cpp
#include "my_string.h"
int my_strlen(const char *s)
{
const char *end = s;
while(*end != '\0')
{
end++;
}
return end-s;
}
函数接口部分:my_string.h
cpp
#pragma once
int my_strlen(const char *s);
二,静态库
在日常使用的库中,通常只能知道库所提供的接口,但是并不知道内部的实现逻辑。因此自己想要实现一个库的逻辑也是一样的。因此首先对所有的(.c)文件进行封装形成(.o)文件。再对所有的(.o)文件进行打包。这就形成了静态库。
在编译器中对应上述通过打包的文件不需要进行解包就可以直接进行运行。打包的方法如下:
cpp
ar -rc libmyc.a *.o
其中(ar -rc )为语法固定操作。 libmyc.a 为静态库的名称。后面加需要打包的**.o**文件。
编译方法:
cpp
gcc -o 目标文件 原来的.o文件 -L. -库名称
在平时写的文件中,当需要用到自己所编写的库时,只要有将原本的编译后加(-L)紧跟库所在的相对路径或者绝对路径 。后加库名称--注意静态库中(lib和.a)都只是格式并不是库的名称;中间的(myc)才是库的名称。
三,动态库
1,使用方法
上文中讲过不管是静态库还是动态库都是要对.o文件进行打包。动态库的打包方式如下:
cpp
gcc -shared -o libmyc.so *.o
如上图,动态库的打包也是通过gcc 来实现的,只不过加了一个参数(-shared )来指明形成的是动态库文件。
在形成动态库之后,我们所写的代码中包含了所需要的动态库。最后一步链接动态库形成可执行程序。操作如下:
cpp
gcc -o 可执行文件 源文件 -I头文件路径 -L动态库路径
前半部分和形成一个正常的可执行一样。后面分别加动态库头文件所在的路径以及动态库.so文件坐在路径。
2,搜索路径方法
当运行这个可执行程序会发现运行不成功。当查看该文件的链接方式时会发现并没有成功完成链接如下:

这有由于在刚才使用gcc完成链接的过程仅仅是告诉gcc这个库所在的位置。但是当形成可执行程序时系统并找不到这个第三方库的文件就会操作链接失败。因此想要解决这个问题就是要让系统找到这个第三方库。
解决办法:
1,直接将.so库文件拷贝到指定的系统目录下--/lib64这个目录下。
2,建立软连接--将我们所写的第三方库通过软连接的方式链接到/lib64这个目录下
3,设置环境变量--在Linux操作系统中当查找一个动态库中会在指定的环境变量中查找是否存在。通过设置如下环境变量来实现动态库的查找:
LD_LIBRARY_PATH这个环境变量来进行查找。只需要设置这个环境变量所对于的路径就可以实现动态库的查找。
4,新增配置文件--在/etc/ld.so.conf.d/路径下创建一个文件内部加入所在库文件的路径,最后重新加载配置文件。
四,总结
在Linux编译器中gcc/g++默认使用的都是动态库,如果指定要实现静态链接要加上(-static),在该系统下默认安装的绝大部分库都是动态库。对于动态库和应用程序的关系中,一个动态库可以对于多个应用程序。