
1.理解軟硬鏈接
軟鏈接和硬鏈接是在Linux系統(tǒng)中常見的文件鏈接方式。
軟鏈接(Symbolic Link): 軟鏈接是一個指向目標文件或目錄的特殊文件,類似于Windows系統(tǒng)中的快捷方式。軟鏈接可以跨文件系統(tǒng),可以鏈接到目錄,也可以鏈接到文件。軟鏈接的特點是:
- 軟鏈接文件有自己的inode和文件名,但是數(shù)據(jù)塊內(nèi)容是指向目標文件的路徑。
- 刪除軟鏈接不會影響目標文件。
- 軟鏈接可以跨文件系統(tǒng),即可以鏈接到不同的磁盤分區(qū)。
硬鏈接(Hard Link): 硬鏈接是指多個文件名指向同一個inode,它們共享同一份數(shù)據(jù)塊內(nèi)容。硬鏈接的特點是:
- 硬鏈接文件和目標文件具有相同的inode和數(shù)據(jù)塊內(nèi)容。
- 刪除任意一個硬鏈接文件不會影響其他硬鏈接文件和目標文件。
- 硬鏈接只能鏈接到文件,不能鏈接到目錄。
- 硬鏈接不能跨文件系統(tǒng),即只能在同一個磁盤分區(qū)內(nèi)創(chuàng)建。
1.1 操作觀察現(xiàn)象
指令ln -s
ln -s
是Linux系統(tǒng)中的一個命令,用于創(chuàng)建軟鏈接(symbolic link)。軟鏈接是一種特殊的文件,它指向另一個文件或目錄。通過軟鏈接,可以在不改變原始文件或目錄位置的情況下,創(chuàng)建一個指向它的鏈接。
使用ln -s命令創(chuàng)建軟鏈接的語法如下:
ln -s <原始文件或目錄路徑> <鏈接文件路徑>
- 其中,<原始文件或目錄路徑>是要創(chuàng)建鏈接的文件或目錄的路徑,<鏈接文件路徑>是要創(chuàng)建的軟鏈接的路徑。
例如,假設(shè)當前目錄下有一個文件file.txt,我們可以使用以下命令創(chuàng)建一個指向它的軟鏈接:ln -s file.txt link.txt
這樣就創(chuàng)建了一個名為link.txt的軟鏈接,它指向file.txt文件。
需要注意的是,軟鏈接是一個指向原始文件或目錄的引用,而不是實際的文件或目錄本身。刪除軟鏈接不會影響原始文件或目錄,但刪除原始文件或目錄可能會導(dǎo)致軟鏈接失效。
指令ll -li
ll -li
是一個Linux命令,用于顯示文件或目錄的詳細信息,并以inode號進行排序。下面是該命令的一些說明:
-
ll
是 “l(fā)s -l” 的簡寫,用于顯示文件和目錄的詳細信息。 -
-li
是兩個選項的組合,其中-l
表示以長格式顯示文件信息,包括文件權(quán)限、所有者、大小、修改日期等;而-i
表示顯示文件的inode號。
通過執(zhí)行 ll -li
命令,您將看到當前目錄下所有文件和目錄的詳細信息,并按照inode號進行排序。
軟鏈接
結(jié)論:軟鏈接本質(zhì)上就是一個文件,有獨立的inode
指令ln
在Linux系統(tǒng)中創(chuàng)建文件硬鏈接,可以通過ln
命令來創(chuàng)建硬鏈接。ln
命令的語法如下:
ln [選項] <源文件或目錄> <目標文件或目錄>
其中,源文件或目錄是要創(chuàng)建鏈接的文件或目錄的路徑,目標文件或目錄是要創(chuàng)建的鏈接的路徑。
創(chuàng)建硬鏈接的命令格式為:
ln <源文件> <目標文件>
例如,要在當前目錄下創(chuàng)建一個名為linkfile的硬鏈接,指向源文件sourcefile,可以使用以下命令:
ln sourcefile linkfile
注意,硬鏈接只能鏈接到同一個文件系統(tǒng)中的文件,且不能鏈接到目錄。
硬鏈接
我們創(chuàng)建了硬鏈接之后可以發(fā)現(xiàn)。前面的文件信息發(fā)生了一個微小的變化,也就是文件權(quán)限后面的數(shù)字由1變成了2,而硬鏈接新出現(xiàn)的文件其初始數(shù)字就是2,這個數(shù)字從來沒有講述過
我們查看一下inode也可以發(fā)現(xiàn),新出現(xiàn)的文件與舊文件inode竟然是一樣的!
結(jié)論:硬鏈接本質(zhì)不是一個獨立的文件,因為它的inode編號和目標文件相同
1.2 軟硬鏈接的原理
測試硬鏈接
- 我們將硬鏈接的目標文件寫入點數(shù)據(jù)
可以看到我們修改目標文件的同時,硬鏈接生成的文件也會發(fā)生變化,其大小與目標文件同樣是12,且修改時間相同,inode也沒有改變
- 我們刪除目標文件
可以看到,我們的硬鏈接產(chǎn)生的文件并沒有什么變化,我們查看其文件數(shù)據(jù)可以清楚的看到,這個數(shù)據(jù)就是我們當初輸入到目標文件的數(shù)據(jù),這是什么情況?
其實也可以理解,其inode和目標文件是一摸一樣的,也就是說他們對應(yīng)的都是同一個文件,我們硬鏈接的工作特別像給目標文件進行一個重命名,并且源文件不改變。
硬鏈接的本質(zhì):一定沒有新建文件,因為沒有新的inode,只是新建了一個文件名,與目標文件inode相同的映射關(guān)系。
這個時候我們再看當初的這個2
其實這就是一個硬鏈接數(shù),表明有多少個硬鏈接,表明了有多少個文件名與這一塊數(shù)據(jù)有相同的映射關(guān)系,同時也叫引用計數(shù)
同時可以看到,硬鏈接就是建立了一個映射關(guān)系同時對引用計數(shù)++即可。
我們刪掉文件后可以看到,引用計數(shù)從2變成了1
測試軟鏈接
軟鏈接創(chuàng)建的文件有獨立的inode,有獨立的inode那么就有獨立的屬性以及獨立的數(shù)據(jù)內(nèi)容。
軟鏈接本質(zhì)就是一個獨立文件,軟鏈接內(nèi)容里面放的目標文件的路徑!
軟鏈接就相當于我們Windows里面的快捷方式,其存儲的就是其可執(zhí)行程序的路徑
1.3 軟硬鏈接的應(yīng)用場景
1.3.1軟鏈接
- 我們創(chuàng)建一系列文件并輸入內(nèi)容給test.c
#include<stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
- 將文件編譯,并把可執(zhí)行文件移動到bin目錄下
- 我們想訪問這個可執(zhí)行文件就只能訪問絕對路徑訪問
- 我們還可以采用軟鏈接的方式訪問到這個可執(zhí)行文件
我們就可以使用軟鏈接的方式,在當前目錄創(chuàng)建一個軟鏈接的文件,這樣就可以直接訪問到深路徑的文件,我們使用起來就更加方便
我們也可以采用硬鏈接的方式來達到訪問深路徑的文件
軟鏈接使用起來還是更加方便一些,一般推薦軟鏈接
系統(tǒng)有很多的軟鏈接
ls -l /lib64/
1.3.2 硬鏈接
- 我們創(chuàng)建一個普通文件以及一個目錄
可以發(fā)現(xiàn)普通文件的硬鏈接數(shù)是1,而目錄一創(chuàng)建出來硬鏈接數(shù)就是2。
- 我們進入empty目錄下
我們可以看到empty目錄下有隱藏的點文件,我們之前講過,這個就是指的當前目錄,它的inode與empty目錄的inode是一模一樣的,而它就是除了empty外另一個硬鏈接。
- 我們進入empty目錄下再創(chuàng)建一個a目錄
這里可以看到我們的empty目錄的硬鏈接數(shù)變成了3,這就是因為我們empty目錄里的a目錄里有一個自帶的點點文件,這代表的是上級目錄,它就是第三個empty目錄的硬鏈接
由此得知:一個目錄下有多少個子目錄:硬鏈接數(shù)-2即可計算得到
注意:Linux中不允許給目錄建立硬鏈接,但是可以建立軟鏈接
2.動靜態(tài)庫
-
靜態(tài)庫(.a):程序在編譯鏈接的時候把庫的代碼鏈接到可執(zhí)行文件中。程序運行的時候?qū)⒉辉傩枰o態(tài)庫
-
動態(tài)庫(.so):程序在運行的時候才去鏈接動態(tài)庫的代碼,多個程序共享使用庫的代碼。
-
一個與動態(tài)庫鏈接的可執(zhí)行文件僅僅包含它用到的函數(shù)入口地址的一個表,而不是外部函數(shù)所在目標文件的整個機器碼
-
在可執(zhí)行文件開始運行以前,外部函數(shù)的機器碼由操作系統(tǒng)從磁盤上的該動態(tài)庫中復(fù)制到內(nèi)存中,這個過程稱為動態(tài)鏈接(dynamic linking)
-
動態(tài)庫可以在多個程序間共享,所以動態(tài)鏈接使得可執(zhí)行文件更小,節(jié)省了磁盤空間。操作系統(tǒng)采用虛擬內(nèi)存機制允許物理內(nèi)存中的一份動態(tài)庫被要用到該庫的所有進程共用,節(jié)省了內(nèi)存和磁盤空間。
我們是很經(jīng)常使用庫的,我們創(chuàng)建一個普通C文件,并編寫簡單代碼
這里就是利用了C語言的庫的,之前進行簡單的講解過,這是C語言的動態(tài)庫
關(guān)于庫我們有過一定的使用經(jīng)驗
庫分為靜態(tài)庫以及動態(tài)庫-----大部分的系統(tǒng)默認安裝的是動態(tài)庫,云服務(wù)器是靜態(tài)庫–(C標準庫)默認是沒有安裝的
默認編譯程序,用的是動態(tài)鏈接的,如果要靜態(tài)要加-static
庫的真實名字:lib. XXXX -a/so 去掉前綴以及后綴
2.1 動靜態(tài)庫的制作和使用
一般我們的程序執(zhí)行會經(jīng)歷幾個階段
a.h + a.c ---> a.o
b.h + b.c ---> b.o
c.h + c.c ---> c.o
d.h + d.c ---> d.o
- 再結(jié)合
libc.so/libc.a
- 最后
main.c ------>main.o
庫則是不提供
.c
文件
a.h + a.o
b.h + b.o
c.h + c.o
d.h + d.o
你只需要將
main.c ------>main.o
注:這里的a、b、c、d只是概念文件
所謂的庫就是將所有的.o
文件用特定的方式,進行打包,形成一個文件
庫的存在的意義:
- 提高開發(fā)效率
- 隱藏源代碼
準備工作
在了解庫的使用原理后我們來模擬實現(xiàn)一個
- 創(chuàng)建五個文件
- 編寫文件
add.c
#include "add.h"
int add(int a, int b)
{
return a + b;
}
add.h
#ifndef __ADD_H__
#define __ADD_H__
int add(int a, int b);
#endif // __ADD_H__
sub.h
#ifndef __SUB_H__
#define __SUB_H__
int sub(int a, int b);
#endif // __SUB_H
sub.c
#include "add.h"
int sub(int a, int b)
{
return a - b;
}
main.c
#include <stdio.h>
#include "add.h"
#include "sub.h"
int main()
{
int a = 10;
int b = 20;
printf("add(%d, %d)=%d\n", a, b, add(a, b));
a = 100;
b = 20;
printf("sub(%d,%d)=%d\n", a, b, sub(a, b));
}
生成.o文件
生成靜態(tài)庫
指令ar -rc
ar -rc是一個用于創(chuàng)建或更新靜態(tài)庫的命令。它是GNU工具鏈中的一個工具,用于將一組目標文件打包成一個靜態(tài)庫文件。下面是ar -rc命令的一些常見用法:
- 創(chuàng)建靜態(tài)庫:可以使用ar -rc命令將多個目標文件打包成一個靜態(tài)庫文件。例如,要將文件1.o、文件2.o和文件3.o打包成一個名為libexample.a的靜態(tài)庫,可以執(zhí)行以下命令:
ar -rc libexample.a 1.o 2.o 3.o
- 更新靜態(tài)庫:如果已經(jīng)存在一個靜態(tài)庫文件,可以使用ar -rc命令向其中添加新的目標文件或替換已有的目標文件。例如,要向名為libexample.a的靜態(tài)庫中添加一個新的目標文件file.o,可以執(zhí)行以下命令:
ar -rc libexample.a file.o
- 替換靜態(tài)庫中的目標文件:如果要替換靜態(tài)庫中已有的目標文件,可以使用ar -rc命令指定相同的目標文件名。例如,要替換名為libexample.a的靜態(tài)庫中的目標文件file.o,可以執(zhí)行以下命令:
ar -rc libexample.a file.o
- 查看靜態(tài)庫內(nèi)容:可以使用ar -t命令來查看靜態(tài)庫中包含的目標文件列表。例如,要查看名為libexample.a的靜態(tài)庫中包含的目標文件列表,可以執(zhí)行以下命令:
ar -t libexample.a
輸入指令
ar -rc libmymath.a add.o sub.o
生成靜態(tài)庫
查看靜態(tài)庫中的目錄列表ar -tv libmymath.a
t:列出靜態(tài)庫中的文件
v:verbose 詳細信息
所以庫的本質(zhì)就是把一堆.o打包形成一個文件,然后通過頭文件來調(diào)用庫。注意,庫中不能包含main函數(shù)。
編譯一下,即可運行
gcc (要形成的可執(zhí)行文件名) main.c(所依賴的文件) -L .(-L + 路徑表示myc這個庫在哪個路徑下)-lmymath(指明要鏈接mymath這個靜態(tài)庫)
生成動態(tài)庫
fPIC:產(chǎn)生位置無關(guān)碼,在將.c或者.cpp形成.o文件時,需要加上-fPIC。要形成動態(tài)庫必須加上-fPIC。
形成動態(tài)庫不需要用到其它指令,gcc編譯器就可以形成動態(tài)庫,只不過要加上-shared命令。
gcc -shared -o libmymath.so(名字,真正的庫名要去掉lib和.so)sub.o add.o (所依賴的.o文件)
直接使用我們的這個動態(tài)庫,那么就同樣要告訴編譯器我們庫的名字和所在的路徑(參考上面靜態(tài)庫路徑的寫法)。
2.2 將自己的庫打包給別人
假設(shè)在我當前目錄下有l(wèi)ibmymath.so動態(tài)庫,add.h,sub.h兩個頭文件,如果我想將這三個文件一起交給別人,就可以把它們打包一起放在一個目錄下,一起壓縮完再交給別人。
Makefile
1 libmymath.so:add.o sub.o
2 gcc -shared -o $@ $^
3 .o:.c
4 gcc -shared -c $<
5 #add.o:add.c
6 # gcc -c -fPIC $< -o $@
7 #sub.o:sub.c
8 # gcc -c -fPIC $< -o $@
9 .PHONY:clean
10 clean:
11 rm -f *.o libmymath.so
12
13 .PHONY:output
14 output:
15 mkdir -p ./user/mylib/
16 mkdir -p ./user/Headfile/
17 cp -rf libmymath.so ./user/mylib/
18 cp -rf add.h sub.h ./user/Headfile/
19 tar -czf user.tgz user
user目錄是通過user.tgz解壓得到的,下面是user目錄下的文件:
文章來源:http://www.zghlxwxcb.cn/news/detail-850082.html
將兩個頭文件拷貝到usr/include目錄下(編譯器默認會到include目錄下去尋找頭文件),將庫文件拷貝到usr/lib目錄下,編譯時指定庫鏈接,就能夠運行了。
文章來源地址http://www.zghlxwxcb.cn/news/detail-850082.html
到了這里,關(guān)于【linux深入剖析】深入理解軟硬鏈接 | 動靜態(tài)庫的制作以及使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!