Linux軟硬鏈接和動靜態庫(20)

文章目錄

  • 前言
  • 一、軟硬鏈接
    • 基本認知
    • 實現原理
    • 應用場景
    • 取消鏈接
    • ACM時間
  • 二、動靜態庫
    • 認識庫
    • 庫的作用
  • 三、制作靜態庫
    • 靜態庫的打包
    • 靜態庫的使用
  • 四、制作動態庫
    • 動態區的打包
    • 動態庫的鏈接與使用
    • 動態庫的鏈接原理
  • 總結


前言

在這里插入圖片描述

??我有款非常喜歡玩的游戲,叫做《饑荒》,現在我下載了這一款游戲,但我不會跑到游戲所在目錄中雙擊 .exe 打開游戲,大多數人都會通過桌面的快捷方式直接打開文件,而這個快捷方式實際就是對 .exe 的 軟鏈接 文件; 當你在游戲中加載地圖、道具等資源時,這些數據是存在 .exe 文件中的嗎? 答案是當然不是,這些資源文件都以 庫 的方式與 .exe 位于同一目錄中,通常為動態庫,在 Windows 中后綴為 dll,那么這些神奇的輔助文件是如何產生的? 其本質又是如何?本篇將帶你一起揭曉。

另外還有一個小要求,請先回顧一下我上篇文章的 inode 這個概念,這在本篇仍很重要


一、軟硬鏈接

基本認知

對文件進行軟鏈接

ln -s file.txt file-soft.link

對文件進行硬鏈接

ln file.txt file-hard.link

源文件,軟鏈接文件,硬鏈接文件如下:
在這里插入圖片描述

注意: 可以對目錄進行軟鏈接,但不能對目錄進行硬鏈接,具體原因后面再解釋

??那么生成的軟硬鏈接有什么用呢?

??像源文件一樣使用即可,結果一模一樣(因為當前軟硬鏈接的都是同一個源文件)
在這里插入圖片描述
同時我們發現這兩種鏈接方式其本質上是有很大差別的:

  1. 軟鏈接文件的 inode 編號與源文件不同(獨立存在),軟鏈接文件比源文件小得多,并且 軟連接文件 -> 源文件
  2. 硬鏈接文件與源文件共用一個 inode 編號(對源文件其別名),硬鏈接文件與源文件一樣大,并且硬鏈接文件與源文件的鏈接數變成了 2

軟鏈接文件依賴于源文件,而硬鏈接文件是源文件的別名

當我們將源文件刪除后,軟鏈接失效; 硬鏈接仍然有效,不過硬鏈接數變為了 1
在這里插入圖片描述

??同樣是對源文件進行鏈接,為何兩種鏈接方式差別如此大呢? 這就不得不談一下它們的實現原理了

實現原理

??軟鏈接又稱為符號鏈接,它是一個單獨存在的文件,擁有屬于自己的 inode 屬性及相應的文件內容,不過在軟鏈接的 Data block 中存放的是源文件的地址,因此軟鏈接很小,并且非常依賴于源文件

??在這里以QQ為例,可以看到快捷方式(軟鏈接方式)中存放的是源文件的地址

在這里插入圖片描述
??因此如果源文件被刪除了,那么在執行軟連接文件時,其中的地址就是一個無效地址(目標文件已丟失),此時就會報錯 No such file or directory

??假設只是單純的刪除軟連接文件,那么對源文件的內容沒有絲毫影響,就好比 桌面上的快捷方式,有的人以為將快捷方式(軟鏈接)文件刪除了,就是在 “卸載” 軟件,其實不是,如果想卸載軟件,直接將其源文件相關文件夾全部刪除即可

有多少人到現在還有誤解呢?

??硬鏈接并非創建一個相同的文件進行鏈接,而是在源文件所目錄下的 (inode編號 & 文件名) 對應表中,新增 inode 編號與 硬鏈接文件名 的映射關系,并將 inode 結構體中的引用計數 +1,表示當前已成功硬鏈接上了一個文件
在這里插入圖片描述
??當刪除當前 對應文件時,會 先判斷 ref_count 是否為 1,如果是,才會將文件內容及其屬性真正刪除,否則刪除的只是 文件名 與 inode 編號的映射關系inode

