1From 7bc891e00be4263311d75aa2b2ee6a3b7b75355f Mon Sep 17 00:00:00 2001 2From: Alex Kube <alexander.j.kube@gmail.com> 3Date: Wed, 23 Oct 2019 21:18:12 +0430 4Subject: [PATCH] cmd/dist: separate host and target builds 5 6Upstream-Status: Inappropriate [OE specific] 7 8Change the dist tool to allow for OE-style cross- 9and cross-canadian builds: 10 11 - command flags --host-only and --target only are added; 12 if one is present, the other changes mentioned below 13 take effect, and arguments may also be specified on 14 the command line to enumerate the package(s) to be 15 built. 16 17 - for OE cross builds, go_bootstrap is always built for 18 the current build host, and is moved, along with the supporting 19 toolchain (asm, compile, etc.) to a separate 'native_native' 20 directory under GOROOT/pkg/tool. 21 22 - go_bootstrap is not automatically removed after the build, 23 so it can be reused later (e.g., building both static and 24 shared runtime). 25 26Note that for --host-only builds, it would be nice to specify 27just the "cmd" package to build only the go commands/tools, 28the staleness checks in the dist tool will fail if the "std" 29library has not also been built. So host-only builds have to 30build everything anyway. 31 32Adapted to Go 1.13 from patches originally submitted to 33the meta/recipes-devtools/go tree by 34Matt Madison <matt@madison.systems>. 35 36Signed-off-by: Alexander J Kube <alexander.j.kube@gmail.com> 37 38--- 39 src/cmd/dist/build.go | 156 ++++++++++++++++++++++++++++++------------ 40 1 file changed, 113 insertions(+), 43 deletions(-) 41 42diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go 43index d82f612..5c8459c 100644 44--- a/src/cmd/dist/build.go 45+++ b/src/cmd/dist/build.go 46@@ -43,6 +43,7 @@ var ( 47 goexperiment string 48 workdir string 49 tooldir string 50+ build_tooldir string 51 oldgoos string 52 oldgoarch string 53 exe string 54@@ -55,6 +56,7 @@ var ( 55 56 rebuildall bool 57 defaultclang bool 58+ crossBuild bool 59 60 vflag int // verbosity 61 ) 62@@ -251,6 +253,8 @@ func xinit() { 63 if tooldir = os.Getenv("GOTOOLDIR"); tooldir == "" { 64 tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch) 65 } 66+ 67+ build_tooldir = pathf("%s/pkg/tool/native_native", goroot) 68 } 69 70 // compilerEnv returns a map from "goos/goarch" to the 71@@ -496,8 +500,10 @@ func setup() { 72 p := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch) 73 if rebuildall { 74 xremoveall(p) 75+ xremoveall(build_tooldir) 76 } 77 xmkdirall(p) 78+ xmkdirall(build_tooldir) 79 80 if goos != gohostos || goarch != gohostarch { 81 p := pathf("%s/pkg/%s_%s", goroot, goos, goarch) 82@@ -1267,17 +1273,35 @@ func cmdbootstrap() { 83 84 var noBanner, noClean bool 85 var debug bool 86+ var hostOnly bool 87+ var targetOnly bool 88+ var toBuild = []string{"std", "cmd"} 89+ 90 flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all") 91 flag.BoolVar(&debug, "d", debug, "enable debugging of bootstrap process") 92 flag.BoolVar(&noBanner, "no-banner", noBanner, "do not print banner") 93 flag.BoolVar(&noClean, "no-clean", noClean, "print deprecation warning") 94+ flag.BoolVar(&hostOnly, "host-only", hostOnly, "build only host binaries, not target") 95+ flag.BoolVar(&targetOnly, "target-only", targetOnly, "build only target binaries, not host") 96 97- xflagparse(0) 98+ xflagparse(-1) 99 100 if noClean { 101 xprintf("warning: --no-clean is deprecated and has no effect; use 'go install std cmd' instead\n") 102 } 103 104+ if hostOnly && targetOnly { 105+ fatalf("specify only one of --host-only or --target-only\n") 106+ } 107+ crossBuild = hostOnly || targetOnly 108+ if flag.NArg() > 0 { 109+ if crossBuild { 110+ toBuild = flag.Args() 111+ } else { 112+ fatalf("package names not permitted without --host-only or --target-only\n") 113+ } 114+ } 115+ 116 // Set GOPATH to an internal directory. We shouldn't actually 117 // need to store files here, since the toolchain won't 118 // depend on modules outside of vendor directories, but if 119@@ -1345,8 +1369,13 @@ func cmdbootstrap() { 120 xprintf("\n") 121 } 122 123- gogcflags = os.Getenv("GO_GCFLAGS") // we were using $BOOT_GO_GCFLAGS until now 124- goldflags = os.Getenv("GO_LDFLAGS") // we were using $BOOT_GO_LDFLAGS until now 125+ // For split host/target cross/cross-canadian builds, we don't 126+ // want to be setting these flags until after we have compiled 127+ // the toolchain that runs on the build host. 128+ if !crossBuild { 129+ gogcflags = os.Getenv("GO_GCFLAGS") // we were using $BOOT_GO_GCFLAGS until now 130+ goldflags = os.Getenv("GO_LDFLAGS") // we were using $BOOT_GO_LDFLAGS until now 131+ } 132 goBootstrap := pathf("%s/go_bootstrap", tooldir) 133 cmdGo := pathf("%s/go", gobin) 134 if debug { 135@@ -1375,7 +1404,11 @@ func cmdbootstrap() { 136 xprintf("\n") 137 } 138 xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n") 139- os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch)) 140+ if crossBuild { 141+ os.Setenv("CC", defaultcc[""]) 142+ } else { 143+ os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch)) 144+ } 145 // Now that cmd/go is in charge of the build process, enable GOEXPERIMENT. 146 os.Setenv("GOEXPERIMENT", goexperiment) 147 goInstall(goBootstrap, append([]string{"-i"}, toolchain...)...) 148@@ -1414,50 +1447,84 @@ func cmdbootstrap() { 149 } 150 checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...) 151 152- if goos == oldgoos && goarch == oldgoarch { 153- // Common case - not setting up for cross-compilation. 154- timelog("build", "toolchain") 155- if vflag > 0 { 156- xprintf("\n") 157+ if crossBuild { 158+ gogcflags = os.Getenv("GO_GCFLAGS") 159+ goldflags = os.Getenv("GO_LDFLAGS") 160+ tool_files, _ := filepath.Glob(pathf("%s/*", tooldir)) 161+ for _, f := range tool_files { 162+ copyfile(pathf("%s/%s", build_tooldir, filepath.Base(f)), f, writeExec) 163+ xremove(f) 164+ } 165+ os.Setenv("GOTOOLDIR", build_tooldir) 166+ goBootstrap = pathf("%s/go_bootstrap", build_tooldir) 167+ if hostOnly { 168+ timelog("build", "host toolchain") 169+ if vflag > 0 { 170+ xprintf("\n") 171+ } 172+ xprintf("Building %s for host, %s/%s.\n", strings.Join(toBuild, ","), goos, goarch) 173+ goInstall(goBootstrap, toBuild...) 174+ checkNotStale(goBootstrap, toBuild...) 175+ // Skip cmdGo staleness checks here, since we can't necessarily run the cmdGo binary 176+ 177+ timelog("build", "target toolchain") 178+ if vflag > 0 { 179+ xprintf("\n") 180+ } 181+ } else if targetOnly { 182+ goos = oldgoos 183+ goarch = oldgoarch 184+ os.Setenv("GOOS", goos) 185+ os.Setenv("GOARCH", goarch) 186+ os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch)) 187+ xprintf("Building %s for target, %s/%s.\n", strings.Join(toBuild, ","), goos, goarch) 188+ goInstall(goBootstrap, toBuild...) 189+ checkNotStale(goBootstrap, toBuild...) 190+ // Skip cmdGo staleness checks here, since we can't run the target's cmdGo binary 191 } 192- xprintf("Building packages and commands for %s/%s.\n", goos, goarch) 193 } else { 194- // GOOS/GOARCH does not match GOHOSTOS/GOHOSTARCH. 195- // Finish GOHOSTOS/GOHOSTARCH installation and then 196- // run GOOS/GOARCH installation. 197- timelog("build", "host toolchain") 198- if vflag > 0 { 199- xprintf("\n") 200- } 201- xprintf("Building packages and commands for host, %s/%s.\n", goos, goarch) 202+ 203+ if goos == oldgoos && goarch == oldgoarch { 204+ // Common case - not setting up for cross-compilation. 205+ timelog("build", "toolchain") 206+ if vflag > 0 { 207+ xprintf("\n") 208+ } 209+ xprintf("Building packages and commands for %s/%s.\n", goos, goarch) 210+ } else { 211+ // GOOS/GOARCH does not match GOHOSTOS/GOHOSTARCH. 212+ // Finish GOHOSTOS/GOHOSTARCH installation and then 213+ // run GOOS/GOARCH installation. 214+ timelog("build", "host toolchain") 215+ if vflag > 0 { 216+ xprintf("\n") 217+ } 218+ xprintf("Building packages and commands for host, %s/%s.\n", goos, goarch) 219+ goInstall(goBootstrap, "std", "cmd") 220+ checkNotStale(goBootstrap, "std", "cmd") 221+ checkNotStale(cmdGo, "std", "cmd") 222+ 223+ timelog("build", "target toolchain") 224+ if vflag > 0 { 225+ xprintf("\n") 226+ } 227+ goos = oldgoos 228+ goarch = oldgoarch 229+ os.Setenv("GOOS", goos) 230+ os.Setenv("GOARCH", goarch) 231+ os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch)) 232+ xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch) 233+ } 234 goInstall(goBootstrap, "std", "cmd") 235 checkNotStale(goBootstrap, "std", "cmd") 236 checkNotStale(cmdGo, "std", "cmd") 237 238- timelog("build", "target toolchain") 239- if vflag > 0 { 240- xprintf("\n") 241+ if debug { 242+ run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") 243+ run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch)) 244+ checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...) 245+ copyfile(pathf("%s/compile4", tooldir), pathf("%s/compile", tooldir), writeExec) 246 } 247- goos = oldgoos 248- goarch = oldgoarch 249- os.Setenv("GOOS", goos) 250- os.Setenv("GOARCH", goarch) 251- os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch)) 252- xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch) 253- } 254- targets := []string{"std", "cmd"} 255- if goos == "js" && goarch == "wasm" { 256- // Skip the cmd tools for js/wasm. They're not usable. 257- targets = targets[:1] 258- } 259- goInstall(goBootstrap, targets...) 260- checkNotStale(goBootstrap, targets...) 261- checkNotStale(cmdGo, targets...) 262- if debug { 263- run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") 264- run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch)) 265- checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...) 266- copyfile(pathf("%s/compile4", tooldir), pathf("%s/compile", tooldir), writeExec) 267 } 268 269 // Check that there are no new files in $GOROOT/bin other than 270@@ -1474,8 +1541,11 @@ func cmdbootstrap() { 271 } 272 } 273 274- // Remove go_bootstrap now that we're done. 275- xremove(pathf("%s/go_bootstrap", tooldir)) 276+ // Except that for split host/target cross-builds, we need to 277+ // keep it. 278+ if !crossBuild { 279+ xremove(pathf("%s/go_bootstrap", tooldir)) 280+ } 281 282 if goos == "android" { 283 // Make sure the exec wrapper will sync a fresh $GOROOT to the device. 284