編譯過程
預(yù)處理 -> 編譯 -> 匯編 -> 鏈接
預(yù)處理
- 完成宏替換、文件引入,去除空行、注釋等。
- 針對預(yù)處理命令進(jìn)行處理,頭文件包含、宏定義擴(kuò)展、條件編譯的選擇等。
# test.c
#include <stdio.h>
int main(){
printf("hello world!\n");
return 0;
}
------------------------------------------------
$ gcc -E test.c -o test.i
- -E: 讓gcc在預(yù)處理結(jié)束后停止編譯,test.i文件為預(yù)處理后的文件
- -o: 指定輸出文件
編譯
這里的編譯不是指程序從源文件到二進(jìn)制程序的全部過程,而是指將經(jīng)過預(yù)處理之后的程序轉(zhuǎn)換成特定匯編代碼(assembly code)的過程。
$ gcc -S test.i -o test.s
匯編
將上一步的匯編代碼轉(zhuǎn)換成機(jī)器碼(machine code),這一步產(chǎn)生的文件叫做目標(biāo)文件,是二進(jìn)制格式。
$ gcc -c test.s -o test.o
鏈接
鏈接過程將多個目標(biāo)文以及所需的庫文件(.so等)鏈接成最終的可執(zhí)行文件
$ gcc test.o -o test
$ ./test
更詳細(xì)的內(nèi)容可以參考:https://www.cnblogs.com/CarpenterLee/p/5994681.html#top
生成靜態(tài)庫
- 首先生成test.o目標(biāo)文件
- 使用ar命令將test.o打包成libtest.a靜態(tài)庫
# 首先生成目標(biāo)文件
$ gcc -c test.c -o test.o
# 使用ar命令將目標(biāo)文件打包成靜態(tài)庫
$ ar rcs libtest.a test.o
# 使用ar t libtest.a 查看靜態(tài)庫內(nèi)容
$ ar t libtest.a
test.o
生成動態(tài)庫
- 首先生成test.o目標(biāo)文件。
- 使用-shared和-fPIC參數(shù)生成動態(tài)庫
# 首先生成目標(biāo)文件
$ gcc -c test.c
# 使用-fPIC和-shared生成動態(tài)庫
$ gcc -shared -fPIC -o libtest.so test.o
例子
tool.h
int find_max(int arr[], int n);
tool.c
#include "tool.h"
int find_max(int arr[], int n){
int max = arr[0];
int i;
for(i = 0; i < n; i++){
if(arr[i] > max){
max = arr[i];
}
}
return max;
}
main.c
#include <stdio.h>
#include "tool.h"
int main(){
int arr[] = {1,3,5,8,2};
int max = find_max(arr, 5);
printf(" max = %d\n", max);
return 0;
}
編譯靜態(tài)庫
- 編譯目標(biāo)文件
$ gcc -c tool.c
,省略-o默認(rèn)生成同名文件 - 編譯靜態(tài)庫文件
ar rcs libtool.a tool.o
- 編譯可執(zhí)行文件&鏈接靜態(tài)庫
gcc -o main main.c -L. -ltool
-L: 查詢庫路徑
-l: 需要鏈接的庫 - 執(zhí)行
./main
編譯動態(tài)庫
$ gcc -shared -fPIC -o libtool.so tool.c
$ gcc -o main -L. -ltool main.c
$ ./main
ps
- 靜態(tài)庫和動態(tài)庫同名時,系統(tǒng)會優(yōu)先鏈接動態(tài)庫。
- 查看文件詳情
ls -lh
- 查看鏈接庫詳情
linuxldd main
macOx 動態(tài)庫:otool -L main
,靜態(tài)庫nm main
靜態(tài)庫與動態(tài)庫區(qū)別
-
靜態(tài)庫
在程序編譯時會鏈接到目標(biāo)代碼中,程序運(yùn)行時不在需要靜態(tài)庫,因此體積較大。每次編譯都需要載入靜態(tài)代碼,因此內(nèi)存開銷大。 -
動態(tài)庫
在程序編譯時不會被鏈接到目標(biāo)代碼中,而是在程序運(yùn)行時才被載入,程序運(yùn)行時需要動態(tài)庫存在,因此體積較小。而且系統(tǒng)只需載入一次動態(tài)庫,不同程序可以得到內(nèi)存中相同的動態(tài)庫副本,因此內(nèi)存開銷小。