??這也就解釋了為什么刪除源文件后,硬鏈接文件不受任何影響,僅僅只是 硬鏈接數 - 1,同理,刪除硬鏈接文件,也不會影響源文件

??為什么新建目錄的硬鏈接數為 2 ?

  1. 因為一個目錄在新建后,其中默認存在兩個隱藏文件:. 與 …
  2. 其中 . 表示當前目錄,… 表示上級目錄

??Linux 中的目錄結構為多叉樹,即當前節點(目錄)需要與父節點(上級目錄)、子節點(下級目錄)建立鏈接關系,并且還得知道當前目錄的地址,否則就會導致切換目錄時出現錯誤

在這里插入圖片描述
??為了避免因用戶的誤操作而導致的目錄環狀問題,規定用戶不能手動給目錄建立硬鏈接關系,只能由 OS 自動建立硬鏈接,比如新目錄后,默認與上級目錄和當前目錄建立硬鏈接文件,在當目錄下創建新目錄后,當前目錄的硬鏈接數 + 1

所以說,將目錄的硬鏈接數 - 2 ,得到的數字就是該目錄下的目錄數

在這里插入圖片描述

??4 - 2 = 2,所以目錄 gitQuest 下一共有2個目錄,我們來驗證一下:
在這里插入圖片描述

應用場景

??軟鏈接可以當作快捷方式使用,比如快速運行一個藏的很深的可執行程序
在這里插入圖片描述
??而硬鏈接一是可以用來當作目錄移動的工具二是可以用來給重要的源文件起別名并使用,一旦發生刪除等不可逆行為時,可以確保源文件的安全

??注意: 硬鏈接并不是將源文件直接進行備份,而是新建立 inode 編號與硬鏈接文件名的映射關系,同時 struct inode 中的引用計數 ref_count++,只有當 ref_count == 1 時才會真正刪除文件內容及屬性, 否則都只是在取消映射關系和 ref_count–

取消鏈接

取消鏈接的方式有兩種:

  1. 直接刪除鏈接文件
  2. 通過 unlink 取消鏈接關系

ACM時間

??每一個文件都有三個時間:訪問 Access、修改屬性 Change、修改內容 Modify,簡稱為時間ACM

??可以通過 查看指定文件的 時間信息 statACM

在這里插入圖片描述
這三個時間的刷新策略如下:

  • Access:最近一次查看內容的時間,具體實現取決于系統
  • Change:最近一次修改屬性的時間
  • Modify:最近一次修改內容的時間(內容更改后,屬性也會跟著修改)

??Access 是高頻操作,如果每次查看都更新的話,會導致 效率變低,因此 實際變化取決于刷新策略:查看 N 次后刷新IO

??注意: 修改內容一定會導致屬性時間被修改,但不一定會導致訪問時間被修改,因為可以不打開文件,對文件進行操作

二、動靜態庫

認識庫

常見的庫文件:stdio.h stdlib.h string.h等

庫分為 動態庫 和 靜態庫

  • Linux 中,.a 后綴為靜態庫,.so 后綴為動態庫
  • Windows 中,.lib 后綴為靜態庫,.dll 后綴為動態庫
  • 雖然不同環境下的后綴有所不同,但其工作原理是一致的

庫命名

  • 比如 libstdc++.so.6
  • 去掉前綴跟后綴,最終庫名為 stdc++

??查找當前環境的庫文件:

find /usr/lib64/libc*

在這里插入圖片描述

??C++ 中具體庫文件可以這樣查看:

find /usr/lib64/libstdc*

在這里插入圖片描述
??在編寫程序時,一定離不開庫文件,動態庫優勢比靜態庫明顯,因此在編譯代碼時,默認采用動態鏈接的方式,如果想指定為靜態鏈接編譯,只需要在 gcc/g++ 語句后面加上 -static 即可(前提是得有靜態庫)

??關于動靜態庫的優缺點可以看看下面這個表格

