一 gcc編譯過程
我們知道gcc是一個強大的編譯器,很多Linux下的GNU工具都是用C語言寫的,並且用gcc編譯的,那麼gcc的編譯過程是怎樣的呢,先來看一個總的流程圖,我自己簡單畫的,湊合著看
1首先是源文件經過預加載變成了.i結尾的文件,可以通過-E這個參數來生成這個中間文件,這裡主要是把一些include的頭文件和一些宏定義,放到源文件中。
2從預加載的文件經過編譯就會變成匯編語言的文件,這一步可以通過-S這個參數來生成這個中間文件
3從匯編語言的文件通過匯編,就會變成目標代碼.o的文件,這一步可以通過-C這個參數來生成這個中間文件
4最後經過鏈接,生成最終的可執行文件
可能這樣說比較難懂,我們通過一個例子來說明下:
我新建了一個hello.c的文件
然後我先生成.i結尾的預加載文件
gcc -E hello.c -o hello.i
我們看到這個文件生成了,我們看一下這個文件的內容
大家會發現這個文件的內容非常多,但是最後是我們本來的代碼,上面的代碼都是頭文件和一些宏的內容,全加載進來了
下面我們通過編譯生成匯編文件.s
gcc -S hello.i -o hello.s
然後我們看一下這個hello.s
看到了我們熟悉的匯編語言
我們繼續,經過匯編器,生成.o的目標文件
gcc -c hello.s -o hello.o
依然來看下內容
看到了一堆二進制的感覺
最後通過鏈接器,生成可執行文件
gcc hello.o -o hello
然後執行
當然如果你不想做這麼多步驟,直接gcc hello.c -o hello即可完成上面所有的步驟了。
二 靜態鏈接庫和動態鏈接庫
靜態鏈接庫就是在程序編譯的時候就被加載進來,這樣的可執行文件會比較大一些,還不能共享
動態鏈接庫是在程序執行的時候加載,可共享
看下面一個例子
現在有這麼三個文件
如果直接編譯hello.c肯定會報錯,因為這裡沒有main函數,那麼我們該怎麼處理呢
1 都編譯成.o文件,然後鏈接,生成可執行文件
2 利用靜態鏈接庫
在linux下,庫文件一般放在/usr/lib和/lib下,
靜態庫的名字一般為libxxxx.a,其中xxxx是該lib的名稱
動態庫的名字一般為libxxxx.so.major.minor,xxxx是該lib的名稱,major是主版本號, minor是副版本號
靜態庫的後綴是.a,它的產生分兩步
由源文件編譯生成一堆.o,每個.o裡都包含這個編譯單元的符號表
ar命令將很多.o轉換成.a,成為靜態庫
ar rcs libmyhello.a hello.o
注意,gcc會在靜態庫名前加上前綴lib,然後追加擴展名.a得到的靜態庫文件名來查找靜態庫文件,因此,我們在寫需要連接的庫時,只寫名字就可以,如libmyhello.a的庫,只寫:-lmyhello
gcc -o hello main.c -static -L. -lmyhello
-static代表使用靜態鏈接庫,-L.代表靜態鏈接庫搜索路徑 .代表當前路徑
3 動態鏈接庫
gcc -shared -fPIC -c hello.c
gcc -shared -fPIC -o libmyhello.so hello.o
-share代表是動態鏈接庫
-fPIC命令行標記告訴GCC產生的代碼不要包含對函數和變量具體內存位置的引用,這是因為現在還無法知道使用該消息代碼的應用程序會將它連接到哪一段內存地址空間。這樣編譯出的hello.o可以被用於建立共享鏈接庫
最後gcc -o hello main.c -L. -lmyhello生成hello可執行文件,注意執行的時候可能會報錯,說找不到這個
libmyhello.so文件,如果放在/lib或者/usr/lib下,那麼默認就能找到,如果放在其他目錄下,需要編輯/etc/ld.so.conf文件,加入庫文件所在目錄的路徑,然後
運行ldconfig 目錄名字,該命令會重建/etc/ld.so.cache文件即可。
好了,Linux下gcc編譯過程,靜態鏈接庫和動態鏈接庫就總結到這裡,如有問題,歡迎指正,謝謝。