Linux(七) 動靜態庫

目錄

一、動靜態庫的概念

二、靜態庫的打包與使用

2.1 靜態庫的打包

2.2 靜態庫的使用

三、動態庫的打包與使用

3.1 動態庫的打包

3.2 動態庫的使用

3.3 運行動態庫的四種方法

四、總makefile


一、動靜態庫的概念

靜態庫: Linux下,以.a為后綴的文件。程序在編譯鏈接的時候把庫的代碼鏈接到可執行文件中。程序運行的時候將不再需要靜態庫。本質是在編譯時把靜態庫中的代碼(不是一次性加載,而是分頁加載)復制到了進程的的代碼區中。
動態庫: Linux下,以.so為后綴的文件。程序在運行的時候才去鏈接動態庫的代碼,在可執行程序裝載或運行時,由操作系統的裝載程序加載庫,多個程序共享使用庫的代碼。一個與動態庫鏈接的可執行文件僅僅包含它用到的函數入口地址的一個表,而不是外部函數所在目標文件的整個機器碼。
靜態鏈接:?將庫中的相關代碼復制進可執行程序中的過程。
動態鏈接:?在可執行文件開始運行以前,外部函數的機器碼由操作系統從磁盤上的該動態庫中復制到內存中。
鏈接的本質: 使.o文件可以找到要調用的函數的位置
庫文件名稱:?比如libc.so,去掉前綴lib和后綴.so,剩下的就是庫名。libhello.a的庫名就是hello。

頭文件gcc的默認搜索路徑是 /usr/include
庫文件的默認搜索路徑是 /usr/lib64

把文件拷貝到系統的默認路徑下就叫做庫的安裝,拷貝之后就不用 -I 和 -L了


實例演示:?分別使用靜態鏈接和動態鏈接編譯生成兩個可執行程序,比較兩個程序的大小
使用gcc靜態鏈接編譯時,命令要帶上**-static** 選項,如下:

gcc -o test test.c -static

?

可以看到的是,使用靜態庫靜態鏈接成的可執行程序比動態鏈接生成的可執行程序要大很多。
我們還可以通過file命令查看文件的鏈接屬性:
?還可以通過ldd?命令查看可執行程序的依賴庫,動態鏈接生成的可執行程序才有依賴庫,靜態鏈接升序的可執行程序不依賴任何庫文件,因為庫文件的代碼已經復制進可執行程序了。

因為這里是動態鏈接,不僅要讓編譯器動態庫的路徑,還要讓操作系統知道,所以這里我們需要導入一個環境變量LD_LIBRARY_PATH,如下:

export LD_LIBRARY_PATH=/home/dgz/linux/lesson26/lib/uselib/output/lib

執行完之后

總結動靜態庫的優缺點
靜態庫

  • 優點: 程序運行的時候將不再需要靜態庫,在可執行程序中已經具備了所有執行程序所需要的任何東西,在執行的時候運行速度快。
  • 缺點:一是浪費空間,因為每個可執行程序中對所有需要的目標文件都要有一份副本,所以如果多個程序對同一個目標文件都有依賴,如多個程序中都調用了printf()函數,則這多個程序中都含有printf.o,所以同一個目標文件都在內存存在多個副本;另一方面就是更新比較困難,因為每當庫函數的代碼修改了,這個時候就需要重新進行編譯鏈接形成可執行程序。

動態庫

  • 優點: 動態鏈接使得可執行文件更小,節省了磁盤空間。操作系統采用虛擬內存機制允許物理內存中的一份動態庫被要用到該庫的所有進程共用,節省了內存和磁盤空間.動態鏈接的優點顯而易見,就是即使需要每個程序都依賴同一個庫,但是該庫不會像靜態鏈接那樣在內存中存在多分,副本,而是這多個程序在執行時共享同一份副本;另一個優點是,更新也比較方便,更新時只需要替換原來的目標文件,而無需將所有的程序再重新鏈接一遍。當程序下一次運行時,新版本的目標文件會被自動加載到內存并且鏈接起來,程序就完成了升級的目標
  • 缺點: 程序運行的時候依賴動態庫,? 據估算,動態鏈接和靜態鏈接相比,性能損失大約在5%以下。經過實踐證明,這點性能損失用來換區程序在空間上的節省和程序構建和升級時的靈活性是值得的。

二、靜態庫的打包與使用

2.1 靜態庫的打包

靜態庫打包:?本質其實就是將代碼編譯成.o的二進制文件,然后進行打包。
為了更好地演示這個過程,我創建了mymath.cmymath.hmyprint.cmyprint.h四個文件,內容分別如下:
mymath.c
?

#include "mymath.h"
int Add_(int a,int b)
{return a+b;
}


mymath.h
?

#pragma once
#include <stdio.h>extern int Add_(int a,int b);


myprint.c
?

