1. 程式人生 > >C/C++ 靜態連結庫(.a) 與 動態連結庫(.so)

C/C++ 靜態連結庫(.a) 與 動態連結庫(.so)

平時我們寫程式都必須 include 很多標頭檔案,因為可以避免重複造輪子,軟體大廈可不是單靠一個人就能完成的。但是你是否知道引用的那些標頭檔案中的函式是怎麼被執行的呢?這就要牽扯到連結庫了!

庫有兩種,一種是 靜態連結庫,一種是 動態連結庫,不管是哪一種庫,要使用它們,都要在程式中包含相應的 include 標頭檔案。我們先來回顧一下程式編譯的過程。如下圖:

我們結合gcc指令來看一下每個階段生成的檔案:

gcc -c helloWorld.c 

生成一個helloWorld.o檔案,該檔案是將原始檔編譯成的彙編檔案,在連結之前,該檔案不是可執行檔案。而

gcc -o helloWorld helloWorld.c

生成的是一個helloWorld的執行檔案,格式為ELF(與windows不一樣)。該檔案為連結後的可執行檔案。

1、靜態連結庫

什麼是靜態連結呢?即在連結階段,將原始檔中用到的庫函式與彙編生成的目標檔案.o合併生成可執行檔案。該可執行檔案可能會比較大。這種連結方式的好處是:方便程式移植,因為可執行程式與庫函式再無關係,放在如何環境當中都可以執行。

缺點是:檔案太大,一個全靜態方式生成的簡單print檔案都有857K。而動態連結生成的一樣的可執行檔案卻只要8.4K。

檔案內容很簡單,就是一個printf("hello world!\n");

因為包含庫檔案stdio,所以靜態編譯出的檔案很大。如果你想嘗試的話,可以這樣編譯:

gcc -static -o print print.c

在linux中,靜態庫為lib*.a,動態庫為lib*.so。

下面我們來寫一個庫檔案,然後生成一個靜態庫,然後嘗試著呼叫一下它。一個簡單的add函式,標頭檔案為

標頭檔案對於的原始檔:

下面我們來生成靜態庫:

輸入:g++ -c add.cpp 生成.o目標檔案

然後用ar命令進一步生成庫libadd.a:

ar -crv libadd.a  add.o

這樣就生成了一個靜態連結庫libadd.a。

下面我們來寫一個測試檔案:

#include <iostream>
#include "./addlib/add.h"
using namespace std;

int main()
{
    int number1 = 10;
    int number2 = 90;
    cout << "the result is " << add(number1, number2) << endl;
    return 0;
}

因為我的目錄結構是add.cpp, addlib(資料夾),在addlib中是標頭檔案和靜態庫,所以include用相對路徑找到標頭檔案add.h。

下面我們編譯一下該檔案:

g++ -o test test.cpp -L./addlib -ladd 

-L是指定載入庫檔案的路徑

-l是指定載入的庫檔案。

執行一下:

可見呼叫成功。

2、動態連結庫

我們知道靜態連結的話,檔案會很大,往往實現很小的一個功能就需要佔用很大的空間,而且每次庫檔案升級的話,都要重新編譯原始檔,很不方便。具體下面如下:

對於靜態編譯的程式1和程式2,都應用庫staticMath。在記憶體中就又兩份相同的staticMath目標檔案,很浪費空間,一旦程式數量過多就很可能會記憶體不足。

這麼大的記憶體才只能執行這幾個程式,實在不甘心。

這樣就又了動態庫發揮威力的地方了。我們來看看動態連結的結果:

我們看到在這種模型中,兩個程式只應用一個庫,這個目標檔案在記憶體中只有一份,供所有程式使用。

並且在程式執行過程中動態呼叫庫檔案,很方便,又不佔空間,但是動態連結有一個缺點就是可移植性太差,如果兩臺電腦執行環境不同,動態庫存放的位置不一樣,很可能導致程式執行失敗。

在具體的應用中,靜態與動態應當合理選擇!!!

下面我們來生成一個動態庫,輸入:

g++ -fPIC -shared -o libadd.so add.cpp

這樣就生成了一個libadd.so的動態庫。

下面我們用動態連結的方式編譯test.cpp,輸入:

g++ -o test test.cpp -L./addlib -ladd

該命令和剛剛靜態連結一樣。注意-l後面接的是lib與so中間的庫名稱。

我們執行一下:

發現不行,因為執行程式找不到libadd.so。

可以看到test執行程式用到的 libadd.so 沒有找到。。。

原因是在 /etc/ld.so.conf 檔案中設定了動態連結庫了尋找路徑。

可以看到有很多路徑設定檔案,在 ld.so.conf.d 中,我們在下面新增一下我們 libadd.so 的路徑。

然後再執行一下 ldconfig 命令。

這下就可以成功執行test檔案了。

