php無(wú)版權(quán)企業(yè)網(wǎng)站管理系統(tǒng)企業(yè)網(wǎng)站推廣外包
目錄
- 引入
- 內(nèi)存級(jí)文件
- 重新使用C文件接口 -- 對(duì)比重定向
- 寫文件
- 讀文件
- 文件流
- 認(rèn)識(shí)文件操作的系統(tǒng)接口
- open
- 參數(shù) -- flag
- flag的內(nèi)容
- 宏的傳參方式
- open
- 關(guān)閉文件
- 寫文件
- 讀文件
- 結(jié)論
- 引入文件描述符fd、對(duì)文件的理解
- 理解一切皆文件
- 方法集
- 文件fd的分配規(guī)則
- 重定向
- 代碼的重定向
- 輸入重定向
- 輸出重定向
- 追加重定向
- 指令重定向
- 輸入重定向
- 輸出重定向
- 追加重定向
- 修改之前的shell,讓它支持重定向
- 緩沖區(qū)
- 概念
- 在哪里
- 磁盤級(jí)文件(文件系統(tǒng))
- 磁盤
- 磁盤的機(jī)械構(gòu)成
- 磁盤的物理存儲(chǔ)
- 磁盤的邏輯存儲(chǔ)
- 1、紅色部分
- 2、藍(lán)色部分
- 文件的增刪查改和路徑有關(guān)
- 具體的文件系統(tǒng)
- 軟硬鏈接
- 原理
- 應(yīng)用場(chǎng)景
- 動(dòng)靜態(tài)庫(kù)
- 回顧
- 動(dòng)態(tài)庫(kù)的制作和使用
- 理解動(dòng)態(tài)庫(kù)加載
- 系統(tǒng)角度理解
- 編址
- 理解動(dòng)態(tài)庫(kù)動(dòng)態(tài)鏈接和加載問(wèn)題
引入
a、文件 = 內(nèi)容 + 屬性
b、訪問(wèn)文件之前,都得先打開。修改文件,都是通過(guò)執(zhí)行代碼的方式完成修改,文件必須被加載到內(nèi)存中
c、進(jìn)程在打開文件
d、一個(gè)打開多少個(gè)文件?可以打開多個(gè)
一定時(shí)間段內(nèi),系統(tǒng)中有多個(gè)進(jìn)程,那么就有更多同時(shí)被進(jìn)程打開的文件,OS要不要管理多個(gè)被進(jìn)程打開的文件?肯定的,先描述再組織
e、進(jìn)程和文件的關(guān)系,struct task_struct和struct xxxx
f、沒(méi)有被打開的文件在哪?磁盤
內(nèi)存級(jí)文件
重新使用C文件接口 – 對(duì)比重定向
寫文件
文件創(chuàng)建的路徑和進(jìn)程有著很大的關(guān)系
像文件里面寫入內(nèi)容:fputs
#include<stdio.h>int main()
{FILE* fp = fopen("./log.txt", "w");if(fp == NULL){perror("fopen");return 1;}const char* str = "hello linux\n";fputs(str, fp);fclose(fp);return 0;
}
文件打開再關(guān)閉就被清空了?
以w方式打開文件,該文件會(huì)被清空
echo “xxxxxx” > log.txt
以a的方式打開,不會(huì)清空文件
echo “xxxxxx” >> log.txt
fwrite寫入數(shù)據(jù)
第一個(gè)參數(shù):寫入文件的其實(shí)內(nèi)存;第二個(gè)參數(shù):寫入數(shù)據(jù)的大小,每個(gè)基本單位的大小;第三個(gè)參數(shù):寫入幾個(gè)基本單元;
返回值:寫入了多少個(gè)基本單位
fputs
:是寫入字符串的形式,它是認(rèn)識(shí)字符串,以\0
結(jié)尾
fwrite
:是以二進(jìn)制流寫入,不認(rèn)識(shí)字符串
如果沒(méi)有此文件,當(dāng)指定絕對(duì)路徑就會(huì)在絕對(duì)路徑下創(chuàng)建這個(gè)文件,否則就在該進(jìn)程所在目錄下創(chuàng)建
int main()
{FILE* fp = fopen("log.txt", "w");if(fp == NULL){perror("fopen");return 1;}char* str = "hello file\n";int cnt = 5;while(cnt){int num = fwrite(str, strlen(str), 1, fp);cnt--;}fclose(fp);return 0;
}
那改變進(jìn)程的路徑,創(chuàng)建的這個(gè)文件也會(huì)變
讀文件
fgets
:一行讀出
文件流
程序默認(rèn)打開的文件流
stdin | 標(biāo)準(zhǔn)輸入 | 鍵盤設(shè)備 |
---|---|---|
stdout | 標(biāo)準(zhǔn)輸出 | 顯示器設(shè)備 |
stderro | 標(biāo)準(zhǔn)錯(cuò)誤 | 顯示器設(shè)備 |
向顯示器繼續(xù)打印的方法
printf、fprintf、fwrite、fputs
int main()
{FILE* fp = fopen("./log.txt", "w");if(fp == NULL){perror("fopen");return 1;}//標(biāo)準(zhǔn)寫入//默認(rèn)想顯示器寫入,寫入流是stdoutprintf("hello printf\n");//與printf略有不同,寫入到哪里不是默認(rèn)的fprintf(stdout, "hello fprintf\n");fprintf(fp, "hello fprintf\n");//char* str = "hello fputs";fputs(str, fp);fputs(str, stdout);//char* str2 = "hello fwrite";fwrite(str2, strlen(str2), 1, fp);fwrite(str2, strlen(str2), 1, stdout);fclose(fp);
標(biāo)準(zhǔn)輸入的方法
scanf 、 fread、fscanf
FILE* fp2 = fopen("./log.txt", "r");if(fp2 == NULL){perror("fopen");return 1;}char str3[64];scanf("%s", str3);printf("%s\n", str3);fscanf(stdin, "%s", str3);printf("%s\n", str3);fread(str3, strlen(str3), 1, stdin);fclose(fp2);
結(jié)論:stdin、stdout、stderro可以直接被使用
認(rèn)識(shí)文件操作的系統(tǒng)接口
訪問(wèn)文件不僅僅有C語(yǔ)言上的文件接口,OS必須提供對(duì)應(yīng)的訪問(wèn)文件的系統(tǒng)調(diào)用
w:會(huì)清空文件
a:追加文件
r:讀取文件
open
返回值:成功–文件描述符, 失敗—1
參數(shù):flags
返回值:int類型的數(shù)據(jù)
參數(shù) – flag
flag的內(nèi)容
O_RDONY | 只讀打開 |
---|---|
O_WRONLY | 只寫打開 |
O_RDWR | 讀寫打開 |
O_CREAT | 如果文件沒(méi)有就創(chuàng)建 |
O_TRUNC | 當(dāng)對(duì)已有內(nèi)容文件做寫入時(shí),會(huì)對(duì)文件內(nèi)容清空 |
O_APPEND | 每次文件打開向文件結(jié)尾處寫,追加 |
宏的傳參方式
如果傳五個(gè)參,要設(shè)置五個(gè)參數(shù)比較低級(jí),可以設(shè)置標(biāo)志位
設(shè)置一個(gè)參數(shù),參數(shù)類型是int, 每個(gè)bit位代表一個(gè)flag
#include<stdio.h>
#include<string.h>
#include<unistd.h>#define ONE 1
#define TWO (1<<1)
#define THREE (1<<2)
#define FOUR (1<<3)
#define FIVE (1<<4)void Print(int flag)
{if(flag & ONE) printf("1\n");if(flag & TWO) printf("2\n");if(flag & THREE) printf("3\n");if(flag & FOUR) printf("4\n");if(flag & FIVE) printf("5\n");return;
}int main()
{Print(ONE);printf("----------------------\n");Print(THREE);printf("----------------------\n");Print(ONE|TWO|THREE);printf("----------------------\n");Print(THREE|FOUR|FIVE);return 0;
}
對(duì)于open函數(shù)中的flag參數(shù)也是如上那么使用
open
先學(xué)習(xí)三個(gè)參數(shù)的
mode
: 權(quán)限設(shè)置
普通文件:0666
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>int main()
{int fd = open("log.txt", O_WRONLY|O_CREAT);close(fd);return 0;
}
兩個(gè)參數(shù)的open在沒(méi)有文件的時(shí)候也能創(chuàng)建,但是創(chuàng)建文件的權(quán)限是亂的
因此需要三個(gè)參數(shù)的open的第三個(gè)參數(shù)mode去設(shè)置創(chuàng)建文件的權(quán)限
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>int main()
{int fd = open("log.txt", O_WRONLY|O_CREAT, 0666);close(fd);return 0;
}
但是上面創(chuàng)建的文件的屬性和我們?cè)O(shè)置的0666
還是不一樣的,它是0644
。那是因?yàn)椴僮飨到y(tǒng)有自己的掩碼umask
不使用系統(tǒng)的umask
,想使用自己的可以在代碼中使用umask()
函數(shù)進(jìn)行設(shè)置
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>int main()
{umask(0);int fd = open("log.txt", O_WRONLY|O_CREAT, 0666);close(fd);return 0;
}
如果文件存在,使用兩個(gè)參數(shù)的open,如果文件不存在,使用三個(gè)參數(shù)的open
關(guān)閉文件
利用返回值關(guān)閉文件
用那個(gè)整數(shù)文件描述符
返回值
為何默認(rèn)從3開始?0、1、2已經(jīng)被用了,stdin – 0、stdout–1、stderror – 2
數(shù)組下標(biāo)?
寫文件
write
strlen(str)不要+1 : \0不是字符串的內(nèi)容,是C語(yǔ)言規(guī)定字符串以、0結(jié)尾。寫入就是亂碼
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>int main()
{//寫文件int fd = open("log.txt", O_WRONLY|O_CREAT, 0666);if(fd == -1){perror("open");return 1;}char* str = "hello world";ssize_t i = write(fd, str, strlen(str));if(i < 0){perror("write");return 1;}close(fd);return 0;
}
系統(tǒng)調(diào)用寫文件,不會(huì)清空文件,直接覆蓋式的往里寫
參數(shù)flag使用O_TRUNC
,即可清空文件里的內(nèi)容再往里面寫
讀文件
返回值:ssize_t
有符號(hào)的整數(shù)
fd:要讀取文件的描述符
buf:讀出的內(nèi)容存放的緩沖區(qū)
count:放入內(nèi)容最大可以存放多少
=0 | 文件結(jié)束 |
---|---|
<0 | 讀取錯(cuò)誤 |
>0 | 讀取成功,讀到多少個(gè)字符 |
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>int main()
{int fd = open("log.txt", O_RDONLY);char str[1024];ssize_t s = read(fd, str, sizeof(str)-1);str[s] = '\0';printf("%s\n", str);close(fd);
結(jié)論
1、C語(yǔ)言的文件接口,本質(zhì)是封裝了系統(tǒng)調(diào)用。不僅在接口進(jìn)行封裝,在類型上進(jìn)行封裝
2、FILE是C標(biāo)準(zhǔn)庫(kù)自己封裝的一個(gè)結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體里一定包含open返回的那個(gè)fd(0.1.2.3…)
3、為何C語(yǔ)言要封裝?為了保證自己的跨平臺(tái)性和可移植性
4、文件描述符的本質(zhì):數(shù)組下標(biāo)
引入文件描述符fd、對(duì)文件的理解
文件描述符的本質(zhì):數(shù)組下標(biāo)
理解一切皆文件
方法集
對(duì)于文件的描述struct file
里面有一塊是函數(shù)指針,函數(shù)指針指向具體的硬件的調(diào)用方法
文件fd的分配規(guī)則
現(xiàn)象1:
關(guān)掉0文件,再打開自己文件,看其文件描述符
tu
最小的沒(méi)有被使用的數(shù)組下標(biāo),會(huì)分配給最新打開的文件
現(xiàn)象2:
關(guān)掉1,打印時(shí)并沒(méi)有在屏幕里打印出來(lái),竟然把信息寫入到了文件里面
輸出重定向:語(yǔ)言層不變,在操作系統(tǒng)層進(jìn)行更改
重定向
代碼的重定向
輸入重定向
輸入重定向,從鍵盤輸入的重定向,stdin
– 0
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>int main()
{close(0);int fd = open("log.txt", O_RDONLY);char buffer[1024];while(1){char* s = fgets(buffer, sizeof(buffer), stdin);if(s == NULL) break;printf("file content:%s", buffer);}close(fd);return 0;
}
輸出重定向
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>int main()
{char* str = "hello world";int fd = open("log.txt", O_WRONLY|O_CREAT|O_APPEND, 0666);dup2(fd, 1);fprintf(stdout, "file %s\n", str);close(fd);return 0;
}
追加重定向
不想利用文件描述符的分配規(guī)則,直接打開,打開之后再拷貝到1的位置,也完成了重定向
最終只剩old
dup2(fd, 1);
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>int main()
{char* str = "hello world";int fd = open("log.txt", O_WRONLY|O_CREAT|O_APPEND, 0666);dup2(fd, 1);fprintf(stdout, "file %s\n", str);close(fd);return 0;
}
指令重定向
輸入重定向
沒(méi)有對(duì)應(yīng)的文件會(huì)創(chuàng)建
什么也不做的時(shí)候會(huì)被清空
輸出重定向
追加重定向
修改之前的shell,讓它支持重定向
緩沖區(qū)
概念
緩沖區(qū)是一塊內(nèi)存空間
提高使用者效率
刷新:聚集數(shù)據(jù),一次拷貝,提高整體效率
我們一直在說(shuō)的緩沖區(qū)和內(nèi)核中的緩沖區(qū)沒(méi)有關(guān)系,語(yǔ)言層面的緩沖區(qū),C語(yǔ)言自帶緩沖區(qū)
調(diào)用系統(tǒng)調(diào)用是有成本的,時(shí)間&&空間
單次調(diào)用一次系統(tǒng)調(diào)用就可以完成工作是效率比較高的
語(yǔ)言層緩沖區(qū)刷新
(1)無(wú)刷新,無(wú)緩沖
(2)行刷新 ----- 顯示器,XXXX\nYY
(3)全刷新 ----- 普通文件,緩沖區(qū)寫滿才刷新
例外
強(qiáng)制刷新
進(jìn)程退出,要自動(dòng)刷新
內(nèi)核中的緩沖區(qū)
OS自主決定
在哪里
緩沖區(qū)在大寫的FILE*內(nèi)部,像stdin、stdout、stderror都是一個(gè)FILE里面都有一個(gè)緩沖區(qū)
如何證明這個(gè)緩沖區(qū)的存在呢?
子進(jìn)程先退出,退出時(shí)對(duì)于緩沖區(qū)需要進(jìn)行刷新,刷新就是修改,修改就要寫時(shí)拷貝,因此打了兩遍
緩沖區(qū)還要支持格式化輸入輸出的實(shí)現(xiàn)
鍵盤顯示器的輸入和顯示都是字符級(jí)的,格式化輸入輸出,就是把字符轉(zhuǎn)換成int、string...
,或者int、string...
轉(zhuǎn)換成字符級(jí)的
磁盤級(jí)文件(文件系統(tǒng))
如何讓系統(tǒng)快速定位一個(gè)文件?
文件系統(tǒng),通過(guò)路徑快速定位文件
例如:菜鳥驛站取快遞
磁盤
磁盤的機(jī)械構(gòu)成
盤片、磁頭(一面一個(gè)磁頭)、馬達(dá)、伺服系統(tǒng)(識(shí)別指令并控制盤片和磁頭)
磁盤的物理存儲(chǔ)
磁道/柱面:一圈
扇區(qū):磁道中的某一部分成為扇區(qū),磁盤IO的基本單位,不一定是系統(tǒng)的
當(dāng)你想要修改某一個(gè)扇區(qū)中的一個(gè)bit位,必須把整個(gè)扇區(qū)加載到內(nèi)存里,修改要修改的bit位,之后再將整個(gè)扇區(qū)的信息寫入。一般512字節(jié)
磁頭/盤面:一個(gè)磁頭一個(gè)盤面,一個(gè)盤面一個(gè)編號(hào)
訪問(wèn)某一個(gè)扇區(qū):
CHS定位法
1、通過(guò)磁頭定位在哪個(gè)磁道/柱面 cylinder
2、使用哪一個(gè)磁頭/盤面head
3、使用哪一個(gè)扇區(qū)sector
磁盤的邏輯存儲(chǔ)
邏輯存儲(chǔ)方便軟件的編寫
LBA地址logical block address
雖然把內(nèi)容進(jìn)行了抽象,但是一次管理這么多還是不容易,所有分成幾塊,分區(qū)
大的分區(qū)再分成很多很多組
一個(gè)文件一個(gè)inode(大小128字節(jié))
刪除文件:不會(huì)刪除內(nèi)容,只要把inode bitmap和block bitmap使用的置為0就好了
Linux磁盤文件的特性:內(nèi)容+屬性
內(nèi)容和屬性分開存儲(chǔ)
內(nèi)容大小不確定,可能很大,可能很小
屬性固定大小的
文件名不屬于文件屬性
ll -i //顯示inode
系統(tǒng)中,表示一個(gè)文件吧不是用文件名,而是inode
每個(gè)inode的大小:128字節(jié)
inode Bitmap:知道inode Table的使用情況
Data blocks:數(shù)據(jù)區(qū)
Block Bitmap:塊位圖
Group Descriptor Table:塊組描述符表
系統(tǒng)里面創(chuàng)建一個(gè)文件的步驟
在某一個(gè)塊創(chuàng)建一個(gè)文件,首先查Inode Bitmap找一個(gè)沒(méi)有被使用的inode,將該文件的相關(guān)屬性寫到找的那個(gè)inode在inode table里面。當(dāng)對(duì)此文件進(jìn)行寫入數(shù)據(jù)的時(shí)候,先查Block Bitmap看看數(shù)據(jù)區(qū)的哪一塊可以使用,寫入到數(shù)據(jù)區(qū)相應(yīng)的塊。之后在該文件的inode里面的有個(gè)int block[15]
寫到這里面,讓文件知道自己用了哪個(gè)塊
inode在整個(gè)分區(qū)內(nèi)唯一
1、首先確定inode在哪個(gè)組里
1、紅色部分
對(duì)于一個(gè)文件,int block只有15塊嗎,這么小?不是的,有直接索引、間接索引、三級(jí)索引
2、藍(lán)色部分
GDT,Group Descriptor Table:塊組描述符,對(duì)分組進(jìn)行管理,描述塊組屬性信息
超級(jí)塊(Super Block):存放整個(gè)分區(qū)情況,對(duì)分區(qū)做管理,一個(gè)文件系統(tǒng)對(duì)應(yīng)一個(gè)super block。一個(gè)區(qū)里選n個(gè)group里面有super block,內(nèi)容是一致的
每個(gè)分區(qū)可以寫入相同或不同的文件系統(tǒng) — super block
目錄是不是文件?是。inode(inode編號(hào))+ 目錄的內(nèi)容(文件名和inode的映射)
當(dāng)目錄沒(méi)有w權(quán)限,在該目錄里面就沒(méi)法創(chuàng)建文件,沒(méi)法刪除文件
當(dāng)目錄沒(méi)有r權(quán)限,就讀不到文件名和inode的映射信息,也就讀不到該目錄下的文件信息
創(chuàng)建文件
(1)查詢inode bitmap查找哪個(gè)inode沒(méi)有用,在相應(yīng)位置創(chuàng)建inode
(2)將inode編號(hào)和文件名的對(duì)應(yīng)寫在相應(yīng)目錄的內(nèi)容里
刪除一個(gè)文件
(1)從目錄里面找到要?jiǎng)h文件名對(duì)應(yīng)的inode
(2)將inode bitmap和block bitmap該文件使用的位置設(shè)置為0
(3)刪除該文件在相應(yīng)目錄內(nèi)容里的inode和文件名的對(duì)應(yīng)
那么訪問(wèn)目錄的內(nèi)容也是需要inode的,哪里來(lái)的
文件的增刪查改和路徑有關(guān)
根目錄的inode,開機(jī)OS是知道的
查一個(gè)文件:在內(nèi)核中,都要逆向的遞歸般得到/,從根目錄進(jìn)行路徑解析
struct dentry{ }
每打開一個(gè)路徑都會(huì)緩存路徑,緩存成一個(gè)dentry
一個(gè)被寫入文件系統(tǒng)的分區(qū),要被linux使用,必須要先把這個(gè)具有文件系統(tǒng)的分期進(jìn)行==“掛載”==
掛起:一個(gè)文件系統(tǒng)所對(duì)應(yīng)的分區(qū),掛載在對(duì)于目錄里面
每一個(gè)分區(qū)都會(huì)掛載在一個(gè)目錄下
訪問(wèn)一個(gè)文件,可以根據(jù)路徑前綴,優(yōu)先區(qū)分文件在哪一個(gè)分區(qū)下
具體的文件系統(tǒng)
軟硬鏈接
原理
軟連接
軟鏈接本質(zhì):是一個(gè)文件,因?yàn)樗凶约旱膇node
軟件內(nèi)容放的是目標(biāo)文件的路徑,類似快捷方式
硬鏈接
硬鏈接:本質(zhì)不是一個(gè)獨(dú)立的文件,因?yàn)樗膇node編號(hào)和目標(biāo)文件的一樣。一定沒(méi)有新建文件
是新的文件名,和目標(biāo)文件inode號(hào)的映射關(guān)系,寫入到指定的目錄的數(shù)據(jù)庫(kù)中
硬鏈接像重命名,引用計(jì)數(shù)
應(yīng)用場(chǎng)景
刪除一個(gè)文件
rm -f 文件名
unlink 文件名
1、軟鏈接
當(dāng)我們寫了一個(gè)項(xiàng)目mytest
要傳給其他人,不想把原始代碼傳給他,只傳bin、conf、log、myexe
對(duì)方要運(yùn)行myexe就需要./bin/myxe
這樣很麻煩,因此可以用一個(gè)軟連接
2、硬鏈接
當(dāng)創(chuàng)建一個(gè)空文件的時(shí)候,它的硬鏈接數(shù)就是2,為什么?
因?yàn)樗幸粋€(gè).
OS不允許用戶自己給目錄簡(jiǎn)歷硬鏈接,因?yàn)闀?huì)形成環(huán)路問(wèn)題
OS可以自己建立,eg. ..
動(dòng)靜態(tài)庫(kù)
回顧
1、默認(rèn)安裝的是動(dòng)態(tài)庫(kù),云服務(wù)器,靜態(tài)庫(kù)(c標(biāo)準(zhǔn)庫(kù))默認(rèn)沒(méi)有安裝
2、默認(rèn)編譯程序,用的是動(dòng)態(tài)鏈接的
動(dòng)態(tài)庫(kù)的制作和使用
為什么要有庫(kù)?
提高開發(fā)效率
隱藏源代碼
1、建立靜態(tài)庫(kù)
當(dāng)沒(méi)有源代碼的時(shí)候,只有.o .h
就可以使用里面的方法
假設(shè)我有一些寫好的方法,user
這個(gè)用戶想要使用,但我不想給他我的源代碼,就可以只給他.o .h
文件
但是當(dāng).o
文件很多的時(shí)候很麻煩,而且難免會(huì)有遺漏的
ar -rc libmyc.a 打包文件 打包文件
庫(kù)名:myc,去掉前綴、去掉后綴
-l
:鏈接哪個(gè)庫(kù)
-L
:連接的庫(kù)在什么地方,因?yàn)橄到y(tǒng)只默認(rèn)知道lib64
下的,所以這要指明
2、形成動(dòng)態(tài)庫(kù)并發(fā)布
轉(zhuǎn)換成.o文件
fPIC :產(chǎn)生位置無(wú)關(guān)碼
//形成.o文件
gcc -c -fPIC 文件名
動(dòng)態(tài)庫(kù)打包
shared:表示生產(chǎn)共享庫(kù)格式
gcc -shared -o libxxx.so xxxx.o xxxx.o
庫(kù)的名字以so結(jié)尾
但此時(shí)給使用者動(dòng)態(tài)庫(kù),還是需要給動(dòng)態(tài)庫(kù)、.h等文件,我們可以把它們合并成一個(gè)
libmyc.so: mymath1.o mymath2.ogcc -shared -o $@ $^%.o:%.cgcc -c -fPIC $<
#mymath1.o:mymath1.c
# gcc -c -fPIC $<
#mymath2.o:mymath2.c
# gcc -c -fPIC $<.PHONY:clean
clean:rm -f *.o mylib libmyc.so.PHONY:output
output:mkdir -p mylib/includemkdir -p mylib/libcp -rf *.h mylib/includecp -rf *.so mylib/lib
其中
$<
代表依賴的對(duì)象從左到右一個(gè)一個(gè)執(zhí)行
還可以吧mylib
壓縮一下
不想使用-L
:把這個(gè)庫(kù)拷貝到/lib64
//看可執(zhí)行程序連接了那些庫(kù)
ldd xxx.out
4、用戶下載
下載使用很麻煩,把.h和庫(kù)拷貝到默認(rèn)路徑下,就可以不用帶了
所謂的把庫(kù)(其他軟件)安裝到系統(tǒng)中,本質(zhì)就是把文件拷貝到指定路徑
5、卸載
不建議把自己寫的不成熟的庫(kù)寫到默認(rèn)路徑里
注意
靜態(tài)庫(kù)只需要編譯的時(shí)候使用,之后運(yùn)行什么的就不需要了(只影響編譯階段)
動(dòng)態(tài)庫(kù):(1)編譯時(shí)搜索路徑 ---- gcc(2)運(yùn)行時(shí)的搜索路徑 — 操作系統(tǒng)
對(duì)于動(dòng)態(tài)庫(kù)在編譯的時(shí)候可以跑通,運(yùn)行的時(shí)候又找不到庫(kù)了
解決方法
1、把自己的庫(kù)拷貝到默認(rèn)路徑下/lib64
,既可以支持編譯、又可以支持運(yùn)行
2、將不在系統(tǒng)默認(rèn)庫(kù)搜索路徑下的庫(kù)連接,添加到LD_LIBERERY_PATH
:系統(tǒng)運(yùn)行程序時(shí),動(dòng)態(tài)庫(kù)查找時(shí)的輔助,:為分隔符
export LD_LIBERERY_PATH=$LD_LIBRARY_PATH:具體路徑
問(wèn)題:重新登陸就沒(méi)有了,但是在家目錄里面的.bashrc
里配置
3、對(duì)庫(kù)文件在默認(rèn)庫(kù)路徑下建立同名軟連接
4、配置文件:把路徑放到配置文件里就可以
/etc/ld.so.conf.d
在該目錄下創(chuàng)建配置文件
ldconfig
使配置文件生效
理解動(dòng)態(tài)庫(kù)加載
1、同時(shí)形成動(dòng)靜態(tài)庫(kù),默認(rèn)動(dòng)態(tài)鏈接
2、非要靜態(tài)鏈接必須使用選項(xiàng)-static
3、如果只提供靜態(tài)庫(kù),那我們的可執(zhí)行程序也沒(méi)辦法,只能對(duì)該庫(kù)進(jìn)行靜態(tài)鏈接,但是程序不一定整體是靜態(tài)鏈接
4、如果只提供動(dòng)態(tài)庫(kù),默認(rèn)只能動(dòng)態(tài)鏈接,非得靜態(tài)鏈接,會(huì)發(fā)生連接報(bào)錯(cuò)
系統(tǒng)角度理解
庫(kù)函數(shù)的調(diào)用,依舊在進(jìn)程的地址空間中進(jìn)行的
動(dòng)態(tài)庫(kù)加載之后,會(huì)映射到進(jìn)程的共享區(qū)
1、誰(shuí)來(lái)決定,哪些庫(kù)加載了,那些沒(méi)加載?OS會(huì)自動(dòng)決定
2、系統(tǒng)中可以同時(shí)有多個(gè)庫(kù)嗎?可以
3、操作系統(tǒng)對(duì)這些庫(kù)先描述再組織
編址
可執(zhí)行程序加載之前,就有地址
我們進(jìn)程地址空間里面很多地址數(shù)據(jù),是從可執(zhí)行程序里面來(lái)的(因?yàn)椴煌目蓤?zhí)行程序,他的數(shù)據(jù)段和代碼段是不一樣的,進(jìn)程初始化進(jìn)程地址空間每塊多大的時(shí)候就是根據(jù)可執(zhí)行程序)
可執(zhí)行程序編制方式:
絕對(duì)編址方式—平坦模式(從0開始編址)
相對(duì)地址—邏輯編制(偏移量)
==虛擬地址空間本身不僅OS要遵守,編譯器編譯程序的時(shí)候,也要遵守
理解動(dòng)態(tài)庫(kù)動(dòng)態(tài)鏈接和加載問(wèn)題
1、進(jìn)程的地址空間既然是一個(gè)數(shù)據(jù)結(jié)構(gòu)對(duì)象,誰(shuí)來(lái)用什么數(shù)據(jù)初始化呢?
可執(zhí)行程序本身在加載到內(nèi)存之前,根據(jù)自身表頭的數(shù)據(jù)部分初始化進(jìn)程地址空間的數(shù)據(jù)段、代碼段等的begin end