1
0
mirror of https://github.com/golang/go synced 2024-11-19 15:44:44 -07:00

cmd/dist, cmd/cgo, cmd/go: allow per-goos/goarch default CC

Even though cmd/dist has historically distinguished "CC for gohostos/gohostarch"
from "CC for target goos/goarch", it has not recorded that distinction
for later use by cmd/cgo and cmd/go. Now that content-based staleness
includes the CC setting in the decision about when to rebuild packages,
the go command needs to know the details of which CC to use when.
Otherwise lots of things look out of date and (worse) may be rebuilt with
the wrong CC.

A related issue is that users may want to be able to build a toolchain
capable of cross-compiling for two different non-host targets, and
to date we've required that CC_FOR_TARGET apply to both.
This CL introduces CC_FOR_${GOOS}_${GOARCH}, so that you can
(for example) set CC_FOR_linux_arm and CC_FOR_linux_arm64
separately on a linux/ppc64 host and be able to cross-compile to
either arm or arm64 with the right toolchain.

Fixes #8161.
Half of a fix for #22509.

Change-Id: I7a43769f39d859f659d31bc96980918ba102fb83
Reviewed-on: https://go-review.googlesource.com/76018
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
Russ Cox 2017-11-05 17:09:54 -05:00
parent 5e48d2b62a
commit 4739c0db47
8 changed files with 125 additions and 88 deletions

View File

@ -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

View File

@ -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".

147
src/cmd/dist/build.go vendored
View File

@ -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"

View File

@ -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

View File

@ -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]
}

View File

@ -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.

View File

@ -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 {

View File

@ -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)
}