1. 程式人生 > >Linux下的動態庫和靜態庫

Linux下的動態庫和靜態庫

在c/c++裡,使用庫(library)的技術,可以將編譯好的符號提供給第三方使用。

1)共享庫(動態庫)share library

2)   靜態庫 static library

一:動態庫的生成辦法:

使用g++命令來生成動態庫

編譯,生成.o檔案(編譯選項:-fPIC)

g++ -c -fPIC example.cpp -o example.o

連結,生成目標.so檔案,(連結選項:-shared)

g++ -shared example.o -o libexample.so

注:PIC:position independent code 位置無關程式碼

規範命令:字首:lib 字尾: .so

使用nm命令檢視庫中的符號:

nm libexample.so

交付物:

example.h+libexample.so,同時告知.so檔案適用的平臺

二:動態庫的使用

包含標頭檔案,呼叫其中的函式,編譯+連結:g++ main.cpp -o helloworld -L. -lexample

連結選項:

-lexample 使用libexample.so這個庫檔案

-L.指定庫檔案的位置(當前路徑) ,-L+路徑 比如-L/opt

那麼當.so檔案就在當前目錄下的時候程式仍然提示找不到庫檔案怎麼辦?

注意:作業系統預設從標準位置尋找相應的庫

/lib /usr/lib/ /usr/local/lib

如果沒有找到依賴的庫檔案,則從LD_LIBRARY_PATH環境變數裡尋找

也就是說,庫檔案要麼放在標準位置,要麼放在LD_LIBRARY_PATH指定的位置,才能被作業系統找到

設定環境變數:使用export命令設定環境變數,然後再執行程式

export LD_LIBRARY_PATH=.

./helloworld

可以使用echo檢視環境變數裡面的內容 :echo $LD_LIBRARY_PATH

那麼拿到一個可執行程式,怎麼知道它依賴哪些庫呢?

readelf -d helloworld

我們至少要知道兩個基本的庫:libc.so標準c庫

libstdc++.s標準c++庫(包含STL)

不需要在命令列中指定,g++預設會連結到這兩個庫。

補充:

1)在Makefile裡面生成動態庫

增加編譯項:-fPIC 增加連結項:-shared

改traget為libexample.so

編譯:%.o:%.cpp:

g++ -c -fPIC -MMD $< -o [email protected]

2)在建立動態庫時,裡面可以呼叫其他的動態庫,如果需要呼叫其他第三方庫,可以在連結時新增連結選項:

g++ -shared $(Objects) -o $(EXE) -lxxx(xxx為需要連結的庫名)

3)動態庫共享class類

引用標頭檔案,建立此類的物件,呼叫此類的函式

三.庫的目錄結構

linux下面可能會經常使用各種庫,有的是系統自帶的庫,有的是第三方庫

通常它們的目錄是:libxxx/ 

                             -lib/

                                     -include/

其中bin下為程式,lib下為庫檔案,include為標頭檔案

系統自帶庫放在:

/usr

  -include/

  -lib/

如何使用第三方庫,

標頭檔案:

使用編譯選項-l 引數來指定,修改Makefile(編譯選項和連結選項)

g++ -c -l /home/mytest/example/include...指定標頭檔案的位置

庫檔案引用:

-L /home/mytest/example -lexample或者-I/home/mytest/example/libexample.so全路徑指明庫檔案的位置

通常在Makefile裡定義兩個變數,CXXFLAGS表示c++編譯選項,LDFLAGS表示連結選項

INCLUDE路徑:用-I選項指定自定義的INCLUDE路徑

標準INCLUDE路徑:/usr/include /usr/local/include

四.靜態庫的建立與使用

靜態庫,static library

標準命名:libxxx.a

第一步:編譯,得到*.o檔案

第二步:打包

ar -rcs libxxx.a file1.o file2.o ...fileN.o

注意:sr只是將*.o檔案打個包而已,並非連結

靜態庫的交付物:

-標頭檔案*.h

