Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go1.21から導入された Go Toolchainの仕組みをまるっと解説

Go1.21から導入された Go Toolchainの仕組みをまるっと解説

2023/8/9にリリースされたGo1.21
新たに導入されたツールチェーン(Go Toolchains)

次の内容を知ってもらい、Toolchainを使いこなせるようになること
・導入が必要となった背景
・導入で期待されること
・具体的にはどう使うのか
・どんな挙動なのか

Takahito Yamatoya

June 07, 2024
Tweet

More Decks by Takahito Yamatoya

Other Decks in Technology

Transcript

  1. toolchainによって誤解を現実にする
 go.modファイルのgo directiveの仕様が直感的に期待する
 挙動ではなかった
 
 前方互換性を向上させる
 古いGo Toolchainが新しいGoのビルドを試み無いようにする
 何故、Go Toolchainが

    導入されることになったのか? 参考:
 disucussion : extending Go forward compatibility #55092 
 issue : extended forwards compatibility for Go #57001 
 Proposal: Extended forwards compatibility in Go 
 Doc: Go Toolchains

  2. Go 1.21より前のgo.modのgo directiveの意味 Go 1.12がインストールされている場合 go.modファイル: 「go 1.14」と記載されている go 1.12でコンパイルを試す

    go 1.12までの機能しか使用していない場合は、 コンパイルが成功し正常終了する func main() { print("Hello, World!") }
  3. Go 1.21より前のgo.modのgo directiveの意味 Go 1.13で搭載された 8進数リテラルのための 0o777構文を例にみていく dst, err :=

    os.OpenFile( testGo, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o777) if err != nil { log.Fatal(err) Go 1.13で実装されたので、 Go 1.12は解釈できない
  4. Go 1.21より前のgo.modのgo directiveの意味 Go 1.12がインストールされている場合 go.modファイル: 「go 1.14」と記載されている go 1.12でコンパイルを試す

    エラーだったら、「go. 1.14」が必要というエラーが表示される % go version go version go1.12.17 darwin/amd64 % go build . ./main.go:25:71: syntax error: unexpected o777, expecting comma or ) note: module requires Go 1.14
  5. Go 1.21より前のgo.modのgo directiveの意味 Go 1.12がインストールされている場合 go.modファイル: 「go 1.16」と記載されている go 1.12でコンパイルを試す

    エラーだったら、「go. 1.16」が必要というエラーが表示される % go version go version go1.12.17 darwin/amd64 % go build . ./main.go:25:71: syntax error: unexpected o777, expecting comma or ) note: module requires Go 1.16
  6. Go 1.21より前のgo.modのgo directiveの意味 Go 1.12がインストールされている場合 go 1.14とgo.modに書いている場合は「note: module requires Go

    1.14」 というエラーが表示される。 go 1.16とgo.modに書いている場合は「note: module requires Go 1.16」 というエラーが表示される。 このエラーが出ると、go.modみますよね? そして「go1.14」や[go1.16」をみて、何故てなりますよね? このエラーの理由は、 ローカルにインストールされている Goのバージョンが低い から。 go.modの設定がおかしいからではないが理解しにくいエラー表記となる。 本当に必要なのは、0o777構文に対応したGo 1.13以上のGo。
  7. Go 1.21より前のgo.modのgo directiveの意味 Go 1.16がインストールされている場合 go.modファイル: 「go 1.12」と記載されている go 1.12でコンパイルを試す

    エラーだったら、「go. 1.13以降」が必要というエラーが表示される % go version  go version go1.16.15 darwin/arm64 % go build .  ./main.go:25:70: 0o/0O-style octal literals requires go1.13 or later (-lang was set to go1.12; check go.mod) Go 1.16は、 go.modで記載されている Go 1.12の言語セマンティクスで解析 してBuildをするので エラーとなる
  8. Go 1.19.4にバグが入り込んだ。
 atomic.Pointer[T]を使用しているとコンパイルエラーになる問題
 https://github.com/golang/go/issues/57124
 Go 1.19.3とGo1.19.5であれば問題が発生しない。
 ※ BackPortされているので、現在ダウンロードできるGo1.19.4では問題は再現しない 
 go

    1.21より前のバージョンでは、
 特定のバージョンのGoでビルドを強制できない。
 Go 1.19.4でBuildするとエラーになる。
 
 Go 1.19.3かGo 1.19.5でBuildをして欲しいのだけど、
 これをgo.modで表現することができなかった 。
 
 Go 1.21より前のgo.modのgo directiveの意味 辛いケース事例の紹介 06:00

  9. goコマンドは、GOTOOLCHAIN設定に基づいて使用するGoツールチェインを選択する。 
 任意のGo環境設定に対する標準ルールを使用する。 
 プロセス環境(os.Getenvで参照)
  GOTOOLCHAINが空でない値に設定されている場合、その値を使用する。 
 ユーザー環境のデフォルトファイル
  go env

    -w / go env -u で管理される 
  GOTOOLCHAINが空でない値に設定されている場合、その値を使用する。 
 バンドルされたGoツールチェインの環境デフォルトファイル 
  バンドルされた$GOROOT/go.env でGOTOOLCHAINが設定されている場合、その値を使用する。 
  標準では、GOOTOLCAHIN=autoを設定します。 
 
 
 GOTOOLCHAIN設定場所 % go env GOTOOLCHAIN auto GOTOOLCHAIN設定の確認 12:00

  10. local : 常にバンドルされたGoツールチェーンを使用する
 <name>  :特定のGoツールチェーン名で指定されたバージョンを使用する
       例:go1.21.0
       PATHを探して無ければダウンロードして実行する
 <name>+auto :必要に応じて新しいGoバージョンを選択して実行する。
         go

    directive/toolchain directiveの設定を参照する。無ければダウンロードする。
 <name>+path :必要に応じて新しいGoバージョンを選択して実行する。
         go directive/toolchain directiveの設定を参照する。PATHに無ければ停止する。
 auto :local+autoの略記
 path :path+autoの略記
 GOTOOLCHAINで設定できる値
  11. 
 
 
 
 
 
 
 
 
 GOTOOLCHAIN環境変数に最新のバージョンとautoを指定できる

    
 常に最新の Goを使いたい場合 % export GOTOOLCHAIN=`curl -s -L "https://go.dev/VERSION?m=text" | head -n 1`+auto % print $GOTOOLCHAIN go1.22.4+auto % go version go: downloading go1.22.4 (darwin/amd64) go version go1.22.4 darwin/amd64 14:00

  12. go.modのtoolchain directiveの意味 Go 1.21.3がインストールされている場合 go.modファイル: go 1.21.1 toolchain go1.22.1  ローカルのgo

    1.21.3 を使わずにgo 1.22.1を使用する  PATHを探して、なければダウンロードしてキャッシュして使用する % go build . go: downloading go1.22.1 (darwin/amd64)
  13. Go 1.21以降のgo.modのgo directiveの意味 Go 1.21.3がインストールされている場合 go.modファイル: 「go 1.21.7」と記載されている  go 1.21.3 を使わずにgo

    1.21.7を使用する  PATHを探して、なければダウンロードしてキャッシュして使用する % go build . go: downloading go1.21.7 (darwin/amd64) // go.mod にgo1.21.9を記載(資料作成時には未リリースのバージョン % go build . go: downloading go1.21.9 (darwin/amd64) go: download go1.21.9 for darwin/amd64: toolchain not available
  14. go get toolchain@version % go get [email protected] go: upgraded toolchain

    go1.21.2 => go1.22.1 go.modファイル: go 1.21.1 toolchain go1.21.2 go.1.22.1をダウンロードしキャッシュし、 go.modのtoolchain directiveを更新する。 17:00

  15. go getでGoライブラリのインポートの時の挙動 % go get github.com/yamatoya/test-go1.21.7 go: github.com/yamatoya/[email protected] requires go

    >= 1.21.7; switching to go1.21.11 go: downloading go1.21.11 (darwin/amd64) go: upgraded go 1.21.4 => 1.21.7 go: added toolchain go1.21.11 go: added github.com/yamatoya/test-go1.21.7 v0.0.1 go.modファイル: go 1.21.4 go.modでgo1.21.7を宣言しているライブラリをgo getする
  16. go getでGoライブラリのインポートの時の挙動 go: github.com/yamatoya/[email protected] requires go >= 1.21.7; switching to

    go1.21.11 go: downloading go1.21.11 (darwin/amd64) go: upgraded go 1.21.4 => 1.21.7 go: added toolchain go1.21.11 go 1.21.7以降を必要とする 3つの利用候補から最小のバージョンを選択 する go directiveが1.21.7に更新される
  17. goコマンドは実行ツールチェーンを決定するために
 利用可能なリストを取得する
 https://golang.org/dl/?mode=json&include=all 
 リストから最大で3つの候補を抽出します
 • リリースされていないバージョンの最新のリリース候補 1.N₃rcR₃
 • 最新のリリースされたバージョンの最新パッチリリース

    1.N₂.P₂
 • 直前のバージョンの最新のパッチリリース 1.N₁.P₁
 要件を満たす最小バージョンの候補を保守的に選択する
 go1.21.7を必要としていて、go1.21.11がリリースされている場合に
 go1.21.11を選択する
 3つの利用候補
  18. 1.21より前のバージョン遷移 
  1.20rc1 < 1.20rc2 < 1.20rc3 < 1.20 <

    1.20.1
  以前のバージョンには、1.18beta2のようばベータリリースがあった。 
  1.18beta1 < 1.18beta2 < 1.18rc1 < 1.18 < 1.18.1 
 1.21以降のバージョン遷移 
  1.21 < 1.21rc1 < 1.21rc2 < 1.21.0 < 1.21.1
  Go 1.N のリリース候補は、1.N.0 の前に発行され1.NrcN(1.21rc1 / 1.21rc2….)を使用します。 
  最初のリリース候補は、1.Nrc1 
  初回リリースは1.Nだったが、 Go 1.21から1.N.0 となった。
 Goのバージョン定義まとめ
  19. Go1.19.13 / Go1.20.8
 Go1.22でloopの意味が変わる可能性があります。 
 Go 1.22向けに書かれたコードをビルドしようとすると、 
 本来発生すべきでないエイリアシングのバグが発生する可能性があります。 


    go.dev/issue/60078を参照してください。 
 サポート終了後の古いGoツールチェーンの誤用や間違いをいくつか捕捉するためにチェックが追 加された
 
 過去のバージョンでの強制的要件
  20. Go1.19.13でのバージョンブロッカー if p.Module != nil && !(allowedVersion(p.Module.GoVersion) || p.Module.GoVersion ==

    "1.20" || p.Module.GoVersion == "1.21") { return errors.New("cannot compile Go " + p.Module.GoVersion + " code") }
  21. Go1.20.8でのバージョンブロッカー if p.Module != nil && !(allowedVersion(p.Module.GoVersion) || p.Module.GoVersion ==

    "1.20" || p.Module.GoVersion == "1.21") { return errors.New("cannot compile Go " + p.Module.GoVersion + " code") }