mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00: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:
parent
5e48d2b62a
commit
4739c0db47
8 changed files with 125 additions and 88 deletions
|
|
@ -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.
|
build constraint "cgo" if cgo is enabled.
|
||||||
|
|
||||||
When cross-compiling, you must specify a C cross-compiler for cgo to
|
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
|
use. You can do this by setting the generic CC_FOR_TARGET or the
|
||||||
variable when building the toolchain using make.bash, or by setting
|
more specific CC_FOR_${GOOS}_${GOARCH} (for example, CC_FOR_linux_arm)
|
||||||
the CC environment variable any time you run the go tool. The
|
environment variable when building the toolchain using make.bash,
|
||||||
CXX_FOR_TARGET and CXX environment variables work in a similar way for
|
or you can set the CC environment variable any time you run the go tool.
|
||||||
C++ code.
|
|
||||||
|
The CXX_FOR_TARGET, CXX_FOR_${GOOS}_${GOARCH}, and CXX
|
||||||
|
environment variables work in a similar way for C++ code.
|
||||||
|
|
||||||
Go references to C
|
Go references to C
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1221,7 +1221,7 @@ func (p *Package) gccBaseCmd() []string {
|
||||||
if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 {
|
if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 {
|
||||||
return ret
|
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".
|
// gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm".
|
||||||
|
|
|
||||||
147
src/cmd/dist/build.go
vendored
147
src/cmd/dist/build.go
vendored
|
|
@ -23,29 +23,28 @@ import (
|
||||||
|
|
||||||
// The usual variables.
|
// The usual variables.
|
||||||
var (
|
var (
|
||||||
goarch string
|
goarch string
|
||||||
gobin string
|
gobin string
|
||||||
gohostarch string
|
gohostarch string
|
||||||
gohostos string
|
gohostos string
|
||||||
goos string
|
goos string
|
||||||
goarm string
|
goarm string
|
||||||
go386 string
|
go386 string
|
||||||
goroot string
|
goroot string
|
||||||
goroot_final string
|
goroot_final string
|
||||||
goextlinkenabled string
|
goextlinkenabled string
|
||||||
gogcflags string // For running built compiler
|
gogcflags string // For running built compiler
|
||||||
goldflags string
|
goldflags string
|
||||||
workdir string
|
workdir string
|
||||||
tooldir string
|
tooldir string
|
||||||
oldgoos string
|
oldgoos string
|
||||||
oldgoarch string
|
oldgoarch string
|
||||||
exe string
|
exe string
|
||||||
defaultcc string
|
defaultcc map[string]string
|
||||||
defaultcflags string
|
defaultcxx map[string]string
|
||||||
defaultldflags string
|
defaultcflags string
|
||||||
defaultcxxtarget string
|
defaultldflags string
|
||||||
defaultcctarget string
|
defaultpkgconfig string
|
||||||
defaultpkgconfigtarget string
|
|
||||||
|
|
||||||
rebuildall bool
|
rebuildall bool
|
||||||
defaultclang bool
|
defaultclang bool
|
||||||
|
|
@ -172,49 +171,21 @@ func xinit() {
|
||||||
|
|
||||||
gogcflags = os.Getenv("BOOT_GO_GCFLAGS")
|
gogcflags = os.Getenv("BOOT_GO_GCFLAGS")
|
||||||
|
|
||||||
b = os.Getenv("CC")
|
cc := "gcc"
|
||||||
if b == "" {
|
if defaultclang {
|
||||||
// Use clang on OS X, because gcc is deprecated there.
|
cc = "clang"
|
||||||
// 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"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
defaultcc = b
|
defaultcc = compilerEnv("CC", cc)
|
||||||
|
defaultcxx = compilerEnv("CXX", cc+"++")
|
||||||
|
|
||||||
defaultcflags = os.Getenv("CFLAGS")
|
defaultcflags = os.Getenv("CFLAGS")
|
||||||
|
|
||||||
defaultldflags = os.Getenv("LDFLAGS")
|
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")
|
b = os.Getenv("PKG_CONFIG")
|
||||||
if b == "" {
|
if b == "" {
|
||||||
b = "pkg-config"
|
b = "pkg-config"
|
||||||
}
|
}
|
||||||
defaultpkgconfigtarget = b
|
defaultpkgconfig = b
|
||||||
|
|
||||||
// For tools being invoked but also for os.ExpandEnv.
|
// For tools being invoked but also for os.ExpandEnv.
|
||||||
os.Setenv("GO386", go386)
|
os.Setenv("GO386", go386)
|
||||||
|
|
@ -244,6 +215,55 @@ func xinit() {
|
||||||
tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch)
|
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.
|
// rmworkdir deletes the work directory.
|
||||||
func rmworkdir() {
|
func rmworkdir() {
|
||||||
if vflag > 1 {
|
if vflag > 1 {
|
||||||
|
|
@ -1009,8 +1029,6 @@ func cmdenv() {
|
||||||
format = "set %s=%s\r\n"
|
format = "set %s=%s\r\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
xprintf(format, "CC", defaultcc)
|
|
||||||
xprintf(format, "CC_FOR_TARGET", defaultcctarget)
|
|
||||||
xprintf(format, "GOROOT", goroot)
|
xprintf(format, "GOROOT", goroot)
|
||||||
xprintf(format, "GOBIN", gobin)
|
xprintf(format, "GOBIN", gobin)
|
||||||
xprintf(format, "GOARCH", goarch)
|
xprintf(format, "GOARCH", goarch)
|
||||||
|
|
@ -1171,12 +1189,7 @@ func cmdbootstrap() {
|
||||||
xprintf("\n")
|
xprintf("\n")
|
||||||
}
|
}
|
||||||
xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n")
|
xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n")
|
||||||
os.Setenv("CC", defaultcc)
|
os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch))
|
||||||
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)
|
|
||||||
}
|
|
||||||
goInstall(goBootstrap, append([]string{"-i"}, toolchain...)...)
|
goInstall(goBootstrap, append([]string{"-i"}, toolchain...)...)
|
||||||
if debug {
|
if debug {
|
||||||
run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
|
run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
|
||||||
|
|
@ -1241,7 +1254,7 @@ func cmdbootstrap() {
|
||||||
goarch = oldgoarch
|
goarch = oldgoarch
|
||||||
os.Setenv("GOOS", goos)
|
os.Setenv("GOOS", goos)
|
||||||
os.Setenv("GOARCH", goarch)
|
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)
|
xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch)
|
||||||
}
|
}
|
||||||
goInstall(goBootstrap, "std", "cmd")
|
goInstall(goBootstrap, "std", "cmd")
|
||||||
|
|
@ -1372,7 +1385,7 @@ func checkCC() {
|
||||||
if !needCC() {
|
if !needCC() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if output, err := exec.Command(defaultcc, "--help").CombinedOutput(); err != nil {
|
if output, err := exec.Command(defaultcc[""], "--help").CombinedOutput(); err != nil {
|
||||||
outputHdr := ""
|
outputHdr := ""
|
||||||
if len(output) > 0 {
|
if len(output) > 0 {
|
||||||
outputHdr = "\nCommand output:\n\n"
|
outputHdr = "\nCommand output:\n\n"
|
||||||
|
|
|
||||||
34
src/cmd/dist/buildgo.go
vendored
34
src/cmd/dist/buildgo.go
vendored
|
|
@ -33,9 +33,9 @@ func mkzdefaultcc(dir, file string) {
|
||||||
fmt.Fprintln(&buf)
|
fmt.Fprintln(&buf)
|
||||||
fmt.Fprintf(&buf, "package cfg\n")
|
fmt.Fprintf(&buf, "package cfg\n")
|
||||||
fmt.Fprintln(&buf)
|
fmt.Fprintln(&buf)
|
||||||
fmt.Fprintf(&buf, "const DefaultCC = `%s`\n", defaultcctarget)
|
fmt.Fprintf(&buf, "const DefaultPkgConfig = `%s`\n", defaultpkgconfig)
|
||||||
fmt.Fprintf(&buf, "const DefaultCXX = `%s`\n", defaultcxxtarget)
|
buf.WriteString(defaultCCFunc("DefaultCC", defaultcc))
|
||||||
fmt.Fprintf(&buf, "const DefaultPkgConfig = `%s`\n", defaultpkgconfigtarget)
|
buf.WriteString(defaultCCFunc("DefaultCXX", defaultcxx))
|
||||||
writefile(buf.String(), file, writeSkipSame)
|
writefile(buf.String(), file, writeSkipSame)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -45,12 +45,34 @@ func mkzdefaultcc(dir, file string) {
|
||||||
fmt.Fprintln(&buf)
|
fmt.Fprintln(&buf)
|
||||||
fmt.Fprintf(&buf, "package main\n")
|
fmt.Fprintf(&buf, "package main\n")
|
||||||
fmt.Fprintln(&buf)
|
fmt.Fprintln(&buf)
|
||||||
fmt.Fprintf(&buf, "const defaultCC = `%s`\n", defaultcctarget)
|
fmt.Fprintf(&buf, "const defaultPkgConfig = `%s`\n", defaultpkgconfig)
|
||||||
fmt.Fprintf(&buf, "const defaultCXX = `%s`\n", defaultcxxtarget)
|
buf.WriteString(defaultCCFunc("defaultCC", defaultcc))
|
||||||
fmt.Fprintf(&buf, "const defaultPkgConfig = `%s`\n", defaultpkgconfigtarget)
|
buf.WriteString(defaultCCFunc("defaultCXX", defaultcxx))
|
||||||
writefile(buf.String(), file, writeSkipSame)
|
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.
|
// mkzcgo writes zosarch.go for cmd/go.
|
||||||
func mkzosarch(dir, file string) {
|
func mkzosarch(dir, file string) {
|
||||||
// sort for deterministic zosarch.go file
|
// sort for deterministic zosarch.go file
|
||||||
|
|
|
||||||
|
|
@ -78,11 +78,11 @@ func MkEnv() []cfg.EnvVar {
|
||||||
env = append(env, cfg.EnvVar{Name: "GO386", Value: cfg.GO386})
|
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 {
|
if env := strings.Fields(os.Getenv("CC")); len(env) > 0 {
|
||||||
cc = 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 {
|
if env := strings.Fields(os.Getenv("CXX")); len(env) > 0 {
|
||||||
cxx = env[0]
|
cxx = env[0]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
// ccExe returns the CC compiler setting without all the extra flags we add implicitly.
|
||||||
func (b *Builder) ccExe() []string {
|
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.
|
// cxxExe returns the CXX compiler setting without all the extra flags we add implicitly.
|
||||||
func (b *Builder) cxxExe() []string {
|
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.
|
// fcExe returns the FC compiler setting without all the extra flags we add implicitly.
|
||||||
|
|
|
||||||
|
|
@ -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.
|
// Else, use the CC environment variable and defaultCC as fallback.
|
||||||
var compiler []string
|
var compiler []string
|
||||||
if cxx {
|
if cxx {
|
||||||
compiler = envList("CXX", cfg.DefaultCXX)
|
compiler = envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch))
|
||||||
} else {
|
} else {
|
||||||
compiler = envList("CC", cfg.DefaultCC)
|
compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
|
||||||
}
|
}
|
||||||
ldflags = append(ldflags, "-buildmode="+ldBuildmode)
|
ldflags = append(ldflags, "-buildmode="+ldBuildmode)
|
||||||
if root.buildID != "" {
|
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.
|
// Else, use the CC environment variable and defaultCC as fallback.
|
||||||
var compiler []string
|
var compiler []string
|
||||||
if cxx {
|
if cxx {
|
||||||
compiler = envList("CXX", cfg.DefaultCXX)
|
compiler = envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch))
|
||||||
} else {
|
} else {
|
||||||
compiler = envList("CC", cfg.DefaultCC)
|
compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
|
||||||
}
|
}
|
||||||
ldflags = setextld(ldflags, compiler)
|
ldflags = setextld(ldflags, compiler)
|
||||||
for _, d := range toplevelactions {
|
for _, d := range toplevelactions {
|
||||||
|
|
|
||||||
|
|
@ -464,7 +464,7 @@ func (tools gccgoToolchain) cc(b *Builder, a *Action, ofile, cfile string) error
|
||||||
defs = append(defs, "-fsplit-stack")
|
defs = append(defs, "-fsplit-stack")
|
||||||
}
|
}
|
||||||
defs = tools.maybePIC(defs)
|
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)
|
"-I", a.Objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue