- 深入淺出Go語(yǔ)言核心編程
- 張朝明 李奕鋒 甘海彬
- 1417字
- 2024-12-24 10:23:11
1.6 探尋Go語(yǔ)言程序的編譯執(zhí)行過(guò)程
無(wú)論是通過(guò)go build命令運(yùn)行,還是通過(guò)IDE直接運(yùn)行,其實(shí)都是封裝了一系列編譯執(zhí)行的操作,這為程序員的開發(fā)提供了很多便利。但是,Go語(yǔ)言的具體編譯執(zhí)行過(guò)程還是值得我們探究一下,以更好地理解Go語(yǔ)言相對(duì)于其他語(yǔ)言的特點(diǎn)。
1.6.1 go build命令的選項(xiàng)
在Linux/Windows/macOS中,大多數(shù)命令都有多種選項(xiàng),這些選項(xiàng)可以實(shí)現(xiàn)命令的個(gè)性化需求。我們可以利用go help build來(lái)查看go build命令的選項(xiàng),具體的命令及輸出如下:

可以看到,go build的選項(xiàng)非常多,其中有3個(gè)需要我們特別關(guān)注:
· -n:打印編譯的詳細(xì)過(guò)程,但是并不實(shí)際執(zhí)行,相當(dāng)于預(yù)覽功能。
· -x:執(zhí)行編譯,同時(shí)也打印編譯的詳細(xì)過(guò)程。
· --work:這是一個(gè)追加選項(xiàng),在go build的編譯過(guò)程中會(huì)生成部分中間目錄和文件,編譯結(jié)束后,會(huì)將生成的臨時(shí)目錄和文件刪除,--work用于保留生成的臨時(shí)目錄和文件,方便開發(fā)者查看和診斷問(wèn)題。
1.6.2 查看編譯的詳細(xì)過(guò)程
我們可以直接利用-x和--work選項(xiàng)來(lái)查看編譯的詳細(xì)過(guò)程,具體的命令及輸出如下:

從go build命令的輸出可以看出,該命令實(shí)際執(zhí)行了若干操作系統(tǒng)指令。各指令說(shuō)明如下:
(1)WORK=/var/folders/28/w3v87nrn6fsd06mkl9v21vnr0000gn/T/go-build3761933774:用于指定WORK變量的值。WORK就是go build的工作目錄,該目錄的前半部分“/var/folders/28/w3v87nrn6fsd06mkl9v21vnr0000gn/T”來(lái)源于操作系統(tǒng)的臨時(shí)目錄;后半部分“go-build3761933774”是編譯時(shí)自動(dòng)追加的子文件夾。在macOS中,操作系統(tǒng)臨時(shí)目錄利用變量$TMPDIR進(jìn)行定義;而在Windows操作系統(tǒng)中,該值來(lái)源于環(huán)境變量TMP。
(2)mkdir -p $WORK/b001/:用于遞歸創(chuàng)建工作目錄。它保證了工作目錄一定存在。
(3)cat >$WORK/b001/importcfg.link << 'EOF' # internal,以及其后的多條packagefile語(yǔ)句,直至EOF:用于生成名為importcfg.link的文件。最后,將所有需要鏈接的文件(.a文件)寫入importcfg.link中。
(4)mkdir -p $WORK/b001/exe/:用于在工作目錄下創(chuàng)建一個(gè)名為exe的文件夾,該文件夾用于存放生成的可執(zhí)行文件。
(5)/usr/local/go/pkg/tool/darwin_amd64/link -o $WORK/b001/exe/a.out -importcfg...:該指令執(zhí)行鏈接操作,并生成a.out文件。
(6)/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/exe/a.out:該指令用于更新a.out文件的build ID。-w選項(xiàng)代表要重寫a.out中的build ID。build ID是可執(zhí)行文件的獨(dú)一無(wú)二的身份標(biāo)識(shí)。
(7)mv $WORK/b001/exe/a.out first:將a.out重命名為first,first文件就是最終生成的可執(zhí)行文件。
1.6.3 鏈接環(huán)節(jié)
在上述go build的過(guò)程中,鏈接(link)環(huán)節(jié)尤其值得我們注意。所有的程序?qū)嶋H上都需要與外部其他程序(或代碼)進(jìn)行關(guān)聯(lián)和調(diào)用,被調(diào)用的代碼往往被稱為共享庫(kù)。例如,在Go語(yǔ)言程序中,往往需要引用Go語(yǔ)言內(nèi)置的函數(shù)。實(shí)際運(yùn)行時(shí),這些共享庫(kù)如何被我們的代碼調(diào)用就成為一個(gè)問(wèn)題。鏈接就是為所有相互調(diào)用的函數(shù)指定入口位置。
鏈接分為靜態(tài)鏈接和動(dòng)態(tài)鏈接。
· 靜態(tài)鏈接:將使用到的所有共享庫(kù)復(fù)制到最終的可執(zhí)行文件中。典型的輸出文件的形式是單個(gè)文件。
· 動(dòng)態(tài)鏈接:只將共享庫(kù)的地址編譯到最終的可執(zhí)行文件中。共享庫(kù)以獨(dú)立的文件存在,其最終表現(xiàn)形式往往是多個(gè)文件。例如,在Windows中的一個(gè)應(yīng)用程序,往往存在一個(gè).exe文件和多個(gè).dll文件。
因此,靜態(tài)鏈接最終的可執(zhí)行文件往往比較大,而動(dòng)態(tài)鏈接最終的可執(zhí)行文件比較小。當(dāng)然,這并不意味著二者有絕對(duì)的優(yōu)劣之分,只是不同的場(chǎng)合使用不同的鏈接方式。
Go語(yǔ)言在絕大多數(shù)情況下都使用靜態(tài)鏈接,這一點(diǎn)從前面的編譯過(guò)程也能看出來(lái)——最終文件是單一的、較大的可執(zhí)行文件。當(dāng)然,Go語(yǔ)言也支持動(dòng)態(tài)編譯,這是因?yàn)镚o語(yǔ)言也支持對(duì)于C語(yǔ)言程序的調(diào)用,而C語(yǔ)言程序往往以外部共享庫(kù)的形式存在。但在本章中,我們只討論常用的靜態(tài)鏈接場(chǎng)景。
在演示實(shí)例的鏈接環(huán)節(jié)中,我們可以看到link的完整命令為:

其中,命令選項(xiàng)-buildmode=exe指定構(gòu)建模式為exe。
我們可以通過(guò)go help build mode命令來(lái)查看構(gòu)建模式的詳細(xì)信息:

在其中找到buildmode=exe的解釋,可以看到,在該模式下會(huì)將main包以及所有導(dǎo)入包構(gòu)建為一個(gè)可執(zhí)行文件。這其實(shí)就是靜態(tài)鏈接的過(guò)程。
- Flask Blueprints
- Kibana Essentials
- Java入門經(jīng)典(第6版)
- Practical Internet of Things Security
- WSO2 Developer’s Guide
- Keras深度學(xué)習(xí)實(shí)戰(zhàn)
- Access 2010數(shù)據(jù)庫(kù)應(yīng)用技術(shù)實(shí)驗(yàn)指導(dǎo)與習(xí)題選解(第2版)
- 寫給程序員的Python教程
- OpenMP核心技術(shù)指南
- 深度學(xué)習(xí)程序設(shè)計(jì)實(shí)戰(zhàn)
- Java EE實(shí)用教程
- JBoss AS 7 Development
- HTML5程序開發(fā)范例寶典
- C#程序設(shè)計(jì)基礎(chǔ)與實(shí)踐
- SEO的藝術(shù)(原書第2版)