本文主要針對gcc編譯器,也就是針對c和c++,不一定適用於其他語言的編譯。原始碼要執行,必須先轉成二進位制的機器碼原作者
#include
int main(void)
確定編譯引數的步驟,就叫做」配置」(configure)。
為什麼確定編譯引數?
編譯器在開始工作之前,需要知道當前的系統環境
標準庫在**
軟體的安裝位置在**
需要安裝哪些元件
怎麼配置
配置資訊儲存在乙個配置檔案之中,叫做configure的指令碼檔案
,由autoconf工具生成的。編譯器通過執行
這個指令碼,獲知編譯引數。
原始碼肯定會用到標準庫函式(standard library)和標頭檔案(header),存放在系統的任意目錄
編譯器從配置檔案中知道標準庫和標頭檔案的位置
原始碼檔案之間往往存在依賴關係,編譯器需要確定編譯的先後順序
編譯順序儲存在乙個叫做makefile的檔案中
makefile
儲存編譯順序–>列出哪個檔案先編譯,哪個檔案後編譯
由configure指令碼執行生成–>為什麼編譯時configure必須首先執行的原因
不同的原始碼檔案,可能引用同乙個標頭檔案(比如stdio.h)
編譯的時候,標頭檔案也必須一起編譯
編譯器會在編譯原始碼之前,先編譯標頭檔案—>保證了標頭檔案只需編譯一次
宣告巨集的#define命令,就不會被預編譯。
預編譯完成後,編譯器就開始替換掉原始碼中bash的標頭檔案和巨集
例如:
extern
intfputs(const
char *, file *);
extern file *stdout;
int main(void)
有所忽略,只擷取了fputs和file的宣告
上面**的標頭檔案沒有經過預編譯,而實際上,插入原始碼的是預編譯後的結果。編譯器在這一步還會移除注釋。
完成之後,就要開始真正的處理了。
預處理之後,編譯器就開始生成機器碼
某些編譯器來說,還存在乙個中間步驟,會先把原始碼轉為彙編碼
(assembly)然後再把彙編碼轉為機器碼
。
.file "test.c"
.section .rodata
.lc0:
.string
"hello, world!\n"
.text
.globl main
.type main, @function
main:
.lfb0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq stdout(%rip), %rax
movq %rax, %rcx
movl $14, %edx
movl $1, %esi
movl $.lc0, %edi
call fwrite
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret.cfi_endproc
.lfe0:
.size main, .-main
.ident "gcc: (debian 4.9.1-19) 4.9.1"
.section .note.gnu-stack,"",@progbits
種轉碼後的檔案稱為物件檔案(object file)
編譯器在記憶體中生成了可執行檔案
物件檔案還不能執行,必須進一步轉成可執行檔案
。
轉碼結果,會發現其中引用了stdout函式和fwrite函式
程式要正常執行,還必須有stdout和fwrite這兩個函式的**,c語言的標準庫提供
編譯器的下一步工作,就是把外部函式的**(通常是字尾名為.lib和.a的檔案),新增到可執行檔案中。這就叫做連線(linking)。
這種通過拷貝,將外部函式庫新增到可執行檔案的方式,叫做靜態連線
,後文會提到還有動態連線(dynamic linking)
。
make命令的作用,就是從第四步標頭檔案預編譯開始,一直到做完這一步。連線是在記憶體中進行的,編譯器在記憶體中生成了可執行檔案
下一步,必須將可執行檔案儲存到
使用者事先指定的安裝目錄
這一步還必須完成建立目錄
、儲存檔案
、設定許可權
等步驟。這整個的儲存過程就稱為"安裝"
(installation)。
開發者可以在編譯階段選擇可執行檔案連線外部函式庫的方式
,到底是靜態連線(編譯時連線),還是動態連線(執行時連線)
靜態連線
就是把外部函式庫,拷貝到可執行檔案中
好處是:
適用範圍比較廣,不用擔心使用者機器缺少某個庫檔案
缺點是:
安裝包會比較大,而且多個應用程式之間,無法共享庫檔案
動態連線
外部函式庫不進入安裝包,只在執行時動態引用
好處是:
安裝包會比較小,多個應用程式可以共享庫檔案
缺點是:
使用者必須事先安裝好庫檔案,而且版本和安裝位置都必須符合要求,否則就不能正常執行。
現實中,大部分軟體採用動態連線,共享庫檔案。這種動態共享的庫檔案,linux平台是字尾名為.so的檔案,windows平台是.dll檔案,mac平台是.dylib檔案。
編譯器工作過程
原始碼要執行,必須先轉成二進位制的機器碼。這是編譯器的任務。比如,下面這段原始碼 假定檔名叫做test.c 要先用編譯器處理一下,才能執行。這些命令到底在幹什麼?大多數的書籍和資料,都語焉不詳,只說這樣就可以編譯了,沒有進一步的解釋。本文將介紹編譯器的工作過程,也就是上面這三個命令各自的任務。我主要...
編譯器的工作過程
日期 2014年11月11日 原始碼要執行,必須先轉成二進位制的機器碼。這是編譯器的任務。比如,下面這段原始碼 假定檔名叫做test.c include int main void 要先用編譯器處理一下,才能執行。gcc test.c a.out hello,world 對於複雜的專案,編譯過程還必...
編譯器的工作過程
日期 2014年11月11日 原始碼要執行,必須先轉成二進位制的機器碼。這是編譯器的任務。比如,下面這段原始碼 假定檔名叫做test.c include int main void 要先用編譯器處理一下,才能執行。gcc test.c a.out hello,world 對於複雜的專案,編譯過程還必...