你不知道的庫:庫的種類,作用和加載方式

你不知道的庫:庫的種類,作用和加載方式

📟作者主頁:慢熱的陜西人

🌴專欄鏈接:Linux

📣歡迎各位大佬👍點贊🔥關注🚓收藏,🍉留言

本博客主要內容講解了庫的概念和為什么要有庫,以及靜態庫和動態庫,最后還有最重要的庫的加載的理解以及動態庫的三種配置方法

文章目錄

  • 你不知道的庫:庫的種類,作用和加載方式
    • 1.了解一下庫
    • 2.為什么要有庫
    • 3.寫一寫----從庫的書寫者的角度
      • 3.1庫的命名規則:
    • 4.用一用----站在使用者的角度去使用我們寫的庫
      • 4.1靜態庫
      • 4.2動態庫
    • 5.動態庫配置問題
      • 5.1環境變量
      • 5.2軟鏈接方案
      • 5.3配置文件方案
    • 6.動態庫加載過程的理解
      • 6.1 動態庫加載問題和周邊問題:
      • 6.2庫中地址的理解

1.了解一下庫

雖然我們目前沒有使用過第三方庫,但是我們一直在使用一些C/C++內部的標準庫,那么我們來在目錄中查看一下這些庫:

包括我們甚至可以找到我們經常使用的stdio.h標準庫,并且可以使用vim編輯器進行查看的!

image-20231121142639688

所以我們可以理解到:

①系統已經預裝了C/C++的頭文件和庫文件,頭文件提供方法說明,庫提供方法實現,頭和庫是有對應關系的,是要組合在一起使用的。

②頭文件是在預處理階段就引入的,鏈接的本質其實就是鏈接庫!

另外我們也可以理解一些現象了:

① 所以我們在vs2019,2022下安裝開發環境—安裝編譯器軟件,其實就是安裝要開發的語言配套的庫和頭文件

②我們在使用編譯器的時候,都會有語法的自動提醒功能,需要先包含頭文件。**語法提醒本質:**編譯器或者編輯器,它會自動的將用戶輸入的內容,不斷的在被包含的頭文件中進行搜索,自動提醒功能依賴于頭文件的。

③我們在寫代碼的時候,我們的環境怎么知道我們的代碼中有那些地有語法報錯,那些地方定義變量有問題?不要太小看編譯器,編譯器有命令行模式,也就是我們在Linux中使用gcc命令那樣,也有其他的自動化模式幫我們不斷在進行語法檢查。

2.為什么要有庫

庫可以幫助我們提高開發效率,我們學習的時候提倡去造輪子,幫我們深入理解庫的原理和實現方法。

到開發中,我們更提倡用輪子!

當然我們也可以選擇將以提供源代碼的方式,來提高開發效率,但是這對我們未來是由一些其他問題的比如我們不想讓使用者看到我們的代碼,比如我們的公司向另一個公司提供軟件服務,我們只需要將打包好的庫給他們使用即可,而不會把源碼直接給他們!

3.寫一寫----從庫的書寫者的角度

庫分為靜態庫(.a)動態庫(.so)

另外一般云服務器,默認只會存在動態庫,不會存在靜態庫,靜態庫需要獨自安裝!

3.1庫的命名規則:

例如:libstdc++.so.6

去掉前面的lib和后面的第一個.后面包括.的內容結惡果就是庫的名稱了!

所以例子的這個庫的名稱使stdc++;

4.用一用----站在使用者的角度去使用我們寫的庫

4.1靜態庫

我們先簡單實現一個加減函數的庫:

我們先寫四個文件:

//myadd.c  
#include"myadd.h"int myadd(int a, int b)
{return a + b;
}
//myadd.h
#pragma once
#include<stdio.h>int myadd(int a, int b);
//mysub.c
#include"mysub.h"
int mysub(int a, int b)
{return a - b;
}
//  mysub.h
#pragma once#include<stdio.h>int mysub(int a, int b);

首先我們之前的做法就是在寫一個主函數的文件將他們一塊編譯:

但是這是我們只有這么兩個源文件的時候看起來還可以,但是當我們的項目非常龐大的時候,并且我們需要分享給別人使用我們的庫的時候,就非常的不方便了!

image-20231121165901487

我們將.c源文件都讓其生成.o文件,也就是未鏈接前的文件:

利用ar命令生成靜態庫:ar -rc libmymath.a myadd.o mysub.o

image-20231121174308280

當我們把libmymath.a文件挪動到我們的ortherperson目錄下的時,我們嘗試編譯的時候:

發現提示我們找不到頭文件

image-20231121174153962

所以我們這樣的方式是不對的!

我們先在ortherperson下創建兩個文件夾libinclude分別存放生成的靜態庫和對應的頭文件;

正確的是這樣:gcc -o mytest main.c -I./include -L./lib -lmymath

我們來解釋一下:

  • -I:其中I表示的inlcude的意思,也就是頭文件的意思后面直接跟上我們頭文件的路徑
  • -L:其中L表示的Lib的意思,就是我們的庫的意思,后面直接跟上我們靜態庫的路徑
  • -l:這個參數后面緊跟我們的靜態庫的名字,就是我們前面命名規則說的那樣,去掉前面的lib.后面的內容就是我們的靜態庫的名字!

image-20231121174529404

那么我們接下來嘗試一下把我們的庫放到語言庫中直接去調嘗試一下:

[root@lavm-5wklnbmaja ortherperson]# cp lib/libmymath.a /lib64
[root@lavm-5wklnbmaja ortherperson]# cp include/*.h /usr/include

嘗試去編譯:

我們發現編譯成功,并且運行成功!

image-20231121180401518

所以我們這里就可以引入第三方庫的使用:

①首先我們需要指定的頭文件和庫文件

②如果沒有默認安裝到系統gcc,g++默認的搜索路徑下,用戶必須指明對應的選項,告知編譯器:

? a.頭文件在哪;

? b.庫文件在哪;

? c.庫文件具體是誰

③將我們下載下來的庫和頭文件,拷貝到系統默認路徑下---- 在Linux下安裝庫!!那么卸載呢?對任何軟件而言,安裝和卸載的本質就是拷貝到系統特定的路徑。

④如果我們安裝的庫是第三方的(語言,操作系統系統接口) 庫,我們要正常使用,即便是已經全部安裝到了系統中,gcc/g++必須要用-l指明具體庫的名稱!

理解現象:

? 無論我們是從網絡中未來直接下載好的庫,或者是源代碼(編譯方法) — make install 安裝的命令 --cp,安裝到系統中,我們安裝大部分指令,庫等等都是需要sudo的或者超級用戶操作!

4.2動態庫

我們刪除掉之前的只留下最開始的源文件和頭文件:

我們重新生成.o文件:

[mi@lavm-5wklnbmaja mylib]$ gcc -c -fPIC -o myadd.o myadd.c
[mi@lavm-5wklnbmaja mylib]$ gcc -c -fPIC -o mysub.o mysub.c

其中:fPIC:產生位置無關碼(position independent code)

image-20231121185348586

再生成動態庫:

gcc -shared -o libmymath.so myadd.o mysub.o

image-20231121185748618

接下來我們嘗試鏈接動態庫:

gcc -o main main.c -Iinclude -Llib -lmymath

鏈接成功了,但是我們運行的時候卻報錯了,報錯說無法找到我們的動態庫文件!但是我們的鏈接卻通過了。原因是我們確實把動態庫的位置告訴了編譯器,但是卻沒告訴操作系統!

image-20231121190107295

那么這里為什么沒有成功呢?這里其實就是靜態庫和動態庫的區別了,對于靜態庫將用戶使用的二進制代碼直接拷貝到可執行目標文件的程序中。但是我們的靜態庫不會。

5.動態庫配置問題

運行時,OS是如何查找我們的動態庫的?三種方法

5.1環境變量

動態庫需要再一個環境變量LD_LIBRARY_PATH 中去尋找我們的動態庫!(告訴操作系統動態庫的位置)。

我們只需要把我們當前的動態庫的路徑添加到這個環境變量中即可:

image-20231121192516738

我們ldd查看一下鏈接的情況并且運行一下:

image-20231121192541623

當然這種方案我們不是很推崇是一種臨時方案,原因是我們知道環境變量我們如果沒有再配置文件修改的話,我們每次重新登錄或者重啟bash都會導致環境變量的初始化。

5.2軟鏈接方案

sudo ln -s /learn/lesson11/ortherperson/lib/libmymath.so /lib64/libmymath.so

這個時候ldd我們再去查看的時候:

image-20231121193409826

并且我們這時候再去運行發現是沒有任何問題的:

image-20231121193534934

并且對于軟鏈接來說它不是臨時的,就算我們重啟bash也不會影響,因為他是真正寫入到磁盤內部的,而不是在內存中!

5.3配置文件方案

首先我們查看一下系統的默認配置文件:

[mi@lavm-5wklnbmaja lesson11]$ ls /etc/ld.so.conf.d/
kernel-3.10.0-957.el7.x86_64.conf  mariadb-x86_64.conf

我們在這個目錄下添加以一個我們的配置文件:xupt_lib.conf

//創建配置文件
[mi@lavm-5wklnbmaja lesson11]$ sudo touch /etc/ld.so.conf.d/xupt_lib.conf
//像配置文件中寫入我們的動態庫所在的絕對路徑
[mi@lavm-5wklnbmaja lib]$ sudo vim /etc/ld.so.conf.d/xupt_lib.conf

我們ldd查看一下:

image-20231122150326397

發現似乎還是沒有鏈接上,其實我們還少一步生效配置文件:

[mi@lavm-5wklnbmaja ortherperson]$ sudo ldconfig

運行一下看看:

image-20231122150654301

嘗試運行:

image-20231122150722572

6.動態庫加載過程的理解

靜態鏈接形成的可執行程序中本身就有靜態庫中對應的方法實現!

首先我們的靜態庫存儲在硬盤中,當多個可執行文件都要使用到這個庫的時候,他就會加載到每個可執行程序內部。會讓每個可執行程序的變大。其次因為它加載到了可執行程序內部,所以我們在外部刪除這個靜態庫的時候我們的程序依然可以正常運行。所以主流會多使用動態庫多一些:


6.1 動態庫加載問題和周邊問題:

鏈接:將可執行程序內部的外部符號,替換稱為庫中的具體地址。

只要我們把庫加載到內存,映射到進程的地址空間中之后,我們的代碼執行庫中的方法,就依舊還是在自己的地址空間內進行函數跳轉即可!

并且為什么動態庫節省資源,原因是當多個進程都要使用到同一個動態庫的時候,這個動態庫只需要在內存加載一份,每個進程只需要在自己的進程地址空間中進行映射即可!因為我們曾經在鏈接動態庫的時候程序內部已經存儲了相關數據和函數的地址信息!

image-20231122154713731

有時候我們的庫很大,我們的程序并不會用到其中所有的接口,所以我們的操作系統也沒必要把庫中所有的信息都加載到內存中。

6.2庫中地址的理解

動態庫必定面臨一個問題:

不同的進程,運行的程度不同,需要使用的第三方庫是不同的,注定了每一個共享空間中空閑位置是不確定的

在程序翻譯鏈接,形成可執行程序的時候,程序內部有沒有地址?

答案是有的:動態庫中的地址,決定不能確定,所以不能使用絕對地址!動態庫中的所有地址,都是偏移量(相對地址),默認從0開始。

當一個庫,真正的被映射進地址空間的時候,它的起始地址才會被真正的確定!當我們映射的時候是將進程地址空間的內部的代碼區包含庫的相對地址+我們的動態庫的初始地址,一塊存儲到進程地址空間對應的共享代碼空間的位置!并且這個地址一旦被確定是不變的!所以我們經過這種方式就可以去訪問動態庫中的方法了!

所以動態庫在我們的進程地址空間中隨意加載,與我們在地址空間中加載的位置毫無關系!

所以這時候我們也可以理解之前,鏈接動態庫的時候我們生成的匯編文件的時候帶了一個參數-fPIC,被稱作與位置無關碼:也就是對應我們這里的相對地址,偏移量!

接下來我們驗證一下:

我們重新生成一個非無關碼的匯編文件:用于生成對應的靜態庫文件。

[mi@lavm-5wklnbmaja mylib]$ gcc -o myadd_static.o -c myadd.c
[mi@lavm-5wklnbmaja mylib]$ gcc -o mysub_static.o -c mysub.c
//生成對應的靜態庫
[mi@lavm-5wklnbmaja mylib]$ ar -rc libmymath.a myadd_static.o mysub_static.o 

將兩個庫拷貝到我們的ortherperson/lib目錄下:

image-20231122171305250

接下來我們有一個問題,當靜態庫和動態庫同時存在的情況下,我們的可執行文件會優先使用哪個呢?答案肯定是動態庫

我們試驗一下:重新編譯文件并運行

image-20231122171700679

我們ldd查看一下可執行程序的鏈接情況:很顯然是我們的動態庫!

image-20231122171733025

那如果我們呢執意要靜態鏈接呢?只需要再加一個參數-static

[mi@lavm-5wklnbmaja ortherperson]$ gcc -o mytest-s main.c -I./include -L./lib -lmymath -static

當我們嘗試編譯的時候報錯了:這是因為我們沒有安裝對應的庫:sudo yum install -y glibc-static