區別動態庫靜態庫
調用方式通過函數位置進行調用直接將需要的函數拷貝至程序中
依賴性(運行時)需要依賴于動態庫可以獨立于靜態庫運行
空間占用共享動態庫中的代碼,空間占用少拷貝代碼會占用大量空間
加載速度調用函數,加載速度慢直接運行,加載速度快

??注意: 靜態庫是將所需要的函數代碼拷貝到源文件中直接使用,而動態庫是通過動態鏈接的方式,進行函數鏈接使用,別急,這個我們后面會再細細講解

庫的作用

  • 提高開發效率
  • 頭和庫是有對應關系的,需要組合使用
  • 頭文件在預處理階段就已經引入了,鏈接的本質就是在鏈接庫

??簡言之,如果沒有庫文件,那么你在開發時,需要自己手動將 等高頻函數編寫出來,因此庫文件可以提高我們的開發效率,比如 中就有很多現成的庫函數可以使用,效率很高,如:printf

我們在IDE環境下編碼的時候,語法提示是如何做到的?

  1. 安裝開發環境,實際上是在安裝編譯器、開發語言配套的庫和頭文件
  2. 編譯器的 語法提示功能來源于頭文件(語法提示其實就是搜索)

我們在寫代碼時,開發環境是怎么知道語法錯誤或其他錯誤的?

  1. 編譯器有命令行模式,還有其他自動化模式,編寫代碼時,不斷進行主動編譯,排查錯誤

三、制作靜態庫

??現在有一些簡單的計算 函數,能滿足整型的 計算

在這里插入圖片描述
??主函數中將對這些自定義的庫函數進行調用
在這里插入圖片描述

靜態庫的打包

??一共分為兩步:

  1. 將源文件進行 預處理 -> 編譯 -> 匯編,生成可鏈接的二進制 .o 文件
  2. 通過指令將 .o 文件打包為靜態庫

??將文件編譯為 .o 二進制文件

gcc -c add.c sub.c

??將所有的 .o 文件打包為一個靜態庫(庫名自定義),其中的 為庫名mycalc

ar -rc libmycalc.a *.o

ar -tv 靜態庫文件
該指令可以查看打包的庫文件
在這里插入圖片描述

??獲得靜態庫后,就可以進行使用了

靜態庫的使用

方法一:通過指定路徑使用靜態庫

??如果直接編譯程序,會出現編譯失敗的情況,因為編譯器不認識第三方庫(需要提供第三方庫的路徑及庫名)

在這里插入圖片描述

第一方庫:語言提供
第二方庫:操作系統提供
第三方庫:other 提供的庫,比如當前我們直接打包的靜態庫

對于自己寫的的第三庫的使用,需要標注三個參數:

  • -I 所需頭文件的路徑 需要將所需頭文件的路徑加上,此處為 ./stdc/include
  • -L 所需庫文件的路徑 這里加的是庫文件的路徑,也為 ./stdc/lib
  • -l 待鏈接靜態庫名 所需要鏈接的靜態庫名字,這里為 libmycalc.a

將選項加上后重新編譯
在這里插入圖片描述
在這里插入圖片描述

方塊二:將頭文件和靜態庫文件安裝至系統目錄中

??除了這種比較麻煩的指定路徑編譯外,我們還可以將頭文件與靜態庫文件直接安裝在系統目錄中,直接使用,無需指定路徑(需要指定靜態庫名)

??所謂的安裝軟件,就是將自己的文件安裝到系統目錄下

