linux動態庫及靜態庫的製作 和makefile 的簡單編寫
一.庫
什麼是庫,簡單的可以說是可執行程式碼的二進位制形式,能夠被作業系統載入記憶體執行。作業系統的不同,二者的庫也是不相容的,如windows與linux.
庫又分為靜態庫和動態庫,動態庫又稱為共享庫。linux下靜態庫(.a)檔案,動態庫(.so)檔案。主要存放函式庫的路徑有:/lib , /usr/lib.
二.靜態庫與動態庫
1.靜態庫
這類庫的名字一般是libname.a.利用靜態庫編寫的檔案比較大,原因是整個函式庫中的資料都被整合進目的碼檔案中去。它的優點是,編譯後的執行程式不需要外部的函式庫支援,因為所有使用的函式都已經被編譯進可執行檔案了。同樣它的不足,如果靜態函式庫改變了,那麼你的程式必須重新編譯,而且體積也較大。
2.動態庫
名字一般是libname.so.相對於靜態函式庫,動態函式庫在編譯的時候並沒有被編譯進目的碼中,你的程式執行到相關函式是菜呼叫函式庫裡的函式,因此動態函式庫所產生的可執行檔案比較小。由於函式庫沒有被整合進你的程式,而是程式執行時動態申請並呼叫,所以程式的執行環境中必須提供相應的庫。動態函式庫的改變並不影響你的程式,所以動態函式庫的升級比較方便。而且如果多個應用程式都要使用同一函式庫,動態庫就非常適合,可以減少應用程式的體積。
三.庫的建立
靜態庫的建立
gcc -c filen.c
ar -cr libname.a file1.o file2.o 。。
ar:靜態函式庫建立的命令-c :create的意思-r :replace的意思,表示當前插入的模組名已經在庫中存在,則替換同名的模組。如果若干模組中有一個模組在庫中不存在,ar顯示一個錯誤資訊,並不替換其他同名的模組。預設的情況下,新的成員增加在庫德結尾處。動態庫的建立
gcc -shard -fpic -o libname.so test1.c test2.c ....
-fpic:產生程式碼位置無關程式碼-shared 生成一個共享庫
四.實際操作
1.編寫三個簡單函式ADD.c SUB.c MUL.c如下
ADD.c
#include <stdio.h>
int ADD(int a, int b)
{
return a+b;
}
SUB.c
#include <stdio.h>
int SUB(int a ,int b)
{
return a-b;
}
MUL.c
#include <stdio.h>
int MUL(int a , int b)
{
return a*b;
}
和一個頭檔案 fun.h
#ifdef __FUN_H_
#define __FUN_H_
extern ADD(int a , int b);
extern SUB(int a , int b);
extern MUL(int a , int b);
#endif
以及一個main函式main.c
main.c
#include <stdio.h>
#include <fun.h>
int main (void)
{
int a=5;
int b=10;
printf("a=5,b=10\n");
printf("a+b=%d\n",ADD(a,b));
printf("a-b=%d\n",SUB(a,b));
printf("a*b=%d\n",MUL(a,b));
return 0;
}
其中main.c 放在~/app下 fun.h ADD.c SUB.c MUL.c放在~/src下
2.生成靜態庫
[[email protected] src]$ ls
ADD.c fun.h makefile MUL.c SUB.c
[[email protected] src]$ gcc -c *.c
[[email protected] src]$ ls
ADD.c ADD.o fun.h makefile MUL.c MUL.o SUB.c SUB.o
[[email protected] src]$ ar -cr libfun.a *.o
[[email protected] src]$ ls
ADD.c ADD.o fun.h libfun.a makefile MUL.c MUL.o SUB.c SUB.o
上中libfun.a即是一個靜態庫
生成動態庫
[[email protected] src]$ ls
ADD.c ADD.o fun.h libfun.a makefile MUL.c MUL.o SUB.c SUB.o
[[email protected] src]$ gcc -shared -fpic -o libfun.so *.c
[[email protected] src]$ ls
ADD.c ADD.o fun.h libfun.a libfun.so makefile MUL.c MUL.o SUB.c SUB.o
上中libfun.so 就是一個動態庫
3.靜態庫與動態庫的使用
對main.c進行編譯
[[email protected] app]$ ls
main.c makefile
[[email protected] app]$ gcc main.c
main.c:14:17: 錯誤:fun.h:沒有那個檔案或目錄
編譯器報錯 找不到標頭檔案 需要指定標頭檔案的位置
-I選項 指定標頭檔案的路徑
[[email protected] app]$ gcc -I../src main.c
/tmp/ccZw9v3Q.o: In function `main':
main.c:(.text+0x30): undefined reference to `ADD'
main.c:(.text+0x5a): undefined reference to `SUB'
main.c:(.text+0x84): undefined reference to `MUL'
collect2: ld 返回 1
連結器再一次報錯 未能找庫
-L選項來指定庫的路徑
-l選項來指定庫的名字 (去掉lib和.a .so)剩下的部分 即-lfun
[[email protected] app]$ gcc -I../src main.c -L../src -lfun -o app
[[email protected] app]$ ls
app main.c makefile
生成一個可執行檔案 app
[[email protected] app]$ ./app
./app: error while loading shared libraries: libfun.so: cannot open shared object file: No such file or directory
執行時出錯 找不到動態庫
[[email protected] app]$ file app
app: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
這時我們可以發現 系統編譯時預設使用的是動態連結 執行時我們需要指定動態庫的位置
兩種方法:
1:將函式庫移動到/lib 或者/usr/lib下 (需要root許可權)
2:修改一個環境變數 LD_LIBRARY_PATH
在這裡我採用第二種方法
[[email protected] app]$ ./app
./app: error while loading shared libraries: libfun.so: cannot open shared object file: No such file or directory
[[email protected] app]$ file app
app: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
[[email protected] app]$ cd ../src
[[email protected] src]$ ls
ADD.c ADD.o fun.h libfun.a libfun.so makefile MUL.c MUL.o SUB.c SUB.o
[[email protected] src]$ pwd
/home/hongfuhao/src
[[email protected] src]$ cd ../app
[[email protected] app]$ ls
app main.c makefile
[[email protected] app]$ export LD_LIBRARY_PATH=/home/hongfuhao/src:$LD_LIBRARY_PATH
[[email protected] app]$ ./app
a=5,b=10
a+b=15
a-b=-5
a*b=50
可以看到程式成功執行
如果想採用靜態連結方式 需要-static關鍵字
[[email protected] app]$ ls
main.c makefile
[[email protected] app]$ gcc -static -I../src main.c -o bpp -L../src -lfun
[[email protected] app]$ ls
bpp main.c makefile
[[email protected] app]$ ./bpp
a=5,b=10
a+b=15
a-b=-5
a*b=50
這時再看bpp檔案
[[email protected] app]$ file bpp
bpp: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.18, not stripped
採用的靜態連結執行時不需要指定庫的路徑
兩個檔案app與bpp的大小 使用du命令
[[email protected] app]$ du app
8 app
[[email protected] app]$ du bpp
744 bpp
看一個檔案執行依賴的動態庫
[[email protected] app]$ ldd app
linux-vdso.so.1 => (0x00007ffe7a3bf000)
libfun.so => /home/hongfuhao/src/libfun.so (0x00007f775018f000)
libc.so.6 => /lib64/libc.so.6 (0x00000030cee00000)
/lib64/ld-linux-x86-64.so.2 (0x00000030ce600000)
以上為app依賴的動態庫檔案
[[email protected] app]$ ldd bpp
不是動態可執行檔案
bpp不是動態連結所以不顯示
上述就完成一個靜態庫和動態庫的建立和使用
五.makefile
1.概述
Linux 環境下的程式設計師如果不會使用GNU make來構建和管理自己的工程,應該不能算是一個合格的專業程式設計師,至少不能稱得上是 Unix程式設計師。在 Linux(unix )環境下使用GNU 的make工具能夠比較容易的構建一個屬於你自己的工程,整個工程的編譯只需要一個命令就可以完成編譯、連線以至於最後的執行。不過這需要投入一些時間去完成一個或者多個稱之為Makefile 檔案的編寫。
所要完成的Makefile 檔案描述了整個工程的編譯、連線等規則。其中包括:工程中的哪些原始檔需要編譯以及如何編譯、需要建立那些庫檔案以及如何建立這些庫檔案、如何最後產生想要得可執行檔案。儘管看起來可能是很複雜的事情,但是為工程編寫Makefile 的好處是能夠使用一行命令來完成“自動化編譯”,一旦提供一個(通常對於一個工程來說會是多個)正確的 Makefile。編譯整個工程你所要做的唯一的一件事就是在shell 提示符下輸入make命令。整個工程完全自動編譯,極大提高了效率。
make是一個命令工具,它解釋Makefile 中的指令(應該說是規則)。在Makefile檔案中描述了整個工程所有檔案的編譯順序、編譯規則。Makefile 有自己的書寫格式、關鍵字、函式。像C 語言有自己的格式、關鍵字和函式一樣。而且在Makefile 中可以使用系統shell所提供的任何命令來完成想要的工作。Makefile(在其它的系統上可能是另外的檔名)在絕大多數的IDE 開發環境中都在使用,已經成為一種工程的編譯方法。
2.makefile 小結即規範
Make 執行總目標
Make clean 執行makefile 中的clean目標
Make -C directory 到directory中執行make
Make clean -C directory 同上兩命令
Make -f common_makefile 通過-f 指定一個makefile檔案
Make var=value 給makefie傳一個引數其值為value
# 註釋
VAR=XXX 定義變數VAR,強制賦值
VAR+=XXX 追加
VAR?=XXX 之前定義這用之前 沒有定義 則定義
Target: depend1 depend2 . . #依賴可以是檔案(目錄)或其他目標
(tab) action1 action2 #動作那一行必須以TAB鍵打頭
Depend1:
@(tab)Action1 action2 #@j鍵表示不列印該行動作資訊
2.實際操作
編寫自己的makefile
使用之前靜態庫與動態庫的案例
建立一個makefile
1 LIB_NAME?=fun
2
3 all:static_library shared_library
4
5 static_library:
6 gcc -c *.c;
7 ar -cr lib${LIB_NAME}.a *.o;
8
9 shared_library:
10 gcc -shared -fpic -o lib${LIB_NAME}.so *.c;
11
12 clean:
13 rm -rf *.o
14 rm -rf *.a *.so
[[email protected] src]$ ls
ADD.c fun.h makefile MUL.c SUB.c
makefile已經建立完成
make命令可以完成之前的操作
[[email protected] src]$ ls
ADD.c fun.h makefile MUL.c SUB.c
[[email protected] src]$ make
gcc -c *.c;
ar -cr libfun.a *.o;
gcc -shared -fpic -o libfun.so *.c;
[[email protected] src]$ ls
ADD.c ADD.o fun.h libfun.a libfun.so makefile MUL.c MUL.o SUB.c SUB.o
完成了靜態庫和動態庫的建立 只需要make一下
對main.c進行makefile的編寫
makefile
1 APP_NAME?=APP
2
3 all:lib_make
4 gcc -static -I../src main.c -L../src -lfun -o ${APP_NAME};
5
6 lib_make:
7 make -C ../src;
8
9 clean:
10 rm -rf ${APP_NAME}
[[email protected] app]$ ls
main.c makefile
[[email protected] app]$ ls
main.c makefile
只需要make一下 就可以完成main.c編譯
[[email protected] app]$ make
make -C ../src;
make[1]: Entering directory `/home/hongfuhao/src'
gcc -c *.c;
ar -cr libfun.a *.o;
gcc -shared -fpic -o libfun.so *.c;
make[1]: Leaving directory `/home/hongfuhao/src'
gcc -static -I../src main.c -L../src -lfun -o APP;
[[email protected] app]$ ls
APP main.c makefile
生成一個APP的可執行檔案makefile中執行的是靜態連結
可以直接執行APP
[[email protected] app]$ ./APP
a=5,b=10
a+b=15
a-b=-5
a*b=50
程式成功執行
即完成了一個簡單的makefile的編寫