#include "myprint.h"
void printf_(const char* str)
{printf("hello %s [%d]\n",str,(int)time(NULL));
}


myprint.h

#pragma once 
#include <stdio.h>
#include <time.h>extern void printf_(const char* str);

如下:?

打包靜態庫的步驟

  1. 先將myadd.cmysub.c?變成生成對應的二進制文件
  2. 使用ar?歸檔工具對兩個二進制文件進行打包,同時帶上選項**-rc**(r和c分別代表replace和creat),這里的庫名是hello。
    ?

    ar -rc libhello.a *.o

  3. 上面這兩個步驟其實就把靜態庫打包好了,下面我們還有做一個工作就是發布靜態庫,簡單地說,就是把頭文件和靜態庫組織起來,頭文件放在include?下,如下:

  4. 這樣一個庫文件就可以給別人使用了。
    上面的所有步驟我們可以寫進Makefile里,利用make指令一鍵打包和make output發布,如下:

    libhello.a:myprint.o mymath.oar -rc libhello.a myprint.o mymath.o
    mymath.o:mymath.cgcc -c mymath.c -o mymath.o
    myprint.o:myprint.cgcc -c myprint.c -o myprint.o.PHONY:output
    output:mkdir -p output/lib mkdir -p output/includecp -rf *.h output/includecp -rf *.a output/lib
    .PHONY:clean
    clean:rm -rf *.o *.a output

2.2 靜態庫的使用

先把靜態庫放到一個測試目錄下:

然后編寫一段代碼:
?

#include "myprint.h"
#include "mymath.h"int main()
{int ret = Add_(1,2); printf("%d\n",ret);printf_("dgz");return 0;
}

編寫Makefile:
使用gcc編譯時,采用靜態鏈接編譯,所以要帶上選項**-static**,此外,因為我們使用了別人給的靜態庫,所以我們還有告訴編譯器庫文件所在路徑,頭文件所在路徑以及庫名,所以要用到以下三個選項:

  • -L: 指明庫文件所在路徑
  • -I: 指明頭文件所在路徑
  • -l: 指明庫文件名稱,這里庫名就是hello(去掉前綴lib和后綴.a)

這里我們可以使用絕對路徑,使用下面的shell命令獲取當前所在路徑:
?

path=$(shell pwd)

Makefile編寫后如下:

path=$(shell pwd)mytest:test.c#-l 指定庫目錄名稱 -L 庫目錄路徑 -I 指定頭文件路徑gcc -o $@ $^ -I $(path)/output/include -L $(path)/output/lib -l hello -static 
.PHONY:clean
clean:rm -f mytest

?

使用file指令查看鏈接屬性:

三、動態庫的打包與使用

3.1 動態庫的打包

我們同樣還是使用上面的那四個文件進行演示。
步驟:

  1. 先將mymath.cmyprint.c?變成生成對應的二進制文件。注意這里生成的二進制文件要帶上選項**-fPIC**,產生路徑無關碼,也就是這里使用相對地址,是動態確定的,不存在絕對地址
    gcc -c -fPIC mymath.c -o mymath_d.o
    gcc -c -fPIC myprint.c -o myprint_d.o
  2. 使用gcc帶上選項**-shared** (生成共享的庫格式)對二進制文件進行打包
    	gcc -shared myprint_d.o mymath_d.o -o libhello.so
  3. 最后一步就是對動態庫進行發布,也就是將庫文件和頭文件進行組織打包
  4. 編寫Makefile:
    libhello.so:myprint_d.o mymath_d.ogcc -shared myprint_d.o mymath_d.o -o libhello.so
    mymath_d.o:mymath.cgcc -c -fPIC mymath.c -o mymath_d.o
    myprint_d.o:myprint.cgcc -c -fPIC myprint.c -o myprint_d.o.PHONY:output
    output:mkdir -p output/lib mkdir -p output/includecp -rf *.h output/includecp -rf *.so output/lib 
    .PHONY:clean
    clean:rm -rf *.o *.so output
    

3.2 動態庫的使用

先把動態庫放到測試目錄下:

然后編寫Makefile,和靜態庫的使用類似:
?

path=$(shell pwd)mytest_d:test.c#-l 指定庫目錄名稱 -L 庫目錄路徑 -I 指定頭文件路徑gcc -o $@ $^ -I $(path)/output/include -L $(path)/output/lib -l hello 
.PHONY:clean
clean:rm -f mytest_d

?編譯程序:?如果此時直接對程序進行編譯,不會報錯,但是執行的時候會報錯,無法打開共享庫里面的文件

?因為這里是動態鏈接,不僅要讓編譯器動態庫的路徑,還要讓操作系統知道,所以這里我們需要導入一個環境變量LD_LIBRARY_PATH,如下(上面已經說過,這里重復一次)

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/dgz/linux/lesson26/lib/uselib/output/lib

