欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Linux下動靜態(tài)庫的打包與使用指南(C/C++)

 更新時間:2023年02月06日 14:40:17   作者:謎一樣的男人1  
c++是面向?qū)ο蟮木幊陶Z言,比較方便實現(xiàn)某些第三方庫,比如翻譯其他面向?qū)ο笳Z言的代碼,比c語言要方便的多,下面這篇文章主要給大家介紹了關(guān)于Linux下C/C++動靜態(tài)庫的打包與使用的相關(guān)資料,需要的朋友可以參考下

前言

為什么用動靜態(tài)庫

我們在實際開發(fā)中,經(jīng)常要使用別人已經(jīng)實現(xiàn)好的功能,這是為了開發(fā)效率和魯棒性(健壯性);因為那些功能都是頂尖的工程師已經(jīng)寫好的,并且已經(jīng)踐行多年的代碼。

那么如何使用他人開發(fā)的功能呢?

1.庫: 包括靜態(tài)庫與動態(tài)庫。

2.開源代碼。

3.基本的網(wǎng)絡(luò)功能調(diào)用,比如各種網(wǎng)絡(luò)接口、語音識別等等。

這其中,我們將詳細(xì)介紹靜態(tài)庫和動態(tài)庫:

為什么在實際工作中一般將源碼打包成動態(tài)靜態(tài)庫來給不同的人使用

  1. 知識就是財富,你只是給某些人用一下你寫的業(yè)務(wù)功能,并不想暴露源碼的邏輯,那就打包成.obj目標(biāo)文件甩給他用;
  2. 你也可以自己給自己封裝庫,因為你自己編譯生成了.obj目標(biāo)文件,是已經(jīng)編譯完成了的,只需要把這個庫對應(yīng)的頭文件引入新的程序中,.obj文件放入庫路徑,這樣新的程序鏈接器就可以直接把功能鏈接起來,方便部署使用,省去了反復(fù)編譯的麻煩

動態(tài)鏈接與靜態(tài)鏈接

一般情況下,為了更好的支持開發(fā),第三方庫或者是語言庫都必須提供靜態(tài)庫和動態(tài)庫(eg:C C++等官方庫),這是方便程序員根據(jù)需求功能進(jìn)行可執(zhí)行文件的生成;

動態(tài)鏈接使用動態(tài)庫,而靜態(tài)鏈接使用靜態(tài)庫。

一般來說,我們gcc編譯默認(rèn)是動態(tài)鏈接的而如果加上-static選項,那么生成的可執(zhí)行文件將為靜態(tài)生成;

底層優(yōu)缺點

動態(tài)鏈接文件信息:

靜態(tài)鏈接文件信息:

可以明顯發(fā)現(xiàn)動態(tài)鏈接的文件大小明顯要比靜態(tài)鏈接的文件大小要小多了

這是因為動態(tài)鏈接是當(dāng)程序執(zhí)行到調(diào)用接口時編譯器再去特定路徑查找目標(biāo)接口的可執(zhí)行文件,直接進(jìn)行計算;

靜態(tài)鏈接比較暴力,鏈接時候直接將目標(biāo)接口的二進(jìn)制代碼全部鏈接到原文件中去,這也就是靜態(tài)鏈接生成的文件這么大的原因了;(畢竟把二進(jìn)制代碼copy過來了)

但是這些都是相對的,有優(yōu)點就有缺點:

萬一動態(tài)庫路徑中的庫丟失損壞 ,動態(tài)鏈接的程序到目標(biāo)位置了,過來用的時候肯定出錯了;

靜態(tài)鏈接因為編譯的時候吧二進(jìn)制代碼考過去了,不依賴原生庫,即便原庫代碼丟失也沒事;

小結(jié)

Linux下的動靜態(tài)庫

linux下庫的命名格式一般為:

靜態(tài)庫: lib+庫的名字+.a eg:c標(biāo)準(zhǔn)庫為 libc.a

動態(tài)庫: lib+庫的名字+.so

靜態(tài)庫是指程序在編譯鏈接的時候把庫的二進(jìn)制可執(zhí)行代碼鏈接到可執(zhí)行文件中。程序運(yùn)行的時候?qū)⒉辉傩枰o態(tài)庫。