image-20231122183954762

我們分別在三種情況下編譯:
①動態庫和靜態庫都存在的情況生成:mytest-d

②動態庫和靜態庫都存在的情況下加-static參數生成:mytest-s

③刪除動態庫只留下靜態庫再生成:mytest-u

ldd查看三個文件:

image-20231122184419491

所以我們可以得出結論:

①動態庫和靜態庫同時存在,系統默認使用動態庫

②編譯器,在鏈接的時候,如果庫提供了動和靜,優先動,沒有動,才使用靜!

到這本篇博客的內容就到此結束了。
如果覺得本篇博客內容對你有所幫助的話,可以點贊,收藏,順便關注一下!
如果文章內容有錯誤,歡迎在評論區指正

在這里插入圖片描述

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

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

相關文章

組件化——組件的實現原理

渲染器主要負責將虛擬 DOM 渲染為真實 DOM&#xff0c;我們只需要使用虛擬 DOM 來描述最終呈現的內容即可。但當我們編寫比較復雜的頁面時&#xff0c;用來描述頁面結構的虛擬 DOM 的代碼量會變得越來越多&#xff0c;或者說頁面模板會變得越來越大。這時&#xff0c;我們就需要…

iperf3 網絡測試

iperf3 測試網絡的上下行帶寬 下載地址 https://iperf.fr/iperf-download.php 開啟服務器 開啟客戶端 常用命令 -c 代表客戶端-s 代表服務端-u 代表 udp-r 代表數據方向是否反向 https://baijiahao.baidu.com/s?id1731514357681464971&wfrspider&forpc

C++學習 --queue

目錄 1&#xff0c; 什么是queue 2&#xff0c; 創建queue 2-1&#xff0c; 標準數據類型 2-2&#xff0c; 自定義數據類型 2-3&#xff0c; 其他創建方式 3&#xff0c; 操作stack 3-1&#xff0c; 賦值 3-2&#xff0c; 插入元素(push) 3-3&#xff0c; 查詢元素 3…

Python簡直是萬能的,這5大主要用途你一定要知道!

從2015開始國內就開始慢慢接觸Python了&#xff0c;從16年開始Python就已經在國內的熱度更高了&#xff0c;目前也可以算的上"全民Python"了。 眾所周知小學生的教材里面已經有Python了&#xff0c;國家二級計算機證也需要學習Python了&#xff01; 因為Python簡單…

編程語言發展史:布爾代數和機器語言

布爾代數是一種數學理論&#xff0c;用于描述和分析邏輯和布爾值的關系。它是由英國數學家George Boole在19世紀中期發明的&#xff0c;被認為是現代計算機科學的基礎之一。布爾代數的發明使得邏輯運算可以被表示為代數運算&#xff0c;從而為計算機科學的發展奠定了基礎。 在…

PTA 7-4 數列求和-加強版

7-4 數列求和-加強版 分數 20 全屏瀏覽題目 作者 DS課程組 單位 浙江大學 給定某數字A&#xff08;1≤A≤9&#xff09;以及非負整數N&#xff08;0≤N≤100000&#xff09;&#xff0c;求數列之和SAAAAAA?AA?A&#xff08;N個A&#xff09;。例如A1, N3時&#xff0c;S1…

Unity、UE和Godot的優劣對比

先占位。。。。。。 首先說Unity和UE這兩家公司&#xff0c;是行業的兩座燈塔&#xff0c;對整個游戲引擎的這個行業的發展具有這種指導性的這種作作用。這兩個引擎我從2016年開始就一直在用&#xff0c;結合一下業內的共識&#xff0c;一般來說認為呢&#xff0c;Unity更擅長移…

2023全球邊緣計算大會深圳站-核心PPT資料下載

一、峰會簡介 邊緣計算&#xff0c;是指在靠近物或數據源頭的一側&#xff0c;采用網絡、計算、存儲、應用核心能力為一體的開放平臺&#xff0c;就近提供最近端服務。其應用程序在邊緣側發起&#xff0c;產生更快的網絡服務響應&#xff0c;滿足行業在實時業務、應用智能、安…

LeetCode算法題解(動態規劃,背包問題)|LeetCode416. 分割等和子集

LeetCode416. 分割等和子集 題目鏈接&#xff1a;416. 分割等和子集 題目描述&#xff1a; 給你一個 只包含正整數 的 非空 數組 nums 。請你判斷是否可以將這個數組分割成兩個子集&#xff0c;使得兩個子集的元素和相等。 示例 1&#xff1a; 輸入&#xff1a;nums [1,5,…

