欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go中的交叉編譯問題

 更新時間:2023年11月22日 14:49:38   作者:機(jī)器鈴砍菜刀  
這篇文章主要介紹了Go中的交叉編譯問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

交叉編譯是指在一個硬件平臺生成另一個硬件平臺的可執(zhí)行文件。而Go提供了非常方便的交叉編譯方式。

如何編譯

Go交叉編譯,涉及到幾個環(huán)境變量的設(shè)置: GOARCH、GOOS和CGO_ENABLED。

  • GOARCH:編譯目標(biāo)平臺的硬件體系架構(gòu)(amd64, 386, arm, ppc64等)。
  • GOOS:編譯目標(biāo)平臺上的操作系統(tǒng)(darwin, freebsd, linux, windows)。
  • CGO_ENABLED:代表是否開啟CGO,1表示開啟,0表示禁用。由于CGO不能支持交叉編譯,所以需要禁用。

GO中env的具體環(huán)境變量的注釋,可通過輸入命令go help environment查看。

 ~ $ go help environment
...
  GOARCH
    The architecture, or processor, for which to compile code.
    Examples are amd64, 386, arm, ppc64.
...
  GOOS
    The operating system for which to compile code.
    Examples are linux, darwin, windows, netbsd.
...
  CGO_ENABLED
    Whether the cgo command is supported. Either 0 or 1.

Mac 下編譯 Linux 和 Windows 64位可執(zhí)行程序

export CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
export CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go

Linux 下編譯 Mac 和 Windows 64位可執(zhí)行程序

export CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go
export CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go

Windows 下編譯 Mac 和 Linux 64位可執(zhí)行程序

SET CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go
SET CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go

其他平臺或32位系統(tǒng)類似,這里就不再贅述。

GO是如何做到交叉編譯?

Go交叉編譯的實現(xiàn)通過在文件頂部增加構(gòu)建標(biāo)記,進(jìn)行選擇編譯。

// +build

注:Go源碼里的編譯器源碼位于$GOROOT/src/cmd/compile路徑下,鏈接器源碼位于$GOROOT/src/link路徑下。

我們的切入點從Go編譯器的main函數(shù)為入口,代碼位于$GOROOT/src/cmd/compile/main.go。

以環(huán)境變量GOARCH為例,看一下Go編譯器是如何通過構(gòu)建標(biāo)記來選擇對應(yīng)的體系架構(gòu)目標(biāo)進(jìn)行編譯。

package main
?
// 引用了Go所能支持的所有架構(gòu)體系庫代碼,根據(jù)GOARCH選擇對應(yīng)的體系代碼
import (  
  "cmd/compile/internal/amd64"
  "cmd/compile/internal/arm"
  "cmd/compile/internal/arm64"
 ....
  "cmd/compile/internal/x86"
...
)
?
// 初始化代碼
var archInits = map[string]func(*gc.Arch){
  "386":      x86.Init,
  "amd64":    amd64.Init,
  "arm":      arm.Init,
  "arm64":    arm64.Init,
...
}
?
func main() {
  // disable timestamps for reproducible output
  log.SetFlags(0)
  log.SetPrefix("compile: ")
?
// 通過objabi.GOARCH選擇對應(yīng)的架構(gòu)體系
  archInit, ok := archInits[objabi.GOARCH]
...
  gc.Main(archInit)
...
}

objabi.GOARCH是$GOROOT/src/cmd/internal/objabi/util.go中的變量GOARCH。

var (
  defaultGOROOT string // set by linker
?
...
  GOROOT   = envOr("GOROOT", defaultGOROOT)
  GOARCH   = envOr("GOARCH", defaultGOARCH)
  GOOS     = envOr("GOOS", defaultGOOS)
...
)

defaultGOARCH是runtime包里的GOARCH值,如下所示。

// Code generated by go tool dist; DO NOT EDIT.
?
package objabi
?
import "runtime"
?
...
const defaultGOOS = runtime.GOOS
const defaultGOARCH = runtime.GOARCH
...

而該值又是通過sys.GOARCH賦值。$GOROOT/src/runtime/extern.go。

// GOARCH is the running program's architecture target:
// one of 386, amd64, arm, s390x, and so on.
const GOARCH string = sys.GOARCH

終于來到了重點!$GOROOT/src/runtime/internal/sys/agoarch_amd64.go

// Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
?
// 我的機(jī)器平臺是amd64,且未對GOARCH的值做修改。因此這里的構(gòu)建標(biāo)簽是amd64.
// +build amd64
?
package sys
?
const GOARCH = `amd64`

通過構(gòu)建amd64的編譯標(biāo)簽,從而控制了Go編譯時需要選擇對應(yīng)的架構(gòu)代碼。即:如果不是amd64,例如arm,那對應(yīng)的編譯代碼就是$GOROOT/src/runtime/internal/sys/agoarch_arm.go。

如何利用交叉編譯?

雖然golang 可以跨平臺編譯,但卻無法解決系統(tǒng)的差異性。在靠近底層邏輯的項目中,我們需要直接調(diào)用操作系統(tǒng)函數(shù),例如同樣是實現(xiàn)IO多路服用,在darwin系統(tǒng)調(diào)用kqueue,而linux系統(tǒng)需調(diào)用epoll。

相同功能可以編寫類似xxx_windows.go xxx.Linux.go文件,根據(jù)操作系統(tǒng)編譯對應(yīng)源文件,而不是在文件中用if else規(guī)劃執(zhí)行路徑。

交叉編譯同樣可以理解為條件編譯,通過構(gòu)建的build標(biāo)簽,選擇需要編譯進(jìn)最終執(zhí)行二進(jìn)制文件的代碼。

這里給一個簡單的條件編譯示例,如下。

代碼文件

  • go.mod
  • main.go
  • myfunc.go

main.go:程序入口,調(diào)用位于myfunc.go中的speak函數(shù)。

package main
?
import "fmt"
?
func main() {
  fmt.Println("mike")
  speak("hello")
}

myfunc.go: 構(gòu)建了build標(biāo)簽,需要build命令 帶上-tag speak,該代碼才能被編譯。

//+build speak
?
package main
?
func speak(s string) {
  println("speak:", s)
}

執(zhí)行命令

$ go build -o main
$ ./main

輸出

mike

可以看到,在main函數(shù)中的speak()函數(shù)并沒有被執(zhí)行,因為myfunc.go沒有被編譯。

如果需要將myfunc.go編譯進(jìn)最終的執(zhí)行代碼,則執(zhí)行命令

$ go build -tags speak -o main
$ ./main

輸出

$ mike
$ speak: hello

上述條件編譯示例對你是否有啟發(fā)呢?

舉例:

項目開發(fā)中,如果想打印程序中的某些信息以便調(diào)試,而又不想打印相關(guān)代碼生成到最終的可執(zhí)行文件中,那么條件編譯便可派上用場。

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Golan中?new()?、?make()?和簡短聲明符的區(qū)別和使用

    Golan中?new()?、?make()?和簡短聲明符的區(qū)別和使用

    Go語言中的new()、make()和簡短聲明符的區(qū)別和使用,new()用于分配內(nèi)存并返回指針,make()用于初始化切片、映射和通道,并返回初始化后的對象,簡短聲明符:=可以簡化變量聲明和初始化過程,感興趣的朋友一起看看吧
    2025-01-01
  • Go常問的一些面試題匯總(附答案)

    Go常問的一些面試題匯總(附答案)

    通常我們?nèi)ッ嬖嚳隙〞行┎诲e的Golang的面試題目的,所以總結(jié)下,讓其他Golang開發(fā)者也可以查看到,同時也用來檢測自己的能力和提醒自己的不足之處,這篇文章主要給大家介紹了關(guān)于Go常問的一些面試題以及答案的相關(guān)資料,需要的朋友可以參考下
    2023-10-10
  • go 異常處理panic和recover的簡單實踐

    go 異常處理panic和recover的簡單實踐

    在Go語言中,異常處理主要通過panic和recover這兩個內(nèi)建函數(shù)來實現(xiàn),本文主要介紹了go異常處理panic和recover的簡單實踐,具有一定的參考價值,感興趣的可以了解一下
    2025-04-04
  • Golang?HTTP服務(wù)超時控制實現(xiàn)原理分析

    Golang?HTTP服務(wù)超時控制實現(xiàn)原理分析

    這篇文章主要介紹了Golang?HTTP服務(wù)超時控制實現(xiàn)原理,HTTP服務(wù)的超時控制是保障服務(wù)高可用性的重要措施之一,由于HTTP服務(wù)可能會遇到網(wǎng)絡(luò)延遲,資源瓶頸等問題,因此需要對請求進(jìn)行超時控制,以避免服務(wù)雪崩等問題,需要的朋友可以參考下
    2023-05-05
  • 詳解golang中Context超時控制與原理

    詳解golang中Context超時控制與原理

    Context本身的含義是上下文,我們可以理解為它內(nèi)部攜帶了超時信息、退出信號,以及其他一些上下文相關(guān)的值,本文給大家詳細(xì)介紹了golang中Context超時控制與原理,文中有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下
    2024-01-01
  • Go 語言中的指針的使用

    Go 語言中的指針的使用

    在Go語言中,指針是存儲另一變量內(nèi)存地址的變量,通過&操作符獲取變量地址,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-09-09
  • Golang使用channel實現(xiàn)一個優(yōu)雅退出功能

    Golang使用channel實現(xiàn)一個優(yōu)雅退出功能

    最近補(bǔ)?Golang?channel?方面八股的時候發(fā)現(xiàn)用?channel?實現(xiàn)一個優(yōu)雅退出功能好像不是很難,之前寫的?HTTP?框架剛好也不支持優(yōu)雅退出功能,于是就參考了?Hertz?優(yōu)雅退出方面的代碼,為我的?PIANO?補(bǔ)足了這個?feature
    2023-03-03
  • Go語言學(xué)習(xí)之映射(map)的用法詳解

    Go語言學(xué)習(xí)之映射(map)的用法詳解

    Map是一種無序的鍵值對的集合。這篇文章主要為大家詳細(xì)介紹了Go語言中映射的用法,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Go語言有一定的幫助,需要的可以參考一下
    2022-04-04
  • Go?項目目錄布局保姆級教程

    Go?項目目錄布局保姆級教程

    這篇文章主要為大家介紹了Go?項目目錄布局保姆級教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • go?logger不侵入業(yè)務(wù)代碼使用slog替換zap并實現(xiàn)callerSkip詳解

    go?logger不侵入業(yè)務(wù)代碼使用slog替換zap并實現(xiàn)callerSkip詳解

    這篇文章主要為大家介紹了go?logger不侵入業(yè)務(wù)代碼使用slog替換zap并實現(xiàn)callerSkip詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09

最新評論