注意一下,有人說為什麼我程式中 extern int number;可以直接編譯不需要什麼靜態連結庫,動態連結庫。那是因為你在連結時已經將number變數定義的目標檔案.o和原始檔進行了連結,如:gcc -o main main.o test.o。如果你只是單純的用 main.o 進行連結,是生成不了可執行目標檔案的,如:gcc -o main main.c會報告未定義的number引用。

綜上說述,靜態和動態連結庫的選擇要視情況而定。一般比較推薦動態連結方式,因為可以很好的節約記憶體,而且方便以後的庫檔案升級。

g++(gcc)編譯選項

  • -shared :指定生成動態連結庫。
  • -static :指定生成靜態連結庫。
  • -fPIC :表示編譯為位置獨立的程式碼,用於編譯共享庫。目標檔案需要建立成位置無關碼,念上就是在可執行程式裝載它們的時候,它們可以放在可執行程式的記憶體裡的任何地方。
  • -L. :表示要連線的庫所在的目錄。
  • -l:指定連結時需要的動態庫。編譯器查詢動態連線庫時有隱含的命名規則,即在給出的名字前面加上lib,後面加上.a/.so來確定庫的名稱。
  • -Wall :生成所有警告資訊。
  • -ggdb :此選項將盡可能的生成gdb的可以使用的除錯資訊。
  • -g :編譯器在編譯的時候產生除錯資訊。
  • -c :只啟用預處理、編譯和彙編,也就是把程式做成目標檔案(.o檔案)。
  • -Wl,options :把引數(options)傳遞給連結器ld。如果options中間有逗號,就將options分成多個選項,然後傳遞給連結程式。

參考:

相關推薦

C/C++ 靜態連結(.a) 動態連結(.so)

平時我們寫程式都必須 include 很多標頭檔案,因為可以避免重複造輪子,軟體大廈可不是單靠一個人就能完成的。但是你是否知道引用的那些標頭檔案中的函式是怎麼被執行的呢?這就要牽扯到連結庫了! 庫有兩種,一種是 靜態連結庫,一種是 動態連結庫,不管是哪一種庫,要使用它們,都要在程式中包含相應的 includ

GCC 編譯動態 so檔案時,靜態連結libmysqlclient.a 動態連結引數一起使用問題。

直接放結論, 下面是編譯一個使用了mysql C API 的 mysql.so 檔案(我們的業務中,它是zbx加裁的modules so檔案) gcc -fPIC -shared -o mysql.so mysql.c \ -I/usr/include

Linux C 靜態(.a) 動態(.so) 的詳解

庫從本質上來說是一種可執行程式碼的二進位制格式,可以被載入記憶體中執行。庫分靜態庫和動態庫兩種。 一、靜態庫和動態庫的區別 1、靜態函式庫 這類庫的名字一般是libxxx.a;利用靜態函式庫編譯成的檔案比較大--空間,因為整個函式庫的所有資料都會被整合進目的碼中,他的優點就顯而易見了,即編譯後的執行

C++中靜態初始化陣列動態初始化陣列

靜態初始化的陣列的長度必須是在程式中確定的常數,不能是由使用者輸入的變數例子:int a[10];//正確Student stud[10];//正確:Student是一個學生類int n;cin>>n;int a[n];//錯誤int n;cin>>n

《CMake實踐》筆記三:構建靜態(.a) 動態(.so) 及 如何使用外部共享和標頭檔案

五、靜態庫與動態庫構建 讀者雲,太能羅唆了,一個Hello World就折騰了兩個大節。OK,從本節開始,我們不再折騰Hello World了,我們來折騰Hello World的共享庫。 本節的任務: 1、建立一個靜態庫和動態庫,提供HelloFunc函式供其他程式程式設計使用,Hell

【轉】《CMake實踐》筆記三:構建靜態(.a) 動態(.so) 及 如何使用外部共享和標頭檔案

五、靜態庫與動態庫構建讀者雲,太能羅唆了,一個Hello World就折騰了兩個大節。OK,從本節開始,我們不再折騰Hello World了,我們來折騰Hello World的共享庫。本節的任務:1、建立一個靜態庫和動態庫,提供HelloFunc函式供其他程式程式設計使用,H

Linux動態.a動態.so的生成區別、以及.so檔案的封裝使用

一、前言 如果有公司需要使用你們產品的一部分功能(通過程式碼呼叫這些功能),如果不想提供原始碼,那麼就可以通過封裝成庫檔案的形式提供給對方使用。本文主要介紹了生成動態庫與靜態庫檔案的過程、以及封裝和使用庫檔案的方法。 二、靜態庫.a與動態庫.so的生成與

Linux中,.a和.so,其實就是靜態連結動態連結

詳細查了一下,.a與.so的區別,其實就是靜態連結庫與動態連結庫。有一篇博文,很詳細,附上鍊接:http://blog.csdn.net/nieyinyin/article/details/6890557   Linux下的.so是基於Linux下的動態連結,其功能和作用類

c語言生成靜態.a動態.so