?此時再執行程序就不會報錯了:

使用file指令查看程序的鏈接屬性:

使用ldd指令查看程序依賴的庫:?

3.3 運行動態庫的四種方法

  1. 將對應到.so和.h文件拷貝到/usr/lib64和/usr/include
  2. 系統在在搜索頭文件時會先在系統默認路徑下搜索(上面兩個路徑),如果沒找到,但是環境變量LD_LIBRARY_PATH設置了,也會在該環境變量下搜索,這種方法是內存級的,退出就沒有了。
  3. 修改配置文件,配置/etc/ld.so.conf.d/
    路徑下原有的文件

    我們想要配置它只需要在該路徑下創建一個.conf文件

    然后將我們要配置的路徑寫進該文件

    最后執行一下
    ldconfig
  4. 建立軟連接
    ?建立成功,然后就可以找到了。

四、總makefile

.PHONY:all
all:libhello.so libhello.alibhello.so:myprint_d.o mymath_d.ogcc -shared myprint_d.o mymath_d.o -o libhello.so
mymath_d.o:mymath.cgcc -c -fPIC mymath.c -o mymath_d.o
myprint_d.o:myprint.cgcc -c -fPIC myprint.c -o myprint_d.olibhello.a:myprint.o mymath.oar -rc libhello.a myprint.o mymath.o
mymath.o:mymath.cgcc -c mymath.c -o mymath.o
myprint.o:myprint.cgcc -c myprint.c -o myprint.o
# 發布
.PHONY:output
output:mkdir -p output/lib mkdir -p output/includecp -rf *.h output/includecp -rf *.a output/libcp -rf *.so output/lib 
.PHONY:clean
clean:rm -rf *.o *.a *.so output

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

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

相關文章

Python專題:十五、JSON數據格式

Python的數據處理&#xff1a;JOSN 計算機的主要工作&#xff1a;處理數據 最容易處理的數據就是結構化數據 非結構化數據&#xff1a;視頻&#xff0c;文件等 近些年的大數據、數據挖掘就是對互聯網中的各種非結構化的數據的分析和處理 半結構化數據 明確的結構屬性&…

陪診服務運用預約小程序的效果是什么

在中高型城市里&#xff0c;陪診師近些年也很有熱度&#xff0c;已經衍生成為一個新的小眾行業&#xff0c;不同醫院/不同科目等其它情況針對不同群體往往很難完善&#xff0c;比如部分老年人腿腳不便、不認識字、外地語言難以溝通等&#xff0c;陪診師的作用就尤為凸顯. 對相…

[Bootloader][uboot]code總結

文章目錄 1、U_BOOT_DRIVER2、DM框架dm_scan_platdatadm_extended_scan_fdt 1、U_BOOT_DRIVER 使用這個宏可以定義一個驅動實例&#xff0c;宏定義是 其中使用的struct driver結構體 使用的ll_entry_declare宏定義是 歸結為 2、DM框架 1、 DM框架 DM模型抽象出了以下四個…

16.投影矩陣,最小二乘

文章目錄 1. 投影矩陣1.1 投影矩陣P1.2 投影向量 1. 投影矩陣 1.1 投影矩陣P 根據上節知識&#xff0c;我們知道當我們在解 A X b AXb AXb的時候&#xff0c;發現當向量b不在矩陣A的列空間的時候&#xff0c;我們希望的是通過投影&#xff0c;將向量b投影到矩陣A的列空間中&…

ModuleNotFoundError: No module named ‘sklearn‘

ModuleNotFoundError: No module named sklearn 解決辦法&#xff1a; pip install scikit-learn

7B2 PRO主題5.4.2免授權直接安裝

B2 PRO 5.4.2 最新免授權版不再需要改hosts&#xff0c;直接在wordpress上傳安裝即可

網站接入百度云防護CDN后回源率非常高原因

最近&#xff0c;有站長反饋網站接入百度云防護后&#xff0c;網站回源率非常高。 今天百度云來給大家講解下&#xff0c;CDN回源高的原因&#xff1a; 1.動態請求比較多 網站的動態請求很多&#xff0c;一般是回源率高的主要原因&#xff0c;因為CDN對待動態請求是每個請求…

Vue的學習 —— <網絡請求庫Axios>

目錄 前言 正文 一、Axios基本概念 二、安裝Axios 三、Axios使用方法 四、向服務器發送請求 前言 在之前的開發案例中&#xff0c;我們通常直接在組件中定義數據。但在實際的項目開發中&#xff0c;我們需要從服務器獲取數據。當其他用戶希望訪問我們自己編寫的網頁時&a…

定檔 11.2-3,COSCon'24 第九屆中國開源年會暨開源社十周年嘉年華正式啟動!