而動態(tài)庫則是指程序在運(yùn)行的時候才去啟動指定位置的動態(tài)庫的代碼,使其加載到內(nèi)存共享區(qū)中,多個程序共享使用庫的二進(jìn)制代碼, 不用拉到本文件中來。

  • 一個與動態(tài)庫鏈接的可執(zhí)行文件僅僅包含它用到的函數(shù)入口地址的一個表(頭文件),而不是外部函數(shù)所在目標(biāo)文件(.o)的整個機(jī)器碼
  • 在可執(zhí)行文件開始運(yùn)行以前,外部函數(shù)的機(jī)器碼由操作系統(tǒng)從磁盤上的該動態(tài)庫中復(fù)制到內(nèi)存中,這個過程稱為動態(tài)鏈接(dynamic linking),也就是說,動態(tài)鏈接是在需要調(diào)用接口時才會去將所用接口的二進(jìn)制代碼拷貝到內(nèi)存中。
  • 當(dāng)一個庫多文件使用時,動態(tài)庫只有一份,所以可以在多個程序間共享,所以動態(tài)鏈接使得可執(zhí)行文件更小,節(jié)省了磁盤空間。–>操作系統(tǒng)采用虛擬內(nèi)存機(jī)制允許物理內(nèi)存中的一份動態(tài)庫被要用到該庫的所有進(jìn)程共用,節(jié)省了內(nèi)存和磁盤空間。
  • 這里需要提一下的是,我們之前所提過的進(jìn)程地址空間中有一個共享區(qū),而一般動態(tài)庫的代碼就映射在共享區(qū),所有進(jìn)程都共享著動態(tài)庫的代碼。

動靜態(tài)庫的對比

動態(tài)庫被加載在內(nèi)存中,可以供多個使用庫的程序共享映射到自己的虛擬地址空間使用,因此可以減少頁面交換以及降低內(nèi)存中代碼冗余,并且因為與源程序模塊分離,因此開發(fā)模式比較好。

而加載動態(tài)庫的程序運(yùn)行速度相對較慢,因為動態(tài)庫運(yùn)行時加載,映射到虛擬地址空間后需要重新根據(jù)映射起始地址計算函數(shù)/變量地址。

靜態(tài)庫直接把二進(jìn)制代碼鏈接過來,與動態(tài)庫的使用恰好相反,其運(yùn)行速度相對較快,但消耗資源較多。

打包靜態(tài)庫

庫函數(shù)源文件:

//file1: Add.c
#include<stdio.h>

int Add(int a,int b)
{
    return a+b;
}

//file2: Sub.c
#include<stdio.h>
int Sub(int a,int b)
{
    return a-b;
}

生成靜態(tài)庫需要先生成目標(biāo)文件(.o)再進(jìn)行打包,故先編寫相應(yīng)的源文件再將其編譯成目標(biāo)文件:

//生成兩個二進(jìn)制目標(biāo)文件
[root@VM-8-15-centos fighting]# gcc -c Sub.c -o Sub.o 
[root@VM-8-15-centos fighting]# gcc -c Add.c -o Add.o

此時的add.o和sub.o文件是已經(jīng)編譯好但還沒有鏈接的兩個文件;

此時再用 ar命令,歸檔工具將其打包成靜態(tài)庫

//將這倆二進(jìn)制目標(biāo)文件打包成靜態(tài)庫
[lyl@VM-4-3-centos 2022-3-14]$ ar -rc libmycal.a Add.o Sub.o //`rc`表示(replace and create)

查看靜態(tài)庫

 //查看靜態(tài)庫的目錄列表
[root@VM-8-15-centos fighting]#  ar -tv libmycal.a `tv`表示(列出靜態(tài)庫中文件 and verbose詳細(xì)信息)
rw-r--r-- 0/0    936 Jan 24 16:57 2023 Add.o
rw-r--r-- 0/0   1240 Jan 24 16:57 2023 Sub.o

使用靜態(tài)庫

將庫的頭文件和靜態(tài)庫都放到指定lib目錄下:

調(diào)用我們的庫接口代碼:

#include <stdio.h>
#include "add.h"
#include "sub.h"

int main()
{
  	int a = 10;
  	int b = 20;
  	printf("a+b:%d\n", Add(a, b));
  	printf("a-b:%d\n", Sub(a, b));
 	return 0;
}

編譯:

