Linux中.a,.la,.o,.so檔案的意義和編程實現

來源:互聯網
上載者:User

Linux中.a,.la,.o,.so檔案的意義和編程實現 (轉)

 

Linux下檔案的類型是不依賴於其尾碼名的,但一般來講:

.o,是目標檔案,相當於windows中的.obj檔案
.so 為共用庫,是shared object,用於動態串連的,和dll差不多
.a為靜態庫,是好多個.o合在一起,用於靜態串連
.la為libtool自動產生的一些共用庫,vi編輯查看,主要記錄了一些配置資訊。可以用如下命令查看*.la檔案的格式 $file *.la

*.la: ASCII English text
所以可以用vi來查看其內容。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
建立.a庫檔案和.o庫檔案:
[yufei@localhost perl_c2]$ pwd
/home/yufei/perl_c2

[yufei@localhost perl_c2]$ cat mylib.c
#include
#include
void hello(){
printf("success call from perl to c library"n");
}
[yufei@localhost perl_c2]$ cat mylib.h
extern void hello();

[yufei@localhost perl_c2]$ gcc -c mylib.c
[yufei@localhost perl_c2]$ dir
mylib.c mylib.h mylib.o
[yufei@localhost perl_c2]$ ar -r mylib.a mylib.o
ar: 正在建立 mylib.a
[yufei@localhost perl_c2]$ dir
mylib.a mylib.c mylib.h mylib.o

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
動態連結程式庫*.so的編譯與使用- -

動態庫*.so在Linux下用c和c++編程時經常會碰到,最近在網站找了幾篇文章介紹動態庫的編譯和連結,總算搞懂了這個之前一直不太瞭解得東東,這裡做個筆記,也為其它正為動態庫連結庫而苦惱的兄弟們提供一點協助
1、動態庫的編譯

下面通過一個例子來介紹如何產生一個動態庫。這裡有一個標頭檔:so_test.h,三個.c檔案:test_a.c、test_b.c、test_c.c,我們將這幾個檔案編譯成一個動態庫:libtest.so。

so_test.h:

#include
#include
void test_a();
void test_b();
void test_c();

test_a.c:

#include "so_test.h"
void test_a()
{
printf("this is in test_a..."n");
}

test_b.c:

#include "so_test.h"
void test_b()
{
printf("this is in test_b..."n");
}

test_c.c:

#include "so_test.h"
void test_c()
{
printf("this is in test_c..."n");
}

將這幾個檔案編譯成一個動態庫:libtest.so
$ gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so

2、動態庫的連結

在1、中,我們已經成功產生了一個自己的動態連結程式庫libtest.so,下面我們通過一個程式來調用這個庫裡的函數。程式的源檔案為:test.c。
test.c:

#include "so_test.h"
int main()
{
test_a();
test_b();
test_c();
return 0;

}
l 將test.c與動態庫libtest.so連結產生執行檔案test:
$ gcc test.c -L. -ltest -o test

l 測試是否動態串連,如果列出libtest.so,那麼應該是串連正常了

$ ldd test
l 執行test,可以看到它是如何調用動態庫中的函數的。
3、編譯參數解析
最主要的是GCC命令列的一個選項:
-shared 該選項指定產生動態串連庫(讓連接器產生T類型的匯出符號表,有時候也產生弱串連W類型的匯出符號),不用該標誌外部程式無法串連。相當於一個可執行檔

l -fPIC:表示編譯為位置獨立的代碼,不用此選項的話編譯後的代碼是位置相關的所以動態載入時是通過代碼拷貝的方式來滿足不同進程的需要,而不能達到真正程式碼片段共用的目的。

l -L.:表示要串連的庫在目前的目錄中

l -ltest:編譯器尋找動態串連庫時有隱含的命名規則,即在給出的名字前面加上lib,後面加上.so來確定庫的名稱

l LD_LIBRARY_PATH:這個環境變數指示動態連接器可以裝載動態庫的路徑。

l 當然如果有root許可權的話,可以修改/etc/ld.so.conf檔案,然後調用 /sbin/ldconfig來達到同樣的目的,不過如果沒有root許可權,那麼只能採用輸出LD_LIBRARY_PATH的方法了。
4、注意
調用動態庫的時候有幾個問題會經常碰到,有時,明明已經將庫的標頭檔所在目錄 通過 “-I” include進來了,庫所在檔案通過“-L”參數引導,並指定了“-l”的庫名,但通過ldd命令察看時,就是死活找不到你指定連結的so檔案,這時你 要作的就是通過修改LD_LIBRARY_PATH或者/etc/ld.so.conf檔案來指定動態庫的目錄。通常這樣做就可以解決庫無法連結的問題 了。

makefile裡面怎麼正確的編譯和串連產生.so庫檔案,然後又是在其他程式的makefile裡面如何編譯和串連才能調用這個庫檔案的函數????
答:
你需要告訴動態連結器、載入器ld.so在哪裡才能找到這個共用庫,可以設定環境變數把庫的路徑添加到庫目錄/lib和/usr/lib,LD_LIBRARY_PATH=$(pwd),這種方法採用命令列方法不太方便,一種替代方法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^注釋^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LD_LIBRARY_PATH可以在/etc/profile還是 ~/.profile還是 ./bash_profile裡設定,或者.bashrc裡,

改完後運行source /etc/profile或 . /etc/profile
更好的辦法是添入/etc/ld.so.conf, 然後執行 /sbin/ldconfig

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^注釋^^^^^^^^^^^^^^^^^^^^^^^^^^^^
是把庫路徑添加到/etc/ld.so.conf,然後以root身份運行ldconfig
也可以在串連的時候指定檔案路徑和名稱 -I -L.

GCC=gcc
CFLAGS=-Wall -ggdb -fPIC
#CFLAGS=
all: libfunc test
libfunc:func.o func1.o
$(GCC) -shared -Wl,-soname,libfunc.so.1 -o libfunc.so.1.1 {GetProperty(Content)}lt;
ln -sf libfunc.so.1.1 libfunc.so.1
ln -sf libfunc.so.1 libfunc.so
***********************************************注釋************************************************
ln -s是用來建立軟連結,也就相當於windows中的捷徑,在目前的目錄中建立上一級目錄中的檔案ttt的命名為ttt2軟連結的命令是ln -s ../ttt ttt2,如果原檔案也就是ttt檔案刪除的話,ttt2也變成了空檔案。
ln -d是用來建立永久連結,也就相當於windows中檔案的副本,當原檔案刪除的時候,並不影響“副本”的內容。

編譯目標檔案時使用gcc的-fPIC選項,產生與位置無關的代碼並能被載入到任何地址:
gcc –fPIC –g –c liberr.c –o liberr.o
使用gcc的-shared和-soname選項;
使用gcc的-Wl選項把參數傳遞給連接器ld;
使用gcc的-l選項顯示的串連C庫,以保證可以得到所需的啟動(startup)代碼,從而避免程式在使用不同的,可能不相容版本的C庫的系統上不能啟動執行。
gcc –g –shared –Wl,-soname,liberr.so –o liberr.so.1.0.0 liberr.o –lc

建立相應的符號串連:
ln –s liberr.so.1.0.0 liberr.so.1;
ln –s liberr.so.1.0.0 liberr.so;

在MAKEFILE中:
$@
表示規則中的目標檔案集。在模式規則中,如果有多個目標,那麼,"$@"就是匹配於目標中模式定義的集合。
$%
僅當目標是函數庫檔案中,表示規則中的目標成員名。例如,如果一個目標是"foo.a(bar.o)",那麼,"$%"就是"bar.o","$@"就 是"foo.a"。如果目標不是函數庫檔案(Unix下是[.a],Windows下是[.lib]),那麼,其值為空白。
{GetProperty(Content)}lt;
依賴目標中的第一個目標名字。如果依賴目標是以模式(即"%")定義的,那麼"{GetProperty(Content)}lt;"將是符合模式的一系列的檔案集。注意,其是一個一個取出來的。
$?
所有比目標新的依賴目標的集合。以空格分隔。
$^
所有的依賴目標的集合。以空格分隔。如果在依賴目標中有多個重複的,那個這個變數會去除重複的依賴目標,只保留一份。
*********************************************注釋***********************************************************************
test: test.o libfunc
$(GCC) -o test test.o -L. -lfunc
%.o:%.c
$(GCC) -c $(CFLAGS) -o $@ {GetProperty(Content)}lt;
clean:
rm -fr *.o
rm -fr *.so*
rm -fr test

要產生.so檔案,cc要帶-shared 參數;要調用.so的檔案,比如libfunc.so,可以在cc命令最後加上-lfunc,還要視情況加上-L/usr/xxx 指出libfunc.so的路徑;這樣,在你要編譯的源檔案中就可以調用libfunc.so這個庫檔案的函數.
前面的都說的差不多了,最後提醒一下最好提供一個介面標頭檔
動態載入,用dlopen,dlclose,dlsym

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.