天天看點

如何電腦上共享代碼

如果你在同一台計算機上做程式設計工作,你想在多個程式中使用相同的代碼,但又不想每個程式都保留一份相同的代碼。那麼最好的做法就是共享這部分代碼,我們可以在程式之間共享兩類代碼:.h頭檔案和.o目标檔案。

那麼應該怎麼共享呢?

共享.h頭檔案

有兩種方式:

1.把.h頭檔案儲存在标準目錄中,在類Unix系統中,标準目錄就是/usr/local/include

隻要頭檔案在标準目錄中,就可以用尖括号包含它們,如共享.encrypt.h檔案:

~$mv encrypt.h /usr/local/include
//在代碼中包含頭檔案
#include <encrypt.h>      

2.把頭檔案放在非标準目錄中,在使用時,就要用完整的路徑名,不能使用尖括号,如:

~/Desktop/Mc$ mkdir ~/my_head_file
~/Desktop/Mc$ mv encrypt.h ~/my_head_file

    //在代碼中包含頭檔案
#include "/home/wong/my_head_file/encrypt.h"      

如果你沒有使用完整路徑名引用頭檔案,就要告訴編譯器去哪裡找頭檔案:

如果此時頭檔案中/home/wong/my_head_file中,如test.c檔案中是如此#include "encrypt.h"包含了此頭檔案,那麼就要這樣編譯:

$ gcc -I/home/wong/my_head_file encrypt.c checksum.c test.c -o test      

注:-I就是告訴編譯器去哪裡找頭檔案的

共享.o目标檔案

1.可以把.o目錄檔案放在一個目錄下,是以編譯時,隻在目标檔案前加上完整路徑即可:

~/Desktop/Mc$ mkdir ~/my_object_file
~/Desktop/Mc$ mv encrypt.o checksum.o ~/my_object_file
~/Desktop/Mc$ gcc -I/home/wong/my_head_file test.c /home/wong/my_object_file/encrypt.o /home/wong/my_object_file/checksum.o -o test      

但是上面這種共享會讓人很累,如果一兩個還好,多了的話,就那是受罪,是以提供另外一種方法,就是将目标檔案存檔,即将一批目标檔案打包在一起,然後就可以一次告訴編譯器一批目标檔案了。

存檔檔案的字尾名是.a。

存檔檔案的标準命名方式是libXXX.a的形式。

存檔是靜态庫,編譯時會把代碼放到你的程式中,文章後面會價紹動态庫。

用ar指令建立存檔:

~/Desktop/Mc$ ar -rcs libencrypchecksum.a encrypt.o checksum.o      

介紹一下參數:

r:表示如果.a檔案存在就更新它。

c:建立存在時不顯示回報資訊

s: 告訴ar要在.a檔案開頭建立索引

.a存檔檔案可以放哪裡呢?

1.可以放在标準目錄/usr/local/lib,編譯就無需要告訴編譯器要去哪裡找存檔檔案:

~/Desktop/Mc$ gcc test.c  -lencrypchecksum -o test      

2.還可以放在其他目錄中,編譯就需要告訴編譯器要去哪裡找存檔檔案。

~/Desktop/Mc$ mkdir ~/my_lib
~/Desktop/Mc$ mv libencrypchecksum.a ~/my_lib
~/Desktop/Mc$ gcc -I/home/wong/my_head_file test.c -L/home/wong/my_lib -lencrypchecksum -o test      

-L參數就是告訴編譯器去哪裡找存檔檔案的。

-l參數後就是跟存檔名,注意存檔名是去掉了lib和.a的部分。

如果想從存檔檔案中提取目标檔案,也是可以的,如我們提取encrypt.o檔案,方法如下:

~/my_lib$ ar -x libencrypchecksum.a encrypt.o
~/my_lib$ ls
encrypt.o  libencrypchecksum.a      

這樣encrypt.o檔案就被提取出來了。

上面就是共享.h頭檔案和.o目标檔案的方法。

上面的編譯都是靜态編譯,或者說是靜态連結,一旦連結了就不能更改了,也就是說,這些目錄檔案的代碼被包含程序式,如果要修改這些目标檔案,那程式隻能重新編譯了。

但是如果這些目标檔案做成動态庫,那問題很好辦了。動态庫與存檔很像,不同的地方就是在動态庫中,目标檔案會連結成一段目标代碼。動态庫有上些額外資訊,作業系統需要用這些資訊把庫連接配接到程式。

因為庫是動态的,是以使用動态庫編譯時,編譯器不會在可執行檔案中包含庫代碼,即目标檔案的代碼不會被包含程序式,而是會在可執行檔案中插入一段用來查找庫的“占位符”代碼,并在運作時連結庫。

動态庫在不同平台有不同叫法:

在Linux和Unix上叫共享目标檔案,​​​字尾名是.so​​​ 在Mac平台上,叫動态庫,字尾名是.dylib

在Windows平台上,叫動态連結庫,字尾名是.dll

我們開始建立動态庫吧。

1.首先建立目标檔案:

~/Desktop/Mc$ gcc -I/home/wong/my_head_file -fPIC -c  encrypt.c
~/Desktop/Mc$ gcc -I/home/wong/my_head_file -fPIC -c  checksum.c      

-c:表示不要連結代碼

-fPIC:告訴gcc編譯器建立位置無關代碼

位置無關的代碼就是無論計算機把它加載到存儲器的哪個位置都可以運作的代碼。例如,有個動态庫,它要加載800個位元組外的某個全局變量的值,如果作業系統把動态庫載到其他地方,就會出錯,隻有建立了位置無關的動态庫才能解決此問題。

有的作業系統和處理器要用位置無關代碼建立庫,這樣它們才能在運作時決定把代碼加載到存儲器的哪個位置。事實上大多數作業系統都不需要加這個選擇。

2.建立動态庫

我們把ecnrypt.o和checksum.o編進動态庫裡去

~/Desktop/Mc$ gcc -shared encrypt.o checksum.o -o libencryptchecksum.so      

-shared選項就是告訴gcc我們想把.o目标檔案轉化為動态庫。

linux和Unix平台上動态庫的标準命名方式是:​​libXXX.so​​​ 注意:上面建立了一個叫libencryptchecksum.so的庫,那麼libencryptchecksum.so檔案就會記錄它的庫名叫encryptchecksum,就是說一旦用了某個名字編譯了動态庫,就不能再修改檔案名了。若想重命名庫,就必須用新的名字重新編譯一次。

3.用動态庫編譯程式

~/Desktop/Mc$ gcc -I/home/wong/my_head_file -c test.c -o test.o
~/Desktop/Mc$ gcc test.o -L/home/wong/my_lib -lencryptchecksum -o test
~/Desktop/Mc$ ./test
./test: error while loading shared libraries: libencryptchecksum.so: cannot open shared object file: No such file or directory      

成功編譯了,但是運作的時候出錯了!!!

原因:在Linux和大部分Unix中,編譯器隻會記錄libencryptchecksum.so庫的檔案名,而不會記錄路徑名。

如果不是把動态庫儲存到标準庫/usr/lib中,程式就會找不到它,為了解決這個問題,Linux會檢查儲存在LD_LIBRARY_PATH變量中的附加目錄,隻要把庫目錄添加到這LD_LIBRARY_PATH中,并export它,程式就能找到libencryptchecksum.so庫了。

~/Desktop/Mc$ export  LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/my_lib
~/Desktop/Mc$ ./test
!!!!!