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的函式符號才適合手工載入。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
好看好睏啊!!!!
相關推薦
Linux下RabbitMQ的編譯,生成動態庫和靜態庫
執行 編譯 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 程式執行後呼叫動態庫 動態庫: 程式在執行的時候才去連結動態庫的程式碼,多個程式
linux下g++ 編譯時動態庫和靜態庫的連結和標頭檔案問題
原來編譯的時候都是用的很隨意,沒用系統的總結一下,這幾天在編譯的時候遇到一些下問題,於是就總結一下,省得過幾天又給忘了。 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