Commit 2dc759d7 authored by Elias Naur's avatar Elias Naur Committed by Ian Lance Taylor

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
parent 76c91825
...@@ -75,7 +75,8 @@ extern char *goroot_final; ...@@ -75,7 +75,8 @@ extern char *goroot_final;
extern char *goextlinkenabled; extern char *goextlinkenabled;
extern char *goversion; extern char *goversion;
extern char *defaultcc; extern char *defaultcc;
extern char *defaultcxx; extern char *defaultcxxtarget;
extern char *defaultcctarget;
extern char *workdir; extern char *workdir;
extern char *tooldir; extern char *tooldir;
extern char *slash; extern char *slash;
......
...@@ -27,7 +27,8 @@ char *gochar; ...@@ -27,7 +27,8 @@ char *gochar;
char *goversion; char *goversion;
char *slash; // / for unix, \ for windows char *slash; // / for unix, \ for windows
char *defaultcc; char *defaultcc;
char *defaultcxx; char *defaultcxxtarget;
char *defaultcctarget;
bool rebuildall; bool rebuildall;
bool defaultclang; bool defaultclang;
...@@ -166,14 +167,23 @@ init(void) ...@@ -166,14 +167,23 @@ init(void)
} }
defaultcc = btake(&b); defaultcc = btake(&b);
xgetenv(&b, "CXX"); xgetenv(&b, "CC_FOR_TARGET");
if(b.len == 0) { if(b.len == 0) {
if(defaultclang) bprintf(&b, defaultcc);
bprintf(&b, "clang++"); }
else defaultcctarget = btake(&b);
bprintf(&b, "g++");
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++");
}
} }
defaultcxx = btake(&b); defaultcxxtarget = btake(&b);
xsetenv("GOROOT", goroot); xsetenv("GOROOT", goroot);
xsetenv("GOARCH", goarch); xsetenv("GOARCH", goarch);
...@@ -1537,6 +1547,7 @@ cmdenv(int argc, char **argv) ...@@ -1537,6 +1547,7 @@ cmdenv(int argc, char **argv)
usage(); usage();
xprintf(format, "CC", defaultcc); 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);
......
...@@ -31,7 +31,7 @@ mkzdefaultcc(char *dir, char *file) ...@@ -31,7 +31,7 @@ mkzdefaultcc(char *dir, char *file)
"\n" "\n"
"const defaultCC = `%s`\n" "const defaultCC = `%s`\n"
"const defaultCXX = `%s`\n", "const defaultCXX = `%s`\n",
defaultcc, defaultcxx); defaultcctarget, defaultcxxtarget);
writefile(&out, file, 0); writefile(&out, file, 0);
......
...@@ -1708,42 +1708,42 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, ...@@ -1708,42 +1708,42 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,
if buildContext.InstallSuffix != "" { if buildContext.InstallSuffix != "" {
ldflags = append(ldflags, "-installsuffix", buildContext.InstallSuffix) ldflags = append(ldflags, "-installsuffix", buildContext.InstallSuffix)
} }
if cxx { // If the user has not specified the -extld option, then specify the
// The program includes C++ code. If the user has not // appropriate linker. In case of C++ code, use the compiler named
// specified the -extld option, then default to // by the CXX environment variable or defaultCXX if CXX is not set.
// linking with the compiler named by the CXX // Else, use the CC environment variable and defaultCC as fallback.
// environment variable, or g++ if CXX is not set. extld := false
extld := false for _, f := range ldflags {
for _, f := range ldflags { if f == "-extld" || strings.HasPrefix(f, "-extld=") {
if f == "-extld" || strings.HasPrefix(f, "-extld=") { extld = true
extld = true break
break
}
} }
if !extld { }
compiler := strings.Fields(os.Getenv("CXX")) if !extld {
if len(compiler) == 0 { var compiler []string
compiler = []string{"g++"} if cxx {
} compiler = ccompilerPath("CXX", defaultCXX)
ldflags = append(ldflags, "-extld="+compiler[0]) } else {
if len(compiler) > 1 { compiler = ccompilerPath("CC", defaultCC)
extldflags := false }
add := strings.Join(compiler[1:], " ") ldflags = append(ldflags, "-extld="+compiler[0])
for i, f := range ldflags { if len(compiler) > 1 {
if f == "-extldflags" && i+1 < len(ldflags) { extldflags := false
ldflags[i+1] = add + " " + ldflags[i+1] add := strings.Join(compiler[1:], " ")
extldflags = true for i, f := range ldflags {
break if f == "-extldflags" && i+1 < len(ldflags) {
} else if strings.HasPrefix(f, "-extldflags=") { ldflags[i+1] = add + " " + ldflags[i+1]
ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):] extldflags = true
extldflags = true break
break } else if strings.HasPrefix(f, "-extldflags=") {
} ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
} extldflags = true
if !extldflags { break
ldflags = append(ldflags, "-extldflags="+add)
} }
} }
if !extldflags {
ldflags = append(ldflags, "-extldflags="+add)
}
} }
} }
return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, swigArg, ldflags, mainpkg) return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, swigArg, ldflags, mainpkg)
...@@ -1973,15 +1973,12 @@ func (b *builder) gxxCmd(objdir string) []string { ...@@ -1973,15 +1973,12 @@ func (b *builder) gxxCmd(objdir string) []string {
} }
// ccompilerCmd returns a command line prefix for the given environment // 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 { func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
// NOTE: env.go's mkEnv knows that the first three // NOTE: env.go's mkEnv knows that the first three
// strings returned are "gcc", "-I", objdir (and cuts them off). // strings returned are "gcc", "-I", objdir (and cuts them off).
compiler := strings.Fields(os.Getenv(envvar)) compiler := ccompilerPath(envvar, defcmd)
if len(compiler) == 0 {
compiler = strings.Fields(defcmd)
}
a := []string{compiler[0], "-I", objdir, "-g", "-O2"} a := []string{compiler[0], "-I", objdir, "-g", "-O2"}
a = append(a, compiler[1:]...) a = append(a, compiler[1:]...)
...@@ -2039,6 +2036,16 @@ func envList(key string) []string { ...@@ -2039,6 +2036,16 @@ func envList(key string) []string {
return strings.Fields(os.Getenv(key)) 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 cgoRe = regexp.MustCompile(`[/\\:]`)
var ( var (
......
...@@ -35,10 +35,15 @@ ...@@ -35,10 +35,15 @@
# controls the default behavior of the linker's -linkmode option. The # controls the default behavior of the linker's -linkmode option. The
# default value depends on the system. # 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". # 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" # GO_DISTFLAGS: extra flags to provide to "dist bootstrap". Use "-s"
# to build a statically linked toolchain. # to build a statically linked toolchain.
...@@ -153,13 +158,15 @@ echo ...@@ -153,13 +158,15 @@ echo
if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then
echo "# Building packages and commands for host, $GOHOSTOS/$GOHOSTARCH." 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 "$GOTOOLDIR"/go_bootstrap install -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
echo echo
fi fi
echo "# Building packages and commands for $GOOS/$GOARCH." 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 echo
rm -f "$GOTOOLDIR"/go_bootstrap rm -f "$GOTOOLDIR"/go_bootstrap
......
...@@ -303,8 +303,7 @@ func defaultContext() Context { ...@@ -303,8 +303,7 @@ func defaultContext() Context {
case "0": case "0":
c.CgoEnabled = false c.CgoEnabled = false
default: default:
// golang.org/issue/5141 // cgo must be explicitly enabled for cross compilation builds
// cgo should be disabled for cross compilation builds
if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS { if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS {
c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH] c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
break break
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment