cmd/go, cmd/cgo, make.bash: cross compiling with cgo enabled

Introduce two new environment variables, CC_FOR_TARGET and CXX_FOR_TARGET.
CC_FOR_TARGET defaults to CC and is used when compiling for GOARCH, while
CC remains for compiling for GOHOSTARCH.
CXX_FOR_TARGET defaults to CXX and is used when compiling C++ code for
GOARCH.

CGO_ENABLED defaults to disabled when cross compiling and has to be
explicitly enabled.

Update #4714

LGTM=minux.ma, iant
R=golang-codereviews, minux.ma, iant, rsc, dominik.honnef
CC=golang-codereviews
https://golang.org/cl/57100043
diff --git a/src/cmd/dist/a.h b/src/cmd/dist/a.h
index 3052e51..6222e50 100644
--- a/src/cmd/dist/a.h
+++ b/src/cmd/dist/a.h
@@ -75,7 +75,8 @@
 extern char *goextlinkenabled;
 extern char *goversion;
 extern char *defaultcc;
-extern char *defaultcxx;
+extern char *defaultcxxtarget;
+extern char *defaultcctarget;
 extern char *workdir;
 extern char *tooldir;
 extern char *slash;
diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c
index 29656f3..0546249 100644
--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -27,7 +27,8 @@
 char *goversion;
 char *slash;	// / for unix, \ for windows
 char *defaultcc;
-char *defaultcxx;
+char *defaultcxxtarget;
+char *defaultcctarget;
 bool	rebuildall;
 bool defaultclang;
 
@@ -166,14 +167,23 @@
 	}
 	defaultcc = btake(&b);
 
-	xgetenv(&b, "CXX");
+	xgetenv(&b, "CC_FOR_TARGET");
 	if(b.len == 0) {
-		if(defaultclang)
-			bprintf(&b, "clang++");
-		else
-			bprintf(&b, "g++");
+		bprintf(&b, defaultcc);
 	}
-	defaultcxx = btake(&b);
+	defaultcctarget = btake(&b);
+
+	xgetenv(&b, "CXX_FOR_TARGET");
+	if(b.len == 0) {
+		xgetenv(&b, "CXX");
+		if(b.len == 0) {
+			if(defaultclang)
+				bprintf(&b, "clang++");
+			else
+				bprintf(&b, "g++");
+		}
+	}
+	defaultcxxtarget = btake(&b);
 
 	xsetenv("GOROOT", goroot);
 	xsetenv("GOARCH", goarch);
@@ -1537,6 +1547,7 @@
 		usage();
 
 	xprintf(format, "CC", defaultcc);
+	xprintf(format, "CC_FOR_TARGET", defaultcctarget);
 	xprintf(format, "GOROOT", goroot);
 	xprintf(format, "GOBIN", gobin);
 	xprintf(format, "GOARCH", goarch);
diff --git a/src/cmd/dist/buildgo.c b/src/cmd/dist/buildgo.c
index a340252..41208fa 100644
--- a/src/cmd/dist/buildgo.c
+++ b/src/cmd/dist/buildgo.c
@@ -31,7 +31,7 @@
 		"\n"
 		"const defaultCC = `%s`\n"
 		"const defaultCXX = `%s`\n",
-		defaultcc, defaultcxx);
+		defaultcctarget, defaultcxxtarget);
 
 	writefile(&out, file, 0);
 
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index da90f0c..4942a1b 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1708,41 +1708,41 @@
 	if buildContext.InstallSuffix != "" {
 		ldflags = append(ldflags, "-installsuffix", buildContext.InstallSuffix)
 	}
