官术网_书友最值得收藏!

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ò)程。

主站蜘蛛池模板: 临洮县| 清苑县| 黎川县| 东方市| 砚山县| 句容市| 徐州市| 舟山市| 布尔津县| 闽侯县| 那坡县| 察隅县| 望都县| 思南县| 衡阳市| 全椒县| 肥乡县| 舒城县| 海城市| 博野县| 博白县| 连州市| 尚志市| 郴州市| 灌南县| 黔西| 云梦县| 额尔古纳市| 静宁县| 浦城县| 特克斯县| 连江县| 临海市| 红安县| 九寨沟县| 锦州市| 崇明县| 广德县| 苍南县| 雷州市| 阿拉尔市|