這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。在這系列的第五篇文章,我們將討論 Go 項目的跨平台編譯.在閱讀這篇文章之前,請確保你已經閱讀了[上一篇](https://studygolang.com/articles/12615)關於“Time包以及重載”的文章,或者訂閱我們的部落格更新提醒來擷取此六部曲後續文章的音訊。- [Golang 之於 DevOps 開發的利與弊(六部曲之一):Goroutines, Channels, Panics, 和 Errors](https://studygolang.com/articles/11983)- [Golang 之於 DevOps 開發的利與弊(六部曲之二):介面實現的自動化和公有/私人實現](https://studygolang.com/articles/12608)- [Golang 之於 DevOps 開發的利與弊(六部曲之三):速度 vs. 缺少泛型](https://studygolang.com/articles/12614)- [Golang 之於 DevOps 開發的利與弊(六部曲之四):time 包和方法重載](https://studygolang.com/articles/12615)- [Golang 之於 DevOps 開發的利與弊(六部曲之五):跨平台編譯,Windows,Signals,Docs 以及編譯器](https://studygolang.com/articles/12616)- Golang 之於 DevOps 開發的利與弊(六部曲之六):Defer 指令和包依賴性的版本控制## Golang 之利: 在 Linux 下編譯 Windows 程式對於我這類主要使用 Linux 的人來說,我對於偶爾不得不去應付 Windows 下的問題感到十分的痛苦。這句話在我寫我們的 [Smart Agent](https://www.bluematador.com/smart-agent) 的時候顯得格外正確,它能同時跑在 Linux 和 Windows 上,並且會為了我們的日誌管理及監視軟體去深入探究這兩個系統的底層相關問題。因為我們的 agent 是用 Golang 寫的,在 Linux 環境下把代碼編譯成能在 Windows 跑的程式是十分輕鬆的。大部分的工作是由兩個運行 `go build` 命令時的傳入參數:GOARCH 和 GOOS 所完成的.![](https://raw.githubusercontent.com/studygolang/gctt-images/master/go_devops/goos-meme.jpg)你可以運行 `go tool dist list` 去查看這兩個參數所有的組合,在 Go 1.8 下一共有 38 種組合。以下的例子展示了如何在 AMD64 和 Intel i386 架構下編譯適用於 Linux 和 Windows 的程式,而且你可以輕鬆看到如何建立一個 `Makefile` 來輕易地為各種不同的系統構建程式。```bashGOOS=linux GOARCH=amd64 go build -o bin/myapp_linux_amd64 myappGOOS=windows GOARCH=amd64 go build -o bin/myapp_windows_amd64 myappGOOS=linux GOARCH=386 go build -o bin/myapp_linux_386 myapp```## Cgo如果你的項目使用 [cgo](https://golang.org/cmd/cgo/),你可能會有點小麻煩。要讓 cgo 程式碼完成跨平台編譯,你需要在編譯環境上安裝正確的工具鏈。儘管現在距離我上次去直面 gcc 已經有好一段時間了,但是在 Unbuntu 16.04 的機器上找到正確的命令去安裝這個工具鏈還是很容易的。以下是一些配置你的 cgo 編譯環境的 one-liners:```bash# Install cgo dependenciesapt-get install -y gcc libsystemd-dev gcc-multilib# cgo for linux/386apt-get install -y libc6-dev-i386# cgo for windowsapt-get install -y gcc-mingw-w64```隨之改變的編譯指令如下:```bashCGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC=gcc go build -o bin/myapp_linux_amd64 myappCGO_ENABLED=1 GOOS=windows GOARCH=amd64 CXX=x86_64-w64-mingw32-g++ CC=x86_64-w64-mingw32-gcc go build -o bin/myapp_windows_amd64 myappCGO_ENABLED=1 GOOS=linux GOARCH=386 CC=gcc go build -o bin/myapp_linux_386 myapp```## Golang 之弊: 關於 Windows 部分的官方文檔Golang 的官方文檔網站做得非常好。在上面有很多實用的例子,原始碼的連結,當然還有測試小段代碼的 playground。但是,golang 官方文檔的一個缺陷會在你使用一些在 Windows 下有不同行為的代碼時顯現。有些頁面,比如 [os](https://golang.org/pkg/os/),就在解釋很多函數在 Unix 和 Windows 系統下的區別這點上做得非常好。但我很好奇的是,他們為什麼在 Windows 下的標準庫包括類似於 [Getegid](https://golang.org/pkg/os/#Getegid) 這樣的函數的同時寫下了類似於以下的注釋: ```Getegid 返回 caller 有效 group id.在 Windows 下,該函數返回 -1.```與其讓我去搞清楚在 Windows 下這個傳回值毫無意義,我寧願編譯器在發現目標系統是 Windows 之後會自動編譯失敗,不然這個函數其實什麼都沒做。其他的這類關於 Windows 的頁面完完全全就是一些空洞無用的語句,比如 [exec](https://golang.org/pkg/os/exec/) 頁面: ```注意這個包裡的例子只適用於 Unix 系統。它們不能在 Windows 和 golang.org 以及 godoc.org 的 Go Playground 下運行。```## Golang 之弊: 開發人員社區第三方包的 Windows 相容性只有在當你在 Unix 系統下完成了某個功能的開發之後,你會因為可以輕易跨平台編譯而去嘗試編譯 Windows 程式之時,這個缺點才會顯現。以前有幾次我用了一些開源庫去開發一個針對 Linux 系統的功能時,我意外地搞砸了 Windows 的程式 - 因為這些庫使用了一些 Unix 特有的調用。以下是兩個相對簡單的解決方案:### 1.為開源社區做貢獻如果你有時間並且想給這些項目做些貢獻,建立一個支援 Windows 的 PR! 注意: 取決於你的開發環境,這個可能非常耗時,因為儘管編譯 Windows 程式很容易,但是測試它們並不簡單。### 2.使用 Build Constraints在 Golang 裡,使用 [build constraints](https://golang.org/pkg/go/build/#hdr-Build_Constraints) 在編譯時間排除或者包含各種檔案非常容易。例如,在一份僅為了 NT 編譯的代碼檔案中去包含一個只支援 Windows 的依賴,你只需要這麼做: ```go// +build windowspackage mypackageimport "github.com/bluematador/windows-only"```你也可以反著來 - 排除不支援的 GOOS:```golang// +build !windowspackage mypackageimport "github.com/bluematador/linux-only"```這很棒的一點是,它讓你更多地去理清你的代碼,並讓你可以通過源碼中的 build constraints 擁有一個能在兩個系統下都能調用但行為不同的函數。
via: https://blog.bluematador.com/golang-pros-cons-part-5-cross-platform-compiling
作者:Matthew Barlocker 譯者:p31d3ng 校對:polaris1119
本文由 GCTT 原創編譯,Go語言中文網 榮譽推出
本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻嗎?歡迎加入 GCTT!
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯絡我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在本文中標註並保留原文/譯文連結和作者/譯者等資訊。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽
487 次點擊