在windows下動態連結庫是以.dll字尾的檔案,二在Linux中,是以.so作字尾的檔案。 動態連結庫的好處就是節省記憶體空間。 1、Linux下建立動態連結庫 在使用GCC編譯程式時,只需加上-shared選項即可,這樣生成的執行程式即為動態連結庫。 例如有檔案:he

GCC編譯過程動態連結靜態連結(未整理)

來源:https://www.cnblogs.com/qingjiaowoxiaoxioashou/p/6410588.html 根據連結時期的不同,庫又有靜態庫和動態庫之分。靜態庫是在連結階段被連結的,所以生成的可執行檔案就不受庫的影響,即使庫被刪除,程式依然可以成功執行。而動態庫是在程式執行的時

C++ 根據作業系統版本呼叫不同的動態連結

在操作資料庫時遇到一個問題:win7 sp1上編譯ADO程式,在win7 sp1以下版本不能執行,(Win7系統下需要的動態檔案與XP系統的需要的動態連結庫不一樣。需要根據系統的版本載入動態連結庫。) Win7 系統下: 需要的動態連結庫 #import "MSADO15.DLL" re

C++中關於class B:AClass B::A問題

include tsa int() pri 示例 pre 派生類 std boost 一,class B:A為類的繼承關系,即A類是B類的基類class <派生類名>:<繼承方式><基類名>{<派生類新定義成員>}; 例如:

關於原始檔,標頭檔案,靜態連結檔案,動態連結檔案的的理解

先從原始檔和標頭檔案的關係說起,由於是還是初學階段,只接觸了C++語言和windows平臺下的程式設計,所以只講這兩方面的東東, 標頭檔案的作用:對函式,變數,和類的宣告,其實在標頭檔案也可對一些特殊函式和變數定義,比如可以在標頭檔案中對行內函數和const型別變數定義,由於對類的宣告

win7下無法定位程式輸入點ucrtbase.abort動態連結api-ms-win-crt-runtime-l1-1-0.dll上解決辦法

前言 由於最近在搭漏洞環境,想在我的win7虛擬機器下配一下wamp環境,出於便利我想使用wampserver這一整合開發環境,但是在安裝過程中遇到了好多問題(各種dll的缺失),dll缺失都是小事,直接下載然後放到相應的目錄下就可以了,但是這個問題我嘗試了很多次才解決,特地記錄下來

c學習筆記--5 結構體實現動態連結串列

這裡不得不多說一句,對於c來說指標我認為最好用的就是連結串列,有很多實用的地方 #include<string.h> #include<stdio.h> //C語言 連結串列篇 //結構體實現單向連結串列 struct MyStruc

原始檔,標頭檔案,靜態連結檔案,動態連結檔案的的理解

如果你把一個.exe檔案只接放到沒有操作系充的“裸機”上去執行,顯然是執行不了的,可是你把這個程式放在一個裝有windows系統的電腦上就能運行了,顯然,程式的執行還是得依靠windows作業系統,這裡就要說到.dll檔案,上面說到的連結這一步時的程式碼複製只講到對程式作者自已寫的檔案和.lib檔案中用到的程

通過gcc建立靜態.a動態.so及其使用

gcc的常用選項 -v:檢視gcc版本 -c:只編譯,生成.o檔案,不進行連結 -g:包含除錯資訊,方便使用gdb除錯 -D:編譯時定義巨集 靜態庫的建立和使用 這裡使用命令ar,常用的選項是: -r:替換歸檔中已有的檔案或加入新檔案 -t:顯示歸檔檔

C++ 單鏈表基本操作分析實現 連結串列   連結串列是一種物理儲存單元上非連續、非順序的儲存結構,資料元素的邏輯順序是通過連結串列中的指標連結次序實現的。連結串列由一系列結點(連結串列中每一個元素稱為結點)組成,結

連結串列   連結串列是一種物理儲存單元上非連續、非順序的儲存結構,資料元素的邏輯順序是通過連結串列中的指標連結次序實現的。連結串列由一系列結點(連結串列中每一個元素稱為結點)組成,結點可以在執行時動態生成。每個結點包括兩個部分:一個是儲存資料元素的資料域,另一個是儲存下一個結點地址的指標域。 相比於線性表

linux下靜態.a動態.so檔案的生成和使用

1.靜態庫是一些目標檔案(字尾名為.o)的集合體而已。 2.靜態庫的字尾名是.a,對應於windows作業系統的字尾名為.lib的靜態庫。 3.可以使用ar命令來建立一個靜態庫檔案。 來看一個例項,根據書中的程式碼簡化的,先看一看可以編譯成庫檔案的原始檔中的程式碼: /* test.c */ i

c++のstatic靜態成員、物件的動態建立和釋放

1、靜態成員變數 (1)核心思想 靜態成員變數的初始化必須在類的外部,也可以通過物件直接進行賦值; 靜態函式的只能使用靜態成員變數,不能使用其他普通的成員變數; (2)程式碼例子邊看邊講解 #include <stdio.h> cla