diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index ee99bfc2c35528e3d7a203050189fbbc88165f35..796d11a63c286c6168881a8ade7f9d5441bd1869 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -102,11 +102,13 @@ the use of cgo, and to 0 to disable it. The go tool will set the build constraint "cgo" if cgo is enabled. When cross-compiling, you must specify a C cross-compiler for cgo to -use. You can do this by setting the CC_FOR_TARGET environment -variable when building the toolchain using make.bash, or by setting -the CC environment variable any time you run the go tool. The -CXX_FOR_TARGET and CXX environment variables work in a similar way for -C++ code. +use. You can do this by setting the generic CC_FOR_TARGET or the +more specific CC_FOR_${GOOS}_${GOARCH} (for example, CC_FOR_linux_arm) +environment variable when building the toolchain using make.bash, +or you can set the CC environment variable any time you run the go tool. + +The CXX_FOR_TARGET, CXX_FOR_${GOOS}_${GOARCH}, and CXX +environment variables work in a similar way for C++ code. Go references to C diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index 99e98cee75575df524fbc57f8406e023e81b9a1a..95be03f6e45f4f3579c8ba1757aab3da8014d781 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -1221,7 +1221,7 @@ func (p *Package) gccBaseCmd() []string { if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 { return ret } - return strings.Fields(defaultCC) + return strings.Fields(defaultCC(goos, goarch)) } // gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm". diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index aa2402163d6963e94ae0370c5a51c280b13448df..a2f3a8c2822209933a45dd1a9bac8bc8e0fef142 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -23,29 +23,28 @@ import ( // The usual variables. var ( - goarch string - gobin string - gohostarch string - gohostos string - goos string - goarm string - go386 string - goroot string - goroot_final string - goextlinkenabled string - gogcflags string // For running built compiler - goldflags string - workdir string - tooldir string - oldgoos string - oldgoarch string - exe string - defaultcc string - defaultcflags string - defaultldflags string - defaultcxxtarget string - defaultcctarget string - defaultpkgconfigtarget string + goarch string + gobin string + gohostarch string + gohostos string + goos string + goarm string + go386 string + goroot string + goroot_final string + goextlinkenabled string + gogcflags string // For running built compiler + goldflags string + workdir string + tooldir string + oldgoos string + oldgoarch string + exe string + defaultcc map[string]string + defaultcxx map[string]string + defaultcflags string + defaultldflags string + defaultpkgconfig string rebuildall bool defaultclang bool @@ -172,49 +171,21 @@ func xinit() { gogcflags = os.Getenv("BOOT_GO_GCFLAGS") - b = os.Getenv("CC") - if b == "" { - // Use clang on OS X, because gcc is deprecated there. - // Xcode for OS X 10.9 Mavericks will ship a fake "gcc" binary that - // actually runs clang. We prepare different command - // lines for the two binaries, so it matters what we call it. - // See golang.org/issue/5822. - if defaultclang { - b = "clang" - } else { - b = "gcc" - } + cc := "gcc" + if defaultclang { + cc = "clang" } - defaultcc = b + defaultcc = compilerEnv("CC", cc) + defaultcxx = compilerEnv("CXX", cc+"++") defaultcflags = os.Getenv("CFLAGS") - defaultldflags = os.Getenv("LDFLAGS") - b = os.Getenv("CC_FOR_TARGET") - if b == "" { - b = defaultcc - } - defaultcctarget = b - - b = os.Getenv("CXX_FOR_TARGET") - if b == "" { - b = os.Getenv("CXX") - if b == "" { - if defaultclang { - b = "clang++" - } else { - b = "g++" - } - } - } - defaultcxxtarget = b - b = os.Getenv("PKG_CONFIG") if b == "" { b = "pkg-config" } - defaultpkgconfigtarget = b + defaultpkgconfig = b // For tools being invoked but also for os.ExpandEnv. os.Setenv("GO386", go386) @@ -244,6 +215,55 @@ func xinit() { tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch) } +// compilerEnv returns a map from "goos/goarch" to the +// compiler setting to use for that platform. +// The entry for key "" covers any goos/goarch not explicitly set in the map. +// For example, compilerEnv("CC", "gcc") returns the C compiler settings +// read from $CC, defaulting to gcc. +// +// The result is a map because additional environment variables +// can be set to change the compiler based on goos/goarch settings. +// The following applies to all envNames but CC is assumed to simplify +// the presentation. +// +// If no environment variables are set, we use def for all goos/goarch. +// $CC, if set, applies to all goos/goarch but is overridden by the following. +// $CC_FOR_TARGET, if set, applies to all goos/goarch except gohostos/gohostarch, +// but is overridden by the following. +// If gohostos=goos and gohostarch=goarch, then $CC_FOR_TARGET applies even for gohostos/gohostarch. +// $CC_FOR_goos_goarch, if set, applies only to goos/goarch. +func compilerEnv(envName, def string) map[string]string { + m := map[string]string{"": def} + + if env := os.Getenv(envName); env != "" { + m[""] = env + } + if env := os.Getenv(envName + "_FOR_TARGET"); env != "" { + if gohostos != goos || gohostarch != goarch { + m[gohostos+"/"+gohostarch] = m[""] + } + m[""] = env + } + + for _, goos := range okgoos { + for _, goarch := range okgoarch { + if env := os.Getenv(envName + "_FOR_" + goos + "_" + goarch); env != "" { + m[goos+"/"+goarch] = env + } + } + } + + return m +} + +// compilerEnvLookup returns the compiler settings for goos/goarch in map m. +func compilerEnvLookup(m map[string]string, goos, goarch string) string { + if cc := m[goos+"/"+goarch]; cc != "" { + return cc + } + return m[""] +} + // rmworkdir deletes the work directory. func rmworkdir() { if vflag > 1 { @@ -1009,8 +1029,6 @@ func cmdenv() { format = "set %s=%s\r\n" } - xprintf(format, "CC", defaultcc) - xprintf(format, "CC_FOR_TARGET", defaultcctarget) xprintf(format, "GOROOT", goroot) xprintf(format, "GOBIN", gobin) xprintf(format, "GOARCH", goarch) @@ -1171,12 +1189,7 @@ func cmdbootstrap() { xprintf("\n") } xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n") - os.Setenv("CC", defaultcc) - if goos == oldgoos && goarch == oldgoarch { - // Host and target are same, and we have historically - // chosen $CC_FOR_TARGET in this case. - os.Setenv("CC", defaultcctarget) - } + os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch)) goInstall(goBootstrap, append([]string{"-i"}, toolchain...)...) if debug { run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") @@ -1241,7 +1254,7 @@ func cmdbootstrap() { goarch = oldgoarch os.Setenv("GOOS", goos) os.Setenv("GOARCH", goarch) - os.Setenv("CC", defaultcctarget) + os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch)) xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch) } goInstall(goBootstrap, "std", "cmd") @@ -1372,7 +1385,7 @@ func checkCC() { if !needCC() { return } - if output, err := exec.Command(defaultcc, "--help").CombinedOutput(); err != nil { + if output, err := exec.Command(defaultcc[""], "--help").CombinedOutput(); err != nil { outputHdr := "" if len(output) > 0 { outputHdr = "\nCommand output:\n\n" diff --git a/src/cmd/dist/buildgo.go b/src/cmd/dist/buildgo.go index 19384a1a530c242af9f2eef956ce16a17e1815f4..caafc13da888ad2ceec2b30bc73823fe1051177a 100644 --- a/src/cmd/dist/buildgo.go +++ b/src/cmd/dist/buildgo.go @@ -33,9 +33,9 @@ func mkzdefaultcc(dir, file string) { fmt.Fprintln(&buf) fmt.Fprintf(&buf, "package cfg\n") fmt.Fprintln(&buf) - fmt.Fprintf(&buf, "const DefaultCC = `%s`\n", defaultcctarget) - fmt.Fprintf(&buf, "const DefaultCXX = `%s`\n", defaultcxxtarget) - fmt.Fprintf(&buf, "const DefaultPkgConfig = `%s`\n", defaultpkgconfigtarget) + fmt.Fprintf(&buf, "const DefaultPkgConfig = `%s`\n", defaultpkgconfig) + buf.WriteString(defaultCCFunc("DefaultCC", defaultcc)) + buf.WriteString(defaultCCFunc("DefaultCXX", defaultcxx)) writefile(buf.String(), file, writeSkipSame) return } @@ -45,12 +45,34 @@ func mkzdefaultcc(dir, file string) { fmt.Fprintln(&buf) fmt.Fprintf(&buf, "package main\n") fmt.Fprintln(&buf) - fmt.Fprintf(&buf, "const defaultCC = `%s`\n", defaultcctarget) - fmt.Fprintf(&buf, "const defaultCXX = `%s`\n", defaultcxxtarget) - fmt.Fprintf(&buf, "const defaultPkgConfig = `%s`\n", defaultpkgconfigtarget) + fmt.Fprintf(&buf, "const defaultPkgConfig = `%s`\n", defaultpkgconfig) + buf.WriteString(defaultCCFunc("defaultCC", defaultcc)) + buf.WriteString(defaultCCFunc("defaultCXX", defaultcxx)) writefile(buf.String(), file, writeSkipSame) } +func defaultCCFunc(name string, defaultcc map[string]string) string { + var buf bytes.Buffer + + fmt.Fprintf(&buf, "func %s(goos, goarch string) string {\n", name) + fmt.Fprintf(&buf, "\tswitch goos+`/`+goarch {\n") + var keys []string + for k := range defaultcc { + if k != "" { + keys = append(keys, k) + } + } + sort.Strings(keys) + for _, k := range keys { + fmt.Fprintf(&buf, "\tcase %q:\n\t\treturn %q\n", k, defaultcc[k]) + } + fmt.Fprintf(&buf, "\t}\n") + fmt.Fprintf(&buf, "\treturn %q\n", defaultcc[""]) + fmt.Fprintf(&buf, "}\n") + + return buf.String() +} + // mkzcgo writes zosarch.go for cmd/go. func mkzosarch(dir, file string) { // sort for deterministic zosarch.go file diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go index 90ab2d718fe0c31d57d7e38bbc019af078afc68d..f756e3b60722749737041d49bbcce8f93ea127da 100644 --- a/src/cmd/go/internal/envcmd/env.go +++ b/src/cmd/go/internal/envcmd/env.go @@ -78,11 +78,11 @@ func MkEnv() []cfg.EnvVar { env = append(env, cfg.EnvVar{Name: "GO386", Value: cfg.GO386}) } - cc := cfg.DefaultCC + cc := cfg.DefaultCC(cfg.Goos, cfg.Goarch) if env := strings.Fields(os.Getenv("CC")); len(env) > 0 { cc = env[0] } - cxx := cfg.DefaultCXX + cxx := cfg.DefaultCXX(cfg.Goos, cfg.Goarch) if env := strings.Fields(os.Getenv("CXX")); len(env) > 0 { cxx = env[0] } diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 7a4e62b0a4466fa4dca187ea3395eddd9f679bfb..d43a5f2417f0d362e026d4b5fb206dec94a92ca3 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -1597,12 +1597,12 @@ func (b *Builder) gfortranCmd(incdir, workdir string) []string { // ccExe returns the CC compiler setting without all the extra flags we add implicitly. func (b *Builder) ccExe() []string { - return b.compilerExe(origCC, cfg.DefaultCC) + return b.compilerExe(origCC, cfg.DefaultCC(cfg.Goos, cfg.Goarch)) } // cxxExe returns the CXX compiler setting without all the extra flags we add implicitly. func (b *Builder) cxxExe() []string { - return b.compilerExe(origCXX, cfg.DefaultCXX) + return b.compilerExe(origCXX, cfg.DefaultCXX(cfg.Goos, cfg.Goarch)) } // fcExe returns the FC compiler setting without all the extra flags we add implicitly. diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go index 651d20c21c57197333e81796267522892684b598..c0db90dfe50561dd19fe9f090736210c8bd0bca9 100644 --- a/src/cmd/go/internal/work/gc.go +++ b/src/cmd/go/internal/work/gc.go @@ -430,9 +430,9 @@ func (gcToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string) // Else, use the CC environment variable and defaultCC as fallback. var compiler []string if cxx { - compiler = envList("CXX", cfg.DefaultCXX) + compiler = envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch)) } else { - compiler = envList("CC", cfg.DefaultCC) + compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch)) } ldflags = append(ldflags, "-buildmode="+ldBuildmode) if root.buildID != "" { @@ -474,9 +474,9 @@ func (gcToolchain) ldShared(b *Builder, toplevelactions []*Action, out, importcf // Else, use the CC environment variable and defaultCC as fallback. var compiler []string if cxx { - compiler = envList("CXX", cfg.DefaultCXX) + compiler = envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch)) } else { - compiler = envList("CC", cfg.DefaultCC) + compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch)) } ldflags = setextld(ldflags, compiler) for _, d := range toplevelactions { diff --git a/src/cmd/go/internal/work/gccgo.go b/src/cmd/go/internal/work/gccgo.go index 1d7155c977601982125f2b652636402ee26d5658..898c3c200486a76a821229e823c503e2695486f8 100644 --- a/src/cmd/go/internal/work/gccgo.go +++ b/src/cmd/go/internal/work/gccgo.go @@ -464,7 +464,7 @@ func (tools gccgoToolchain) cc(b *Builder, a *Action, ofile, cfile string) error defs = append(defs, "-fsplit-stack") } defs = tools.maybePIC(defs) - return b.run(p.Dir, p.ImportPath, nil, envList("CC", cfg.DefaultCC), "-Wall", "-g", + return b.run(p.Dir, p.ImportPath, nil, envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch)), "-Wall", "-g", "-I", a.Objdir, "-I", inc, "-o", ofile, defs, "-c", cfile) }