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