Linux中的進程程序替換

Linux中的進程程序替換 1. 替換原理2. 替換函數3. 函數解釋4. 命名理解程序替換的意義 1. 替換原理 替換原理 用fork創建子進程后執行的是和父進程相同的程序(但有可能執行不同的代碼分支),子進程往往要調用一種exec函數以執行另一個程序。當進程調用一種exec函數時,該進程的…

[Docker]九.Docker compose講解

docker-compose 是 docker 官方的一個開源項目&#xff0c;可以實現對 docker 容器集群的快速編排, docker-compose 通過一個 配置文件 來管理多個 Docker 容器,在配置文件中&#xff0c;所有的容器通過 services 來定義&#xff0c;然后使用 docker-compose腳本 來 啟動&am…

Nuxt.js Next.js Nest.js

Nuxt.js和Next.js都是服務端渲染框架(SSR)&#xff0c;屬于前端框架,Nest.js則是node框架,屬于后端框架。 其中Nuxt.js是vue的ssr框架&#xff0c;Next.js是react的ssr框架。 都是比vue和react更上層的前端框架。 文章目錄 1.SSR2.Nuxt2.1 Nuxt的下載2.2 Nuxt的集成2.3 Nuxt…

HuggingFace-利用BERT預訓練模型實現中文情感分類(下游任務)

準備數據集 使用編碼工具 首先需要加載編碼工具&#xff0c;編碼工具可以將抽象的文字轉成數字&#xff0c;便于神經網絡后續的處理&#xff0c;其代碼如下&#xff1a; # 定義數據集 from transformers import BertTokenizer, BertModel, AdamW # 加載tokenizer token Ber…

cobol基本動詞

cobol基本動詞 基本動詞用于過程部中的數據處理。每個語句總是以cobol動詞開頭。 input&#xff08;輸入&#xff09;/output&#xff08;輸出&#xff09; 輸入輸出動詞用于從用戶獲取數據。并顯示cobol程序的輸出。 accept 用于從操作系統或者用戶獲取數據&#xff0c;例如日…

langchain 部署組件-LangServe

原文&#xff1a;&#x1f99c;?&#x1f3d3; LangServe | &#x1f99c;?&#x1f517; Langchain LangServe &#x1f6a9; We will be releasing a hosted version of LangServe for one-click deployments of LangChain applications. Sign up here to get on the wa…

OpenLayers入門,OpenLayers6的WebGLPointsLayer圖層樣式和運算符詳解,四種symbolType類型案例

專欄目錄: OpenLayers入門教程匯總目錄 前言 本章講解使用OpenLayers6的WebGL圖層顯示大量點情況下,列舉出所有WebGLPointsLayer圖層所支持的所有樣式運算符大全。 補充說明 本篇主要介紹OpenLayers6.x版本的webgl圖層,OpenLayers7.x和OpenLayers8.x主要更新內容就是webgl…

GB28181學習(十七)——基于jrtplib實現tcp被動和主動發流

前言 GB/T28181-2022實時流的傳輸方式介紹&#xff1a;https://blog.csdn.net/www_dong/article/details/134255185 基于jrtplib實現tcp被動和主動收流介紹&#xff1a;https://blog.csdn.net/www_dong/article/details/134451387 本文主要介紹下級平臺或設備發流功能&#…

生活如果真能像隊列一樣的話

生活如果真能像隊列一樣&#xff0c;那該多好啊。 —————————————————————————————————————————— 背包&#xff0c;隊列 可以先看他們的API&#xff1a;都含有一個無參構造函數&#xff0c;添加單個元素的方法&#xff0c;測試集合…

php項目從寶塔面板切換轉到phpstudy小皮面板

寶塔面板轉phpstudy面板 版本 寶塔面板8.0.1 phpstudy面板8.1.1.3 步驟 1、寶塔面板,找到項目文件夾,打包、下載到本地、解壓 2、本地windows系統安裝phpstudy面板,選擇盡可能一樣的配置 比如寶塔php7.4.33,可能phpstudy面板只有php7.4.3,也行 大環境一定要一致,比如…

力扣算法練習BM46—最小的K個數

題目 給定一個長度為 n 的可能有重復值的數組&#xff0c;找出其中不去重的最小的 k 個數。例如數組元素是4,5,1,6,2,7,3,8這8個數字&#xff0c;則最小的4個數字是1,2,3,4(任意順序皆可)。 數據范圍&#xff1a;0≤k,n≤10000&#xff0c;數組中每個數的大小0≤val≤1000 要…