sudo cp ./stdc/include/*.h /usr/include/
sudo cp ./stdc/lib/*.a /lib64/

在這里插入圖片描述

??注意: 將自己寫的文件安裝到系統目錄下是一件危險的事(導致系統環境被污染),用完后記得手動刪除

在這里插入圖片描述

四、制作動態庫

動態區的打包

??動態庫不同于靜態庫,動態庫中的函數代碼不需要加載到源文件中,而是通過 與位置無關碼 ,對指定函數進行鏈接使用

動態庫的打包也同樣分為兩步:

  1. 編譯源文件,生成二進制可鏈接文件,此時需要加上 -fPIC 與位置無關碼
  2. 通過 gcc/g++ 直接目標程序(此時不需要使用 ar 歸檔工具)

??將源文件編譯為 .o 二進制文件,此時需要帶上 fPIC 與位置無關碼
在這里插入圖片描述
??將所有的 .o 文件打包為動態庫(借助 gcc/g++)

gcc -o libmycalc.so *.o -shared

??獲得動態庫后,就可以進行使用了
在這里插入圖片描述

動態庫的鏈接與使用

??像使用靜態庫一樣使用動態庫(指定路徑及庫名),編譯成功,但運行失敗!

??為什么會出現這種問題? 因為當前只告訴了編譯器動態庫的位置,沒有告訴 OS

通過 查看程序鏈接情況:ldd
在這里插入圖片描述
運行時, 是如何鏈接動態庫?OS

  1. 環境變量 LD_LIBRARY_PATH (默認沒有這個環境變量),將第三方動態庫路徑添加至此環境變量中(臨時方案)
  2. sudo 在 /lib64/ 目錄下建立動態庫的軟鏈接
  3. 更改配置文件 /etc/ld.so.conf.d 這個目錄中都是各種動態庫配置文件,創建文件 xx.conf 至目錄中(文件中存儲的是第三方動態庫的路徑)ldconfig 令配置文件生效

方法一:通過環境變量解決

??添加動態庫路徑至 環境變量中LD_LIBRARY_PATH

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:路徑

??環境變量 是程序在進行動態庫查找時的默認搜索路徑LD_LIBRARY_PATH

注意: 更改環境變量只是臨時方案,重新登錄后會失效

方法二:將動態庫的軟鏈接文件存入系統目錄中

sudo ln -s 路徑 /lib64/libmycalc.so

??注意: 創建軟連接文件時,需要使用絕對路徑!

方法三:更改配置文件中的信息

echo 路徑 > lhq.conf
sudo mv lhq.conf /etc/ld.so.conf.d/
sudo ldconfig # 手動更新

??注意: 后兩種方法都可以做到永久生效(因為存入了系統目錄中),但在使用完后最好刪除,避免污染系統環境

動態庫的鏈接原理

??程序在鏈接動態庫函數時,是通過 動態庫起始地址 + 所鏈接函數偏移量 的方式進行鏈接訪問的,而這個偏移量就是 fPIC 與位置無關碼

??地址其實就兩種:絕對地址和相對地址,靜態鏈接時,將可鏈接的二進制文件加載至程序中,直接通過 絕對地址 進行鏈接,假設函數被調用了多次,就會導致代碼冗余等問題; 動態鏈接采用 相對地址 的方式進行鏈接,同一個函數的 + 值相同,代碼只需要加載一份,并且可以任意位置進行函數調用(與位置無關)動態庫起始地址所鏈接函數偏移量

在這里插入圖片描述

??動態庫中所有地址都是偏移量,默認從 開始0

??只有當一個庫被真正映射進地址空間后,它的起始地址才能真正確定

  • 鏈接庫中的函數時,通過 動態庫的起始地址 + 函數偏移量 的方式鏈接函數
  • 這種方法不論在什么位置,都可以隨便鏈接函數(與位置無關)
  • 與位置無關碼:動態庫中地址,是偏移量

總結

最后還有需要總結的一些要點就是:

  1. 當同時擁有 靜態庫 和 動態庫 時,默認采用動態鏈接
  2. 可以在編譯的時候最后加上 -static 指定 靜態鏈接
  3. 只有靜態庫,又不指定靜態鏈接,這個時候是動態鏈接(內含靜態庫)
  4. 靜態鏈接生成的程序比動態鏈接大得多,并且內含靜態庫的動態鏈接程序,也比純粹的動態鏈接程序大,程序并非非靜即動

??另外,你可不可以利用 Makefile 來簡化步驟?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/78391.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78391.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/78391.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【鴻蒙HarmonyOS】深入理解router與Navigation

5. 路由 1.頁面路由(router模式) 1.概述 頁面路由指的是在應用程序中實現不同頁面之間的跳轉,以及數據傳遞。 我們先明確自定義組件和頁面的關系: 自定義組件:Component 裝飾的UI單元,頁面:即應用的UI…

Apache SeaTunnel:新一代開源、高性能數據集成工具

Apache SeaTunnel 是一款開源、分布式、高性能的數據集成工具,可以通過配置快速搭建數據管道,支持實時海量數據同步。 Apache SeaTunnel 專注于數據集成和數據同步,主要旨在解決數據集成領域的常見問題: 數據源多樣性&#xff1a…

CF-Hero:自動繞過CDN找真實ip地址

CF-Hero:自動繞過CDN找真實ip地址 CF-Hero 是一個全面的偵察工具,用于發現受 Cloudflare 保護的 Web 應用程序的真實 IP 地址。它通過各種方法執行多源情報收集。目前僅支持Cloudflare的cdn服務查找真實ip,但從原理上來說查找方法都是通用的…

React-組件和props

1、類組件 import React from react; class ClassApp extends React.Component {constructor(props) {super(props);this.state{};}render() {return (<div><h1>這是一個類組件</h1><p>接收父組件傳過來的值&#xff1a;{this.props.name}</p>&…

談談接口和抽象類有什么區別?

接口&#xff08;interface&#xff09;和抽象類&#xff08;abstract class&#xff09;都是 Java 中常用的“抽象”工具&#xff0c;用來定義類的規范和結構&#xff0c;但它們有一些本質的區別。下面我用一個簡單明了的表格 說明來幫你理解&#xff1a; 對比點抽象類&…

使用Nacos 打造微服務配置中心

一、背景介紹 Nacos 作為服務注冊中心的使用方式&#xff0c;同時 Nacos 還可以作為服務配置中心&#xff0c;用于集中式維護各個業務微服務的配置資源。 作為服務配置中心的交互流程圖如下。 這樣設計的目的&#xff0c;有一個明顯的好處就是&#xff1a;有利于對各個微服務…

OpenCv高階(十一)——物體跟蹤

文章目錄 前言一、OpenCV 中的物體跟蹤算法1、均值漂移&#xff08;Mean Shift&#xff09;&#xff1a;2、CamShift&#xff1a;3、KCF&#xff08;Kernelized Correlation Filters&#xff09;&#xff1a;4、MIL&#xff08;Multiple Instance Learning&#xff09;&#xf…

聲音分離人聲和配樂base,vocals,drums -從頭設計數字生命第6課, demucs——仙盟創夢IDE

demucs -n htdemucs --two-stemsvocals 未來之窗.mp3 demucs -n htdemucs --shifts5 之.mp3demucs -n htdemucs --shifts5 -o wlzcoutspl 未來之窗.mp3 伴奏提取人聲分離技術具有多方面的重大意義&#xff0c;主要體現在以下幾個領域&#xff1a; 音樂創作與制作 創作便利…

使用若依二次開發商城系統-4:商品屬性

功能3&#xff1a;商品分類 功能2&#xff1a;商品品牌 功能1&#xff1a;搭建若依運行環境前言 商品屬性功能類似若依自帶的字典管理&#xff0c;分兩步&#xff0c;先設置屬性名&#xff0c;再設置對應的屬性值。 一.操作步驟 1&#xff09;數據庫表product_property和pro…

操作指南:vLLM 部署開源大語言模型(LLM)

vLLM 是一個專為高效部署大語言模型&#xff08;LLM&#xff09;設計的開源推理框架&#xff0c;其核心優勢在于顯存優化、高吞吐量及云原生支持。 vLLM 部署開源大模型的詳細步驟及優化策略&#xff1a; 一、環境準備與安裝 安裝 vLLM 基礎安裝&#xff1a;通過 pip 直接安裝…

32.768kHz晶振詳解:作用、特性及與其他晶振的區別

一、32.768kHz晶振的核心作用 實時時鐘&#xff08;RTC&#xff09;驅動&#xff1a; 提供精確的1Hz時鐘信號&#xff0c;用于計時功能&#xff08;如電子表、計算機CMOS時鐘&#xff09;。 分頻公式&#xff1a; 1Hz 32.768kHz / 2^15&#xff08;通過15級二分頻實現&#x…

第3講、大模型如何理解和表示單詞:詞嵌入向量原理詳解

1. 引言 大型語言模型&#xff08;Large Language Models&#xff0c;簡稱LLM&#xff09;如GPT-4、Claude和LLaMA等近年來取得了突破性進展&#xff0c;能夠生成流暢自然的文本、回答復雜問題、甚至編寫代碼。但這些模型究竟是如何理解人類語言的&#xff1f;它們如何表示和處…

【Java面試筆記:進階】19.Java并發包提供了哪些并發工具類?

Java 并發包(java.util.concurrent)提供了一系列強大的工具類,用于簡化多線程編程、提升并發性能并確保線程安全。 1. Java 并發包的核心內容 并發包概述:java.util.concurrent 包及其子包提供了豐富的并發工具類,用于簡化多線程編程。主要組成部分: 高級同步結構:如 C…

Matlab數字信號處理——小波閾值法去噪分析系統

&#x1f527; 系統簡介 本系統通過 MATLAB GUI 圖形界面&#xff0c;集成了 小波閾值去噪算法 的各個核心模塊&#xff0c;可以實現以下功能&#xff1a; 打開語音文件&#xff1a;支持常見音頻格式讀取&#xff1b; 模擬加噪&#xff1a;系統內置白噪聲模擬功能&#xff0…

EDI 如何與 ERP,CRM,WMS等系統集成

在數字化浪潮下&#xff0c;與制造供應鏈相關產業正加速向智能化供應鏈轉型。傳統人工處理訂單、庫存和物流的方式已難以滿足下單客戶對響應速度和數據準確性的嚴苛要求。EDI技術作為企業間數據交換的核心樞紐&#xff0c;其與ERP、CRM、WMS等業務系統的深度集成&#xff0c;成…

計算機組成原理-408考點-數的表示

常見題型&#xff1a;C語言中的有符號數和無符號數的表示。 【例】有如下C語言程序段: short si-32767&#xff1b;unsigned short usisi&#xff1b;執行上述兩條語句后&#xff0c;usi的值為___。short和unsigned short均使用16位二進制數表示。 【分析】考點&#xff1a;同…

企業級AI開發利器:Spring AI框架深度解析與實戰

企業級AI開發利器&#xff1a;Spring AI框架深度解析與實戰 一、前言&#xff1a;Java生態的AI新紀元 在人工智能技術爆發式發展的今天&#xff0c;Java開發者面臨著一個新的挑戰&#xff1a;如何將大語言模型&#xff08;LLMs&#xff09;和生成式AI&#xff08;GenAI&#…

【金倉數據庫征文】——選擇金倉,選擇勝利

目錄 第一部分&#xff1a;金倉數據庫——開創數據庫技術的新時代 1.1 金倉數據庫的技術底蘊 1.2 高可用架構與災備能力 1.3 分布式架構與彈性擴展能力 第二部分&#xff1a;金倉數據庫助力行業數字化轉型 2.1 電信行業&#xff1a;核心系統國產化替代 2.2 醫療行業&…

用C語言實現——一個中綴表達式的計算器。支持用戶輸入和動畫演示過程。

一、思路概要和知識回顧 1.思路概要 ①中綴表達式計算&#xff1a; 需要處理運算符的優先級&#xff0c;可能需要用到棧結構。 ??如何將中綴表達式轉換為后綴表達式&#xff1f;或者直接計算&#xff1f; 通常&#xff0c;中綴轉后綴&#xff08;逆波蘭式&#xff09;再…

Langchain_Agent+數據庫

本處使用Agent數據庫&#xff0c;可以直接執行SQL語句。可以多次循環查詢問題 前文通過chain去聯系數據庫并進行操作&#xff1b; 通過鏈的不斷內嵌組合&#xff0c;生成SQL在執行SQL再返回。 初始化 import os from operator import itemgetterimport bs4 from langchain.ch…