發(fā)現(xiàn)報錯: 這是因為gcc編譯時去鏈接庫和頭文件,是去默認(rèn)路徑以及當(dāng)前源文件路徑下尋找;

//gcc 尋找的默認(rèn)頭文件路徑:不建議污染原生庫
/usr/include
//gcc 尋找的默認(rèn)庫文件路徑:   
/lib , lib64 ......等

而我們將靜態(tài)庫打包到lib目錄下,gcc編譯時就找不到我們的庫了,因此我們編譯的時候,需要指定一些選項,并且?guī)下窂?/lib;

因此,正確鏈接的指令為:

gcc -o test test.c -I ./lib -L ./lib  -lmycal -static
  • -I(大寫i) + 指定路徑:告知gcc除了默認(rèn)路徑之外,還要去尋找這個指定路徑的頭文件。
  • -L + 指定路徑:除默認(rèn)庫路徑以外,需要尋找這個指定路徑的
  • -l(小寫L)+ 庫名稱:表示要具體鏈接的是哪一個庫;(因為路徑下庫可能不止一個)
  • -static 選擇使用靜態(tài)庫的靜態(tài)鏈接

由此,我們就靜態(tài)鏈接生成了一個可執(zhí)行文件test,運(yùn)行test程序結(jié)果如下:

此時我們刪除靜態(tài)庫,發(fā)現(xiàn)照樣可以運(yùn)行,因為靜態(tài)庫中Add和Sub的二進(jìn)制代碼已經(jīng)被鏈接入test程序中了,不怕原生庫沒了!

可見,有時候編譯選項多而雜,難記,特別是文件一多,寫的很麻煩,介紹一個camke構(gòu)建項目的工具,C/C++開發(fā)人員必會技能;文章鏈接

打包動態(tài)庫

類似與打包靜態(tài)庫使用的ar歸檔工具,動態(tài)庫也有自己的語法,我們將生成動態(tài)庫的依賴關(guān)系及方法寫進(jìn)自動化構(gòu)建工具(Makefile)中::

顯然手動寫Makefile和上面手動打包靜態(tài)庫一樣,麻煩很多,我的評價是,直接cmake起飛;

注意:

  • 由于動態(tài)庫在內(nèi)存中是可加載的,它可能在內(nèi)存中的任意位置,也可能被映射到進(jìn)程地址空間的每個區(qū)域,所以為了保證庫當(dāng)中的代碼執(zhí)行不會出錯,也就是要保證庫中的代碼是與位置無關(guān)的,因此生成.o文件時需要帶上-fPIC選項表示生成與位置無關(guān)碼。
  • 這里由于在依賴關(guān)系中已經(jīng)點明了要生成的目標(biāo)文件,故不帶上$@也可以
  • 打包動態(tài)庫不是像靜態(tài)庫一樣先gcc -o再使用ar(歸檔工具);
  • 而是用gcc 帶上-shared選項表示生成共享動態(tài)庫格式,這也體現(xiàn)了動態(tài)庫代碼映射在共享區(qū)的特點

編寫好Makefile之后 make指令構(gòu)建動態(tài)庫 libmycal.so:

使用動態(tài)庫

和靜態(tài)庫一樣,我們把頭文件和.so庫文件放入lib目錄,gcc的時候帶上選項;

 gcc -o test test.c -I ./lib -L ./lib -l mycal //因為是動態(tài)鏈接 所以不用帶-static了

然后編譯過了,運(yùn)行程序時發(fā)現(xiàn)有問題,打不開動態(tài)庫?:

既然編譯都聲稱可執(zhí)行程序了,此時的可執(zhí)行程序是沒問題的,因此已經(jīng)與編譯過程無關(guān)了;

那么這屬于運(yùn)行問題,其實運(yùn)行時系統(tǒng)也會去默認(rèn)路徑下找到我們所使用的動態(tài)庫但在默認(rèn)路徑下沒有我們的庫。

這里解決方法有多種,但我傾向于推薦下面這一種:

修改環(huán)境變量LD_LIBRARY_PATH,將動態(tài)庫所在路徑.lib添加到該環(huán)境變量中,這樣程序在運(yùn)行時系統(tǒng)就能夠找到動態(tài)庫,從而運(yùn)行成功。

當(dāng)然,還可以拷貝我們的.so文件到系統(tǒng)共享庫路徑下, 一般指/usr/lib;