中國開源年會 COSCon 是業界最具影響力的開源盛會之一&#xff0c;由開源社在2015年首次發起&#xff0c;今年將舉辦第九屆。 以其獨特定位及日益增加的影響力&#xff0c;COSCon 吸引了越來越多的國內外企業、高校、開源組織/社區的大力支持。與一般企業、IT 媒體、行業協會舉…

網絡安全快速入門(十三)linux及vmware軟件的網絡配置

13.1 前言 在通過我們前面的了解&#xff0c;我們現在已經對Linux的基礎知識有了大致的了解&#xff0c;今天我們來大概講一下關于linux系統及vmware的網絡配置問題&#xff0c;在這之前&#xff0c;我們需要對網絡有一個大概的認識和了解&#xff0c;話不多說&#xff0c;我們…

01記-“計算機基礎知識”

感覺媒體: 直接作用于人的感覺器官&#xff0c;使人產生直接感覺的媒體&#xff1a;聲音、圖形、圖像、動畫等。 表示媒體: 為了加工、處理和傳輸感覺媒體而人為研究、構造出來的一種媒體&#xff0c;常見的有各種編碼方式&#xff0c;如文本編碼、圖像編碼和聲音編碼等。 …

Java中靜態方法為什么不能調用非靜態成員?

在Java面試中&#xff0c;這個問題經常被問到&#xff0c;因為它不僅涉及到Java的基本語法規則&#xff0c;還深入到了JVM的工作機制。理解這個問題可以幫助面試者更好地掌握Java的靜態和非靜態成員的區別以及它們在內存中的分配和使用。 靜態成員 vs 非靜態成員 首先&#x…

AtCoder Beginner Contest 318 A題 Full Moon

A題&#xff1a;Full Moon 標簽&#xff1a;模擬、數學題意&#xff1a;給定一個起始 m m m和上限 n n n&#xff0c;每次增量 p p p&#xff0c;求能加幾次。題解&#xff1a;數據比較小&#xff0c;可以直接暴力&#xff1b;數學方法算的話&#xff0c;注意邊界。代碼&#…

HNU-算法設計與分析-作業5

第五次作業【回溯算法】 文章目錄 第五次作業【回溯算法】<1> 算法分析題5-3 回溯法重寫0-1背包<2> 算法分析題5-5 旅行商問題&#xff08;剪枝&#xff09;<3> 算法實現題5-2 最小長度電路板排列問題<4> 算法實現題5-7 n色方柱問題<5> 算法實現…

時間格式數據向前或向后歸于整時

假設你有一個“時:分:秒”的時間格式數據&#xff0c;例如"12:34:56"&#xff0c;你想要將它向前歸整于整時或者向后歸整于整時&#xff0c;可以按照以下方法進行處理&#xff1a; 1、向前歸整于整時&#xff1a;將分鐘和秒數設置為0 import datetime# 原始時間 ti…

公共字段填充(AOP的使用)

Thread是線程池,ThreadLocal是線程變量,每個線程變量是封閉的,與其它線程變量分隔開來,在sky-common下的com.sky.context包下有一個Basecontext類 public class BaseContext {//每一個上下文創建了一個線程變量,用來存儲long類型的id//創建三個方法,用來設置,取用,刪除idpubli…

絕地求生:PGS3參賽隊伍跳點一覽,17壓力有點大,4AM與PeRo大概率不roll點

在PCL春季賽結束后&#xff0c;PGS3的參賽隊伍名單以及分組就正式確定了&#xff0c;最后確定名額的DDT和NH被安排在了A組和B組&#xff0c;感覺這次PGS3的分組比較均衡&#xff0c;沒有“死亡之組”一說。這段時間已經有網友匯總了PGS3隊伍在各個地圖的跳點&#xff0c;并且把…

「AIGC算法」近鄰算法原理詳解

本文主要介紹近鄰算法原理及實踐demo。 一、原理 K近鄰算法&#xff08;K-Nearest Neighbors&#xff0c;簡稱KNN&#xff09;是一種基于距離的分類算法&#xff0c;其核心思想是距離越近的樣本點&#xff0c;其類別越有可能相似。以下是KNN算法的原理詳解&#xff1a; 1. 算…

python安裝ESPHome

1. powershell輸入python 或者 python3 可以查看python版本&#xff0c;沒安裝則會自動跳出微軟商店&#xff0c;安裝即可(注意這里會自動安裝在C盤默認路徑) 2. pip3 install esphome -i https://mirrors.aliyun.com/pypi/simple 3. 根據報錯信息找到esphome的安裝目錄&…

python腳本編輯oss文件

1、安裝oss2庫 rootubuntu:~# pip3 install oss2 Collecting oss2Downloading oss2-2.18.5.tar.gz (283 kB)|████████████████████████████████| 283 kB 6.9 MB/s Collecting aliyun-python-sdk-core>2.13.12Downloading aliyun-python-s…