-庫檔案libxxx.a

另外需要說明靜態庫適用的平臺

靜態庫的本質就是將一些.o檔案打個包而已,使其可以像.o檔案一樣使用

如何使用別人提供的靜態庫?

ar -rcs libtest.a test1.o test2.o 比較:g++ main.cpp test1.o test2.o -o helloworld g++ main.cpp libtest.a -o helloworld 也就是說靜態庫在命令列裡可以直接使用全路徑 也可以使用-l選項,指定靜態庫: g++ main.cpp -o helloworld -L .../.. -ltest,編譯器就在上述指定的位置找到 libtest.a 如果在一個目錄下同時存在靜態庫和動態庫,那麼編譯器如何選擇? 靜態庫與動態庫的區別: 1)使用靜態庫: 最終的程式裡含有test1和test2的程式碼,所以最終的程式在執行時不依賴於libtest.a的存在 2)使用動態庫: 最終的程式裡面沒有相應程式碼,所以程式在執行時會尋找libtest.so 當目錄中同時存在靜態庫和動態庫時,比如:
 -build/ 
-libtest.a -libtest.so 執行命令: g++ main.cpp -o helloworld -Lbuild -ltest 檢視用了哪個庫?nm helloworld 或者 readef -d helloworld 發現連結器首先選擇動態庫進行連結。 以下兩種方法可以強制使用靜態庫: 1)使用全路徑: g++ main.cpp build/libtest.a -o helloworld 2)-static 強制所有的庫都使用靜態庫版本 g++ main.cpp -o helloworld -static -Lbuild -ltest 這種方法的缺點是要求所有的庫都必須提供靜態庫版本,少一個都不行 注意;centos 預設安裝時不帶libc.a libstdc++.a...

五.C的函式與C++的函式的區別

1)按照c++編譯example.cpp

g++ -fPIC -shared example.cpp -o libexample.so

nm libexample.so

結果是:.....T _Z7exampleii

2)按照c編譯example.c

gcc -fPIC -shared example.c -o libexample.so

nm libexample.so

結果是:.....T  example

由於c函式生成的目標檔名稱就是函式名,因此不能重名,但是c++可以

那麼c++中如何使用c的庫呢?

比如,linexample.so是一個c的庫,在main.cpp中宣告標頭檔案,呼叫函式example(),執行命令:

g++ main.cpp -o helloworld -Lbuild -lexample,會出現undefined reference 的錯誤。

原因是:編譯器要找的是_Z7exampleii,而libexample.so裡面的符號是example,所以會報告出錯。

解決辦法:

如果在c++裡需要呼叫一個c的函式符號,需要新增extern "C"

例如在mian.cpp裡面呼叫時用以下語句:extern "C" vodi example(int a, int b)

extern "C":

1)宣告單個函式,如上

2)宣告多個函式,

extern “C”

{

 void fun1()

 void fun2()

}

一般情況下,應該由庫的作者提供一個相容c/c++的標頭檔案

比如example.h

/////example.h////

#ifdef __cplusplus

extern "C"

{

#endif

void example(int a ,int b);

#ifdef __cplusplus

}

#endif

這個是一個c/c++都相容的標頭檔案

也可以這樣使用:

extern "C"

{

 #include "example.h"

}

六.動態庫的手工載入

手工載入,在程式執行時刻,根據實際需要來載入、解除安裝

使用dl庫中的函式(dynamic linking loader)

標頭檔案:

#include<unistd.h>

#include<dlfcn.h>

連結選項:

-ldl

g++ main.cpp -o helloworld -ldl

程式碼裡面使用的dl函式:

1)載入:dlopen

2)找到函式符號:dlsym

3)呼叫函式(函式指標的語法)

4)解除安裝:dlclose

具體的程式碼如下:

//main.cpp

#include<stdio.h>

#include<unistd.h>

#include<dlfcn.h>

int main()

{

 //載入庫

void *lib = dlopen("build/libexample.so",RTLD_NOW);

 if(!lib)

{

printf("failed to load library!\n");

return -1;

}

//尋找函符號

typedef void (*SO_FUNCTION)(int ,int);

SO_FUCNTION f = (SO_FUNCTION) dlsym(lib, "example");

if(!f)

{

printf("failed to find the function!\n");

return -1;

}

//呼叫函式

f(1,2);

//解除安裝動態庫

dlclose(lib);

return 0;

}

常見問題:

1)dlopen失敗?

檢查檔案路徑

2)dlsym失敗

用nm命令檢視目標so是否有該符號。

注意:只有c的函式符號才適合手工載入。

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

好看好睏啊!!!!


相關推薦

LinuxRabbitMQ的編譯,生成動態靜態

執行 編譯 ast lin 目錄 off href apt-get span 一、步驟 1、代碼托管處下載代碼 最新:https://github.com/alanxz/rabbitmq-c/archive/master.zip 穩定:https://g

Linux動態靜態的連結

一、檢視連結了哪些指令 ldd 程式名字 二、在應用程式需要連線外部庫的情況下,linux預設對庫的連線是使用動態庫,在找不到動態庫的情況下再選擇靜態庫。使用方式為: gcc test.cpp -L. -ltestlib 如果當前目錄有兩個庫libtestlib.

Linux怎麼建立動態靜態

前言 linux下的生成的動態庫和靜態庫沒有windows下方便 linux下gcc編譯預設動態連結和release 程式執行後呼叫動態庫 動態庫: 程式在執行的時候才去連結動態庫的程式碼,多個程式

linuxg++ 編譯時動態靜態的連結標頭檔案問題

原來編譯的時候都是用的很隨意,沒用系統的總結一下,這幾天在編譯的時候遇到一些下問題,於是就總結一下,省得過幾天又給忘了。 1.動態庫和靜態庫簡介 靜態庫在程式連結的時候會自動的連結到程式裡,所以一旦編譯完成,靜態庫就不需要了,靜態庫以.a結尾。  動態庫在編譯時不會被連線到目的碼中,而是在程式執行

Linux用Makefile製作動態靜態並編譯生成可執行程式

Makefile 一個工程中的原始檔不計其數,其按型別、功能、模組分別放在若干個目錄中,makefile定義了一系列的規則來指定,哪些檔案需要先編譯,哪些檔案需要後編譯,哪些檔案需要重新

Linux動態靜態

庫: 在c/c++裡,使用庫(library)的技術,可以將編譯好的符號提供給第三方使用。 1)共享庫(動態庫)share library 2)   靜態庫 static library 一:動態庫

linux動態靜態的製作、尋找、比較及相關Makefile的編寫

一.庫的定義 什麼是庫,在windows平臺和linux平臺下都大量存在著庫。 本質上來說庫是一種可執行程式碼的二進位制形式,可以被作業系統載入記憶體執行。 由於windows和linux的本質不同,

Linux 動態靜態

Linux作業系統中,依據函式庫是否被編譯到程式內部,將其分為兩大類,靜態函式庫和動態函式庫。 Linux下的函式庫放在/lib或/usr/lib,標頭檔案放在/usr/include。 在既有靜態庫又有動態庫的情況下,預設使用動態庫,如果強制使用靜態庫則需要加-static選項支援。

QtEmbedded-4.8.6-arm 編譯選擇從 動態變化到靜態 時,生成的Makefile連結路徑如果有動態靜態,優先選擇動態編譯應用

問題:QtEmbedded-4.8.6-arm 編譯選擇從 動態庫到靜態庫 時,發現的一個疑惑:,生成的Makefile連結庫路徑下如果有動態庫和靜態庫,優先選擇動態庫編譯應用 具體現象: 我最初是使用動態庫的 QtEmbedded-4.8.6-arm (編譯器選擇時,是 ./co

Linux中的動態靜態(.a.la.so.o)

​ Linux中的動態庫和靜態庫(.a/.la/.so/.o) 原文地址:https://www.cnblogs.com/findumars/p/5421910.html 在windows下,一般可以通過檔案的字尾名來識別檔案的型別。在Linux下大致上也是可以的。但是要明

Linux系統的動態靜態

靜態庫 靜態庫:一些公共程式碼是需要反覆使用,就把這些程式碼編譯為“庫”檔案;在連結步驟中,聯結器將從庫檔案取得所需的程式碼,複製到生成的可執行檔案中的這種庫。 程式編譯一般需經預處理、編譯、彙編和連結幾個步驟。靜態庫特點是可執行檔案中包含了庫程式碼的一份完整拷貝;缺點就是被多次

linux c/c++ 動態靜態的生成與使用

二.介紹     從原始碼到可執行程式,通常要經過最重要的兩大步是:編譯,連結。編譯就是將原始檔生成中間檔案的過程,在linux下就是生成  .obj檔案。連結就是用連結器將,這些個中間檔案有序地”糅合“在一起,構成一個可執行檔案。通常,一個.c檔案或者.cpp原始檔編譯後,就會對應生成一個.obj檔案。  

自己在linux上編譯、連結、動態靜態的學習筆記

在平常的專案中,我們都是使用公司要求的makefile、makedebug一類的檔案,因此,在編譯、連結、生成和連結動態庫與靜態庫的時候,我們只是簡單的使用一些已經設定的變數,只是簡單的修改、新增一些檔名,或許這次我們編譯通過了,但是,在某一個時候,可能出現了一個問題,無論

linux編譯自己的靜態時依賴其他的動態,使用時出現“undefined reference to”

        對於我這個剛入IT行業不就得新手來說,在linux下連結庫的時候總是會遇到各種各樣奇葩的問題,最多的就是“undefined reference to”和“cannot find”這兩類,層出不窮,總是在我即將完成工作的時候給我當頭一棒,讓我欲罷不能。這不,這

linux兩種:動態靜態(共享)說明

linux下有兩種庫:動態庫和靜態庫(共享庫) 二者的不同點在於程式碼被載入的時刻不同。 靜態庫的程式碼在編譯過程中已經被載入可執行程式,因此體積比較大。 動態庫(共享庫)的程式碼在可執行程式執行時才載入記憶體,在編譯過程中僅簡單的引用,因此程式碼體積比較

linux c 語言程式設計環境:動態靜態的製作

庫: 庫用於將相似函式打包在一個單元中。然後這些單元就可為其他開發人員所共享,並因此有了模組化程式設計這種說法 — 即,從模組中構建程式。Linux 支援兩種型別的庫,每一種庫都有各自的優缺點。靜態庫包

動態靜態

linu not fine 執行文件 port pic 靜態庫 可執行 生成可執行文件 前提:本文是基於Linux系統下的編程與學習 補充:頭文件衛士,避免頭文件重復包含。 //頭文件衛士 #ifndef __HEAD_H__ #define __HEAD_H__ //頭

iOS裡的動態靜態

介紹 動態庫形式:.dylib和.framework 靜態庫形式:.a和.framework 動態庫和靜態庫的區別 靜態庫:連結時,靜態庫會被完整地複製到可執行檔案中,被多次使用就有多份冗餘拷貝(圖1所示) 系統動態庫:連結時不復制,程式執行時由系統動態

gcc中動態靜態的連結順序

so檔案:動態庫 a檔案: 靜態庫 exe檔案:可執行程式(linux下以檔案屬性來標示是否是可執行檔案,與字尾名無關) gcc中連結順序問題,總結出以下幾點: 1,動態庫中可以包含另一個靜態庫,通過引數 -lxxx 把靜態庫libxxx.a加入so檔案中,這樣so檔案中 &nbs

編譯時混合使用動態靜態

         編譯某個測試程式碼時,出現了下面的錯誤:# g++ -std=c++11 -o testlurkcli main.cpp -L. -llurkcli-lasl -static /us