但是這可能會污染系統(tǒng)原生的庫,一般不推薦這樣做。

還有一種方法,在我們的系統(tǒng)下有**/etc/ld.so.conf.d/**這個路徑:

我們可以在這個路徑下制造自己的.conf,然后再將自己的庫路徑寫進(jìn)這個conf中;

但是還是有點污染了原生庫,不建議;

小結(jié)

linux打包使用靜態(tài)庫:

接口的.c源文件–>.o目標(biāo)二進(jìn)制文件–>ar rc(歸檔工具)進(jìn)行打包成.a靜態(tài)庫,編譯程序使用時帶上-static;(注意帶上頭文件尋找路徑選項)

linux打包使用動態(tài)庫:

接口的.c源文件–>.o目標(biāo)二進(jìn)制文件(需帶上-fPIC 與位置無關(guān))–>-shard 打包動態(tài)庫;(注意帶上頭文件尋找路徑選項)+(注意添加動態(tài)庫尋找路徑)

win下打包動靜態(tài)庫

比如通過VS2019打包,由于是可視化界面方便操作,不再贅述,參考下方文章;

參考文章

總結(jié)

到此這篇關(guān)于Linux下動靜態(tài)庫的打包與使用指南(C/C++)的文章就介紹到這了,更多相關(guān)Linux動靜態(tài)庫打包使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Qt實現(xiàn)俄羅斯方塊

    Qt實現(xiàn)俄羅斯方塊

    這篇文章主要為大家詳細(xì)介紹了Qt實現(xiàn)俄羅斯方塊,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • KMP 算法實例詳解

    KMP 算法實例詳解

    這篇文章主要介紹了KMP 算法實例詳解的相關(guān)資料,MP的關(guān)鍵是求出next的值、先預(yù)處理出next的值,需要的朋友可以參考下
    2017-07-07
  • C語言利用EasyX實現(xiàn)繪制足球圖案

    C語言利用EasyX實現(xiàn)繪制足球圖案

    這篇文章主要為大家詳細(xì)介紹了C語言如何利用EasyX繪圖庫實現(xiàn)繪制一個簡單的足球圖案,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2022-11-11
  • CFileDialog的鉤子函數(shù)解決對話框的多選之DoModal問題

    CFileDialog的鉤子函數(shù)解決對話框的多選之DoModal問題

    前幾天領(lǐng)導(dǎo)問我一個問題:就是使用CFileDialog類在設(shè)置多選時選中的文件所放的文件緩沖區(qū)不知設(shè)置多大合適,本文將詳細(xì)介紹,需要的朋友可以參考下
    2012-12-12
  • C++超詳細(xì)講解單鏈表的實現(xiàn)

    C++超詳細(xì)講解單鏈表的實現(xiàn)

    單鏈表是后面要學(xué)的雙鏈表以及循環(huán)鏈表的基礎(chǔ),要想繼續(xù)深入了解數(shù)據(jù)結(jié)構(gòu)以及C++,我們就要奠定好這塊基石!接下來就和我一起學(xué)習(xí)吧
    2022-03-03
  • 深入uCOS中全局變量的使用詳解

    深入uCOS中全局變量的使用詳解

    本篇文章是對uCOS中全局變量的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++實現(xiàn)圖書管理程序

    C++實現(xiàn)圖書管理程序

    這篇文章主要為大家詳細(xì)介紹了C++實現(xiàn)圖書管理程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • stl常用算法(Algorithms)介紹(stl排序算法、非變序型隊列)

    stl常用算法(Algorithms)介紹(stl排序算法、非變序型隊列)

    這篇文章主要介紹了stl常用算法(Algorithms)介紹(stl排序算法、非變序型隊列),需要的朋友可以參考下
    2014-05-05
  • 用C實現(xiàn)添加和讀取配置文件函數(shù)

    用C實現(xiàn)添加和讀取配置文件函數(shù)

    本篇文章是對用C語言實現(xiàn)添加和讀取配置文件函數(shù)的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • c語言stack(棧)和heap(堆)的使用詳解

    c語言stack(棧)和heap(堆)的使用詳解

    這篇文章主要介紹了c語言stack(棧)和heap(堆)的使用詳解,需要的朋友可以參考下
    2014-04-04

最新評論