-	if cxx {
-		// The program includes C++ code.  If the user has not
-		// specified the -extld option, then default to
-		// linking with the compiler named by the CXX
-		// environment variable, or g++ if CXX is not set.
-		extld := false
-		for _, f := range ldflags {
-			if f == "-extld" || strings.HasPrefix(f, "-extld=") {
-				extld = true
-				break
-			}
+	// If the user has not specified the -extld option, then specify the
+	// appropriate linker. In case of C++ code, use the compiler named
+	// by the CXX environment variable or defaultCXX if CXX is not set.
+	// Else, use the CC environment variable and defaultCC as fallback.
+	extld := false
+	for _, f := range ldflags {
+		if f == "-extld" || strings.HasPrefix(f, "-extld=") {
+			extld = true
+			break
 		}
-		if !extld {
-			compiler := strings.Fields(os.Getenv("CXX"))
-			if len(compiler) == 0 {
-				compiler = []string{"g++"}
+	}
+	if !extld {
+		var compiler []string
+		if cxx {
+			compiler = ccompilerPath("CXX", defaultCXX)
+		} else {
+			compiler = ccompilerPath("CC", defaultCC)
+		}
+		ldflags = append(ldflags, "-extld="+compiler[0])
+		if len(compiler) > 1 {
+			extldflags := false
+			add := strings.Join(compiler[1:], " ")
+			for i, f := range ldflags {
+				if f == "-extldflags" && i+1 < len(ldflags) {
+					ldflags[i+1] = add + " " + ldflags[i+1]
+					extldflags = true
+					break
+				} else if strings.HasPrefix(f, "-extldflags=") {
+					ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
+					extldflags = true
+					break
+				}
 			}
-			ldflags = append(ldflags, "-extld="+compiler[0])
-			if len(compiler) > 1 {
-				extldflags := false
-				add := strings.Join(compiler[1:], " ")
-				for i, f := range ldflags {
-					if f == "-extldflags" && i+1 < len(ldflags) {
-						ldflags[i+1] = add + " " + ldflags[i+1]
-						extldflags = true
-						break
-					} else if strings.HasPrefix(f, "-extldflags=") {
-						ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
-						extldflags = true
-						break
-					}
-				}
-				if !extldflags {
-					ldflags = append(ldflags, "-extldflags="+add)
-				}
+			if !extldflags {
+				ldflags = append(ldflags, "-extldflags="+add)
 			}
 		}
 	}
@@ -1973,15 +1973,12 @@
 }
 
 // ccompilerCmd returns a command line prefix for the given environment
-// variable and using the default command when the variable is empty
+// variable and using the default command when the variable is empty.
 func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
 	// NOTE: env.go's mkEnv knows that the first three
 	// strings returned are "gcc", "-I", objdir (and cuts them off).
 
-	compiler := strings.Fields(os.Getenv(envvar))
-	if len(compiler) == 0 {
-		compiler = strings.Fields(defcmd)
-	}
+	compiler := ccompilerPath(envvar, defcmd)
 	a := []string{compiler[0], "-I", objdir, "-g", "-O2"}
 	a = append(a, compiler[1:]...)
 
@@ -2039,6 +2036,16 @@
 	return strings.Fields(os.Getenv(key))
 }
 
+// ccompilerCmd returns the compilerpath for the given environment
+// variable and using the default command when the variable is empty.
+func ccompilerPath(envvar, defcmd string) []string {
+	compiler := envList(envvar)
+	if len(compiler) == 0 {
+		compiler = strings.Fields(defcmd)
+	}
+	return compiler
+}
+
 var cgoRe = regexp.MustCompile(`[/\\:]`)
 
 var (
diff --git a/src/make.bash b/src/make.bash
index 877d1e5..bfcb5d5 100755
--- a/src/make.bash
+++ b/src/make.bash
@@ -35,10 +35,15 @@
 # controls the default behavior of the linker's -linkmode option.  The
 # default value depends on the system.
 #
-# CC: Command line to run to get at host C compiler.
+# CC: Command line to run to compile C code for GOHOSTARCH.
 # Default is "gcc". Also supported: "clang".
-# CXX: Command line to run to get at host C++ compiler, only recorded
-# for cgo use. Default is "g++". Also supported: "clang++".
+#
+# CC_FOR_TARGET: Command line to run to compile C code for GOARCH.
+# This is used by cgo.  Default is CC.
+#
+# CXX_FOR_TARGET: Command line to run to compile C++ code for GOARCH.
+# This is used by cgo. Default is CXX, or, if that is not set, 
+# "g++" or "clang++".
 #
 # GO_DISTFLAGS: extra flags to provide to "dist bootstrap". Use "-s"
 # to build a statically linked toolchain.
@@ -153,13 +158,15 @@
 
 if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then
 	echo "# Building packages and commands for host, $GOHOSTOS/$GOHOSTARCH."
-	GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
+	# CC_FOR_TARGET is recorded as the default compiler for the go tool. When building for the host, however,
+	# use the host compiler, CC, from `cmd/dist/dist env` instead.
+	CC=$CC GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
 		"$GOTOOLDIR"/go_bootstrap install -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
 	echo
 fi
 
 echo "# Building packages and commands for $GOOS/$GOARCH."
-"$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
+CC=$CC_FOR_TARGET "$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
 echo
 
 rm -f "$GOTOOLDIR"/go_bootstrap
diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go
index 50d2fb4..e4fc853 100644
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -303,8 +303,7 @@
 	case "0":
 		c.CgoEnabled = false
 	default:
-		// golang.org/issue/5141
-		// cgo should be disabled for cross compilation builds
+		// cgo must be explicitly enabled for cross compilation builds
 		if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS {
 			c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
 			break