Skip to content

Commit 422f470

Browse files
committed
cmd/dist: set go version in bootstrap go.mod file
The commands to build the bootstrap toolchains and go commands are run from modules created by two bootstrap go.mod files: one is used when building toolchain1 and go_bootstrap, and the other is used for toolchain2 and toolchain3, and the final build. Currently the first has a go directive specifying go 1.20, and the second one does not have a go directive at all. This affects the default GODEBUG setting when building the final toolchain: the default GODEBUG value is based on the go version of the go.mod file, and when the go.mod file does not have a version it defaults to go1.16. We should set the go directive on the bootstrap used for the second half of the builds to use the current go verison from the std's go.mod file (which is the same as the version on cmd's go.mod file). The go.mod file used for the initial bootstrap should have a go directive with the minimum version of the toolchain required for bootstrapping. That version is the current version - 2 rounded down to an even number. For #64751 Fixes #68797 Change-Id: Ibdddf4bc36dc963291979d603c4f3fc55264f65b Reviewed-on: https://go-review.googlesource.com/c/go/+/604799 Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
1 parent c7faf7f commit 422f470

File tree

3 files changed

+52
-2
lines changed

3 files changed

+52
-2
lines changed

src/cmd/dist/build.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"path/filepath"
1818
"regexp"
1919
"sort"
20+
"strconv"
2021
"strings"
2122
"sync"
2223
"time"
@@ -261,8 +262,12 @@ func xinit() {
261262
os.Unsetenv("GOFLAGS")
262263
os.Setenv("GOWORK", "off")
263264

265+
// Create the go.mod for building toolchain2 and toolchain3. Toolchain1 and go_bootstrap are built with
266+
// a separate go.mod (with a lower required go version to allow all allowed bootstrap toolchain versions)
267+
// in bootstrapBuildTools.
268+
modVer := goModVersion()
264269
workdir = xworkdir()
265-
if err := os.WriteFile(pathf("%s/go.mod", workdir), []byte("module bootstrap"), 0666); err != nil {
270+
if err := os.WriteFile(pathf("%s/go.mod", workdir), []byte("module bootstrap\n\ngo "+modVer+"\n"), 0666); err != nil {
266271
fatalf("cannot write stub go.mod: %s", err)
267272
}
268273
xatexit(rmworkdir)
@@ -441,6 +446,33 @@ func findgoversion() string {
441446
return version
442447
}
443448

449+
// goModVersion returns the go version declared in src/go.mod. This is the
450+
// go version to use in the go.mod building go_bootstrap, toolchain2, and toolchain3.
451+
// (toolchain1 must be built with requiredBootstrapVersion(goModVersion))
452+
func goModVersion() string {
453+
goMod := readfile(pathf("%s/src/go.mod", goroot))
454+
m := regexp.MustCompile(`(?m)^go (1.\d+)$`).FindStringSubmatch(goMod)
455+
if m == nil {
456+
fatalf("std go.mod does not contain go 1.X")
457+
}
458+
return m[1]
459+
}
460+
461+
func requiredBootstrapVersion(v string) string {
462+
minorstr, ok := strings.CutPrefix(v, "1.")
463+
if !ok {
464+
fatalf("go version %q in go.mod does not start with %q", v, "1.")
465+
}
466+
minor, err := strconv.Atoi(minorstr)
467+
if err != nil {
468+
fatalf("invalid go version minor component %q: %v", minorstr, err)
469+
}
470+
// Per go.dev/doc/install/source, for N >= 22, Go version 1.N will require a Go 1.M compiler,
471+
// where M is N-2 rounded down to an even number. Example: Go 1.24 and 1.25 require Go 1.22.
472+
requiredMinor := minor - 2 - minor%2
473+
return "1." + strconv.Itoa(requiredMinor)
474+
}
475+
444476
// isGitRepo reports whether the working directory is inside a Git repository.
445477
func isGitRepo() bool {
446478
// NB: simply checking the exit code of `git rev-parse --git-dir` would

src/cmd/dist/build_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,20 @@ func TestMustLinkExternal(t *testing.T) {
2424
}
2525
}
2626
}
27+
28+
func TestRequiredBootstrapVersion(t *testing.T) {
29+
testCases := map[string]string{
30+
"1.22": "1.20",
31+
"1.23": "1.20",
32+
"1.24": "1.22",
33+
"1.25": "1.22",
34+
"1.26": "1.24",
35+
"1.27": "1.24",
36+
}
37+
38+
for v, want := range testCases {
39+
if got := requiredBootstrapVersion(v); got != want {
40+
t.Errorf("requiredBootstrapVersion(%v): got %v, want %v", v, got, want)
41+
}
42+
}
43+
}

src/cmd/dist/buildtool.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,8 @@ func bootstrapBuildTools() {
151151
xmkdirall(base)
152152

153153
// Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths.
154-
writefile("module bootstrap\ngo 1.20\n", pathf("%s/%s", base, "go.mod"), 0)
154+
minBootstrapVers := requiredBootstrapVersion(goModVersion()) // require the minimum required go version to build this go version in the go.mod file
155+
writefile("module bootstrap\ngo "+minBootstrapVers+"\n", pathf("%s/%s", base, "go.mod"), 0)
155156
for _, dir := range bootstrapDirs {
156157
recurse := strings.HasSuffix(dir, "/...")
157158
dir = strings.TrimSuffix(dir, "/...")

0 commit comments

Comments
 (0)