gcc/g++實戰之動態連接庫與靜態連接庫編寫

函數庫通常分爲靜態庫和動態庫兩種。ios

靜態庫:

是指編譯連接時,把庫文件的代碼所有加入到可執行文件中,所以生成的文件比較大,但在運行時也就再也不須要庫文件了。其後綴名通常爲」.a」。bash

動態庫:函數

與之相反,在編譯連接時並無把庫文件的代碼加入到可執行文件中,而是在程序執行時由運行時連接文件加載庫,這樣能夠節省系統的開銷。動態庫通常後綴名爲」.so」,gcc/g++在編譯時默認使用動態庫。不管靜態庫,仍是動態庫,都是由.o文件建立的。測試

 

動態庫的編譯:

下面經過一個例子來介紹如何生成一個動態庫。建一個頭文件:dynamic.h,三個.cpp文件:dynamic_a.cpp、dynamic_b.cpp、dynamic_c.cpp,咱們將這幾個文件編譯成一個動態庫:libdynamic.so。
//dynamic.h
#ifndef __DYNAMIC_H_
#define __DYNAMIC_H_
#include <iostream>
void dynamic_a();
void dynamic_b();
void dynamic_c();
#endif

  

//dynamic_a.cpp:
#include"dynamic.h"
void dynamic_a()
{
  cout<<"this is in dynamic_a "<<endl;
}
 
//dynamic_b.cpp:
#include"dynamic.h"
void dynamic_b()
{
  cout<<"this is in dynamic_b "<<endl;
}
 
 
//dynamic_c.cpp:
#include"dynamic.h"
void dynamic_c()
{
  cout<<"this is in dynamic_c "<<endl;
}
 
將這幾個文件編譯成動態庫libdynamic.so。編譯命令以下:
 
g++ dynamic_a.cpp dynamic_b.cpp dynamic_c.cpp -fPIC -shared -o libdynamic.so
 

參數說明:

-shared:該選項指定生成動態鏈接庫
-fPIC:表示編譯爲位置獨立的代碼,不用此選項的話編譯後的代碼是位置相關的因此動態載入時是經過代碼拷貝的方式來知足不一樣進程的須要,而不能達到真正代碼段共享的目的。
 
 
在上面的部分,咱們已經生成了一個libdynamic.so的動態連接庫,如今咱們用一個程序來調用這個動態連接庫。文件名爲:main.cpp
//main.cpp:
#include"dynamic.h"
int main()
{
  dynamic_c();
  dynamic_c();
  dynamic_c();
  return 0;
}

 

將main.cpp與libdynamic.so連接成一個可執行文件main。命令以下:
 
g++ main.cpp -L. -ldynamic -o main

 

參數說明:

-L.:表示要鏈接的庫在當前目錄中
-ldynamic:編譯器查找動態鏈接庫時有隱含的命名規則,即在給出的名字前面加上lib,後面加上.so來肯定庫的名稱
 
 
測試可執行程序main是否已經連接的動態庫libdynamic.so,若是列出了libdynamic.so,那麼就說明正常連接了。能夠執行如下命令:
ldd main

 
若是運行:
./main
 
出現錯誤 error while loading shared libraries: libdynamic.so: cannot open shared object file: No such file or directory
 

錯誤緣由

ld提示找不到庫文件,而庫文件就在當前目錄中。
 
連接器ld默認的目錄是/lib和/usr/lib,若是放在其餘路徑也能夠,須要讓ld知道庫文件在哪裏。
 

解決方法:

方法1:

編輯/etc/ld.so.conf文件,在新的一行中加入庫文件所在目錄;好比筆者應添加:
/home/neu/code/Dynamic_library
 
運行:
sudo ldconfig

 

目的是用ldconfig加載,以更新/etc/ld.so.cache文件;
 
 

方法2:

在/etc/ld.so.conf.d/目錄下新建任何以.conf爲後綴的文件,在該文件中加入庫文件所在的目錄;
運行:
sudo ldconfig

以更新/etc/ld.so.cache文件;this

 
ld.so.cache的更新是遞增式的,就像PATH系統環境變量同樣,不是從頭從新創建,而是向上累加。除非從新開機,纔是從零開始創建ld.so.cache文件。

方法3:

在bashrc或profile文件裏用LD_LIBRARY_PATH定義,而後用source加載。

方法4:

你能夠直接採用在編譯連接的時候告訴系統你的庫在什麼地方
 
執行main能夠看看main是否調用了動態連接庫中的函數。
./main

 

靜態庫的編譯:

讀者能夠本身建立代碼,筆者比較懶,就以以上代碼演示,最好把生成的動態庫的東西所有刪掉。spa

1.編譯靜態庫:
g++ -c dynamic_a.cpp dynamic_b.cpp dynamic_c.cpp  

 

 2.使用ar命令建立靜態庫文件(把目標文檔歸檔)
 
ar cr libstatic.a dynamic_a.o dynamic_b.o dynamic_c.o  //cr標誌告訴ar將object文件封裝(archive)

 

 
 
參數說明:
         
          d 從指定的靜態庫文件中刪除文件 
          m 把文件移動到指定的靜態庫文件中 
          p 把靜態庫文件中指定的文件輸出到標準輸出 
          q 快速地把文件追加到靜態庫文件中 
          r 把文件插入到靜態庫文件中 
          t 顯示靜態庫文件中文件的列表 
          x 從靜態庫文件中提取文件 
          a 把新的目標文件(*.o)添加到靜態庫文件中現有文件以後 
 
 
使用nm -s 命令來查看.a文件的內容
nm -s libstatic.a 

 
3.連接靜態庫
g++ main.cpp -lstatic -L. -static -o main//這裏的-static選項是告訴編譯器,hello是靜態庫也能夠用

                        //g++ main.cpp -lstatic -L.  -o main 

 

執行如下命令,由於筆者仍是用的動態庫的代碼,因此結果同樣
./main

相關文章
相關標籤/搜索