[go] cmd/compile: Add support for MSVC toolchain to go build

1,223 views
Skip to first unread message

Caleb Champlin (Gerrit)

unread,
Sep 7, 2018, 3:25:21 AM9/7/18
to Ian Lance Taylor, goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

Caleb Champlin has uploaded this change for review.

View Change

cmd/compile: Add support for MSVC toolchain to go build

Allows building with MSVC as an external compiler/linker.

Setting CC=cl.exe inside an MSVC environment will automatically
build cgo executables using MSVC as the external compiler and
linker.

For the builders setting the environment variable GOVSVARSPATH
to the location of a msvsvars.bat file and setting the
environment variable GOTESTMSVC=1 will automatically cause
all.bat to run tests and compiler with both gcc and MSVC

Updates #20982

Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced
---
M src/cmd/go/internal/work/build.go
M src/cmd/go/internal/work/exec.go
M src/cmd/go/internal/work/gc.go
M src/cmd/go/internal/work/security.go
M src/run.bat
5 files changed, 542 insertions(+), 32 deletions(-)

diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go
index ed41ce5..c296e04 100644
--- a/src/cmd/go/internal/work/build.go
+++ b/src/cmd/go/internal/work/build.go
@@ -5,6 +5,7 @@
package work

import (
+ "bytes"
"errors"
"fmt"
"go/build"
@@ -193,6 +194,10 @@
cfg.BuildToolchainCompiler = BuildToolchain.compiler
cfg.BuildToolchainLinker = BuildToolchain.linker
cfg.BuildContext.Compiler = value
+ cfg.BuildContext.CompilerType = resolveToolchainType()
+ if cfg.BuildContext.CompilerType == "msvc" {
+ cfg.BuildContext.BuildTags = append(cfg.BuildContext.BuildTags, "msvc")
+ }
return nil
}

@@ -207,6 +212,63 @@
}
}

+// resolveToolchainType tries to determine if we are compiling with
+// gcc or msvc. It executes the compiler command and checks
+// for specific strings to make the determination. It's okay
+// if the command executed returns an error
+// defaults to gcc
+func resolveToolchainType() string {
+ // Bail out early
+ if runtime.GOOS != "windows" {
+ return "gcc"
+ }
+
+ args := strings.Fields(os.Getenv("CC"))
+ if len(args) == 0 {
+ args = []string{cfg.DefaultCC(cfg.Goos, cfg.Goarch)}
+ }
+ args = append(args, "-v")
+ var out bytes.Buffer
+
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Stdout = &out
+ cmd.Stderr = &out
+ cmd.Dir = ""
+ cmd.Env = base.EnvForDir(cmd.Dir, os.Environ())
+ err := cmd.Run()
+ // Check for MSVC header
+ if idx := bytes.Index(out.Bytes(), []byte("Microsoft (R) C/C++ Optimizing Compiler")); idx == 0 {
+ return "msvc"
+ }
+
+ // Check for MSVC environment
+ msvc := os.Getenv("VSInstallDir")
+ if err != nil && len(msvc) > 0 {
+ underlyingErr, ok := err.(*exec.Error)
+ if err == exec.ErrNotFound || os.IsNotExist(err) || (ok && (os.IsNotExist(underlyingErr.Err) || underlyingErr.Err == exec.ErrNotFound)) {
+ args := strings.Fields(os.Getenv("MSCC"))
+ if len(args) == 0 {
+ args = []string{"cl.exe"}
+ }
+ args = append(args, "-v")
+ var out bytes.Buffer
+
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Stdout = &out
+ cmd.Stderr = &out
+ cmd.Dir = ""
+ cmd.Env = base.EnvForDir(cmd.Dir, os.Environ())
+ cmd.Run()
+
+ if idx := bytes.Index(out.Bytes(), []byte("Microsoft (R) C/C++ Optimizing Compiler")); idx == 0 {
+ return "msvc"
+ }
+ }
+ }
+
+ return "gcc"
+}
+
// addBuildFlags adds the flags common to the build, clean, get,
// install, list, run, and test commands.
func AddBuildFlags(cmd *base.Command) {
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index f2b65ac..7629c52 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -201,10 +201,20 @@
}
if len(p.CgoFiles)+len(p.SwigFiles) > 0 {
fmt.Fprintf(h, "cgo %q\n", b.toolID("cgo"))
- cppflags, cflags, cxxflags, mscppflags, mscflags, mscxxflags, fflags, _, ldflags, _ := b.CFlags(p)
+ cppflags, cflags, cxxflags, mscppflags, mscflags, mscxxflags, fflags, msldflags, ldflags, _ := b.CFlags(p)
fmt.Fprintf(h, "CC=%q %q %q %q\n", b.ccExe(), cppflags, cflags, ldflags)
+ if cfg.BuildContext.CompilerType == "msvc" {
+ if len(mscppflags)+len(mscflags) > 0 {
+ fmt.Fprintf(h, "MSCC=%q %q %q %d\n", b.ccExe(), mscppflags, mscflags, msldflags)
+ }
+ }
if len(p.CXXFiles)+len(p.SwigFiles) > 0 {
fmt.Fprintf(h, "CXX=%q %q\n", b.cxxExe(), cxxflags)
+ if cfg.BuildContext.CompilerType == "msvc" {
+ if len(mscxxflags) > 0 {
+ fmt.Fprintf(h, "MSCXX=%q %q\n", b.cxxExe(), mscxxflags)
+ }
+ }
}
if len(p.FFiles) > 0 {
fmt.Fprintf(h, "FC=%q %q\n", b.fcExe(), fflags)
@@ -537,7 +547,8 @@
// In that case gcc only gets the gcc_* files.
var gccfiles []string
if a.Package.Standard && a.Package.ImportPath == "runtime/cgo" {
- filterCombine := func(files, cfiles, gccfiles, nongcc []string, prefix string, exclude []string) ([]string, []string) {
+ filterCombine := func(files, cfiles, gccfiles, nongcc []string, prefix string) ([]string, []string) {
+ toolchainPrefixes := []string{"gcc", "gc", "gccgo", "msvc"}
for _, f := range cfiles {
if strings.HasPrefix(f, prefix) {
gccfiles = append(gccfiles, f)
@@ -548,8 +559,8 @@
gccfiles = append(gccfiles, f)
} else {
valid := true
- for _, exclusion := range exclude {
- if strings.HasPrefix(f, exclusion+"_") {
+ for _, exclusion := range toolchainPrefixes {
+ if exclusion != prefix && strings.HasPrefix(f, exclusion+"_") {
valid = false
break
}
@@ -561,7 +572,11 @@
}
return nongcc, gccfiles
}
- sfiles, gccfiles = filterCombine(sfiles, cfiles, gccfiles, sfiles[:0], "gcc_", []string{"msvc"})
+ if cfg.BuildContext.CompilerType != "msvc" {
+ sfiles, gccfiles = filterCombine(sfiles, cfiles, gccfiles, sfiles[:0], "gcc_")
+ } else {
+ sfiles, gccfiles = filterCombine(sfiles, cfiles, gccfiles, sfiles[:0], "msvc_")
+ }
cfiles = nil
} else {
gccfiles = append(gccfiles, cfiles...)
@@ -580,7 +595,7 @@
sfiles = nil
}

- outGo, outObj, err := b.cgo(a, base.Tool("cgo"), objdir, pcCFLAGS, pcLDFLAGS, mkAbsFiles(a.Package.Dir, cgofiles), gccfiles, cxxfiles, a.Package.MFiles, a.Package.FFiles)
+ outGo, outObj, err := b.cgo(a, base.Tool("cgo"), objdir, pcCFLAGS, pcMSCFLAGS, pcLDFLAGS, pcMSLDFLAGS, mkAbsFiles(a.Package.Dir, cgofiles), gccfiles, cxxfiles, a.Package.MFiles, a.Package.FFiles)
if err != nil {
return err
}
@@ -2038,11 +2053,49 @@
return noCompiler()
}

+// toolchainCc runs the toolchain C compiler to create an object from a single C file.
+func (b *Builder) toolchainCc(a *Action, p *load.Package, workdir, out string, flags []string, cfile string) error {
+ if cfg.BuildContext.CompilerType == "msvc" {
+ return b.msvccc(a, p, workdir, out, flags, cfile)
+ }
+ return b.gcc(a, p, workdir, out, flags, cfile)
+}
+
+// toolchainGxx runs the toolchain C++ compiler to create an object from a single C++ file.
+func (b *Builder) toolchainGxx(a *Action, p *load.Package, workdir, out string, flags []string, cfile string) error {
+ if cfg.BuildContext.CompilerType == "msvc" {
+ return b.msvccxx(a, p, workdir, out, flags, cfile)
+ }
+ return b.gxx(a, p, workdir, out, flags, cfile)
+}
+
// gcc runs the gcc C compiler to create an object from a single C file.
func (b *Builder) gcc(a *Action, p *load.Package, workdir, out string, flags []string, cfile string) error {
return b.ccompile(a, p, out, flags, cfile, b.GccCmd(p.Dir, workdir))
}

+// msvccc runs the msvc C compiler or assemblers to create an object from
+// a single source file.
+func (b *Builder) msvccc(a *Action, p *load.Package, workdir, out string, flags []string, cfile string) error {
+ if strings.HasSuffix(strings.ToLower(cfile), ".s") {
+ return b.msvcassemble(a, p, out, flags, cfile, b.MsvcAsmCmd(p.Dir, workdir))
+ } else {
+ flags = append(flags, "/Tc"+filepath.Base(cfile))
+ return b.msvccompile(a, p, out, flags, cfile, b.MsvcCcCmd(p.Dir, workdir))
+ }
+}
+
+// msvccc runs the msvc C compiler or assemblers to create an object from
+// a single source file.
+func (b *Builder) msvccxx(a *Action, p *load.Package, workdir, out string, flags []string, cfile string) error {
+ if strings.HasSuffix(strings.ToLower(cfile), ".s") {
+ return b.msvcassemble(a, p, out, flags, cfile, b.MsvcAsmCmd(p.Dir, workdir))
+ } else {
+ flags = append(flags, "/Tp"+filepath.Base(cfile))
+ return b.msvccompile(a, p, out, flags, cfile, b.MsvcCcCmd(p.Dir, workdir))
+ }
+}
+
// gxx runs the g++ C++ compiler to create an object from a single C++ file.
func (b *Builder) gxx(a *Action, p *load.Package, workdir, out string, flags []string, cxxfile string) error {
return b.ccompile(a, p, out, flags, cxxfile, b.GxxCmd(p.Dir, workdir))
@@ -2053,7 +2106,71 @@
return b.ccompile(a, p, out, flags, ffile, b.gfortranCmd(p.Dir, workdir))
}

-// ccompile runs the given C or C++ compiler and creates an object from a single source file.
+// msvccompile runs the given C or C++ compiler and creates an object from a single source file.
+func (b *Builder) msvccompile(a *Action, p *load.Package, outfile string, flags []string, file string, compiler []string) error {
+ file = mkAbs(p.Dir, file)
+ desc := p.ImportPath
+ if !filepath.IsAbs(outfile) {
+ outfile = filepath.Join(p.Dir, outfile)
+ }
+
+ // TODO enable debugging information?
+ // flags = str.StringList(flags, "/Zi")
+
+ staticSet := false
+ for _, p := range flags {
+ if p == "/ML" || p == "/MLd" || p == "/MT" || p == "/MTd" || p == "/MDd" {
+ staticSet = true
+ }
+ }
+ if !staticSet {
+ flags = str.StringList(flags, "/MD")
+ }
+ flags = str.StringList(flags, "/nologo")
+ output, err := b.runOut(filepath.Dir(file), nil, compiler, flags, "/Fo"+outfile)
+ if len(output) > 0 {
+ headerless := b.stripMsvcHeader(output, filepath.Base(file))
+ if len(headerless) > 0 {
+ b.showOutput(a, p.Dir, desc, b.processOutput(output))
+ if err != nil {
+ err = errPrintedOutput
+ } else if os.Getenv("GO_BUILDER_NAME") != "" {
+ return errors.New("C compiler warning promoted to error on Go builders")
+ }
+ }
+ }
+ return err
+}
+
+// msvcassemble runs the given asm and creates an object from a single
+// source file.
+func (b *Builder) msvcassemble(a *Action, p *load.Package, outfile string, flags []string, file string, compiler []string) error {
+ file = mkAbs(p.Dir, file)
+ desc := p.ImportPath
+ if !filepath.IsAbs(outfile) {
+ outfile = filepath.Join(p.Dir, outfile)
+ }
+ flags = b.msvcConvertAsmFlags(flags)
+
+ flags = str.StringList(flags, "/c", "/Cx", "/Zi", "/nologo")
+
+ output, err := b.runOut(filepath.Dir(file), nil, compiler, flags, "/Fo"+outfile, filepath.Base(file))
+ if len(output) > 0 {
+ headerless := b.stripMsvcHeader(output, filepath.Base(file))
+ if len(headerless) > 0 {
+ b.showOutput(a, p.Dir, desc, b.processOutput(output))
+ if err != nil {
+ err = errPrintedOutput
+ } else if os.Getenv("GO_BUILDER_NAME") != "" {
+ return errors.New("C compiler warning promoted to error on Go builders")
+ }
+ }
+ }
+ return err
+}
+
+// ccompile runs the given C or C++ compiler and creates an object from a
+// single source file.
func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []string, file string, compiler []string) error {
file = mkAbs(p.Dir, file)
desc := p.ImportPath
@@ -2092,6 +2209,15 @@
return err
}

+// toolchainLd runs the toolchain linker to create an executable from a set of
+// object files.
+func (b *Builder) toolchainLd(p *load.Package, objdir, out string, flags []string, objs []string) error {
+ if cfg.BuildContext.CompilerType == "msvc" {
+ return b.msvcld(p, objdir, out, flags, objs)
+ }
+ return b.gccld(p, objdir, out, flags, objs)
+}
+
// gccld runs the gcc linker to create an executable from a set of object files.
func (b *Builder) gccld(p *load.Package, objdir, out string, flags []string, objs []string) error {
var cmd []string
@@ -2103,32 +2229,95 @@
return b.run(nil, p.Dir, p.ImportPath, b.cCompilerEnv(), cmd, "-o", out, objs, flags)
}

+// msvcld runs the msvc linker to create an executable from a set of object files.
+func (b *Builder) msvcld(p *load.Package, objdir, out string, flags []string, objs []string) error {
+ var cmd []string
+ cmd = b.MsvcLinkCmd(p.Dir, objdir)
+ flags = str.StringList(flags, "/NOLOGO")
+
+ output, err := b.runOut(p.Dir, nil, cmd, "/OUT:"+out, objs, flags)
+ if len(out) > 0 {
+ headerless := b.stripMsvcHeader(output, "x")
+ if len(headerless) > 0 {
+ b.showOutput(nil, p.Dir, p.ImportPath, b.processOutput(output))
+ if err != nil {
+ err = errPrintedOutput
+ }
+ }
+ }
+ return err
+}
+
// Grab these before main helpfully overwrites them.
var (
- origCC = os.Getenv("CC")
- origCXX = os.Getenv("CXX")
+ origCC = os.Getenv("CC")
+ origMSCC = os.Getenv("MSCC")
+ origCXX = os.Getenv("CXX")
+ origLD = os.Getenv("LD")
+ origASM = os.Getenv("ASM")
)

// gccCmd returns a gcc command line prefix
// defaultCC is defined in zdefaultcc.go, written by cmd/dist.
func (b *Builder) GccCmd(incdir, workdir string) []string {
- return b.compilerCmd(b.ccExe(), incdir, workdir)
+ return b.gccCompilerCmd(b.ccExe(), incdir, workdir)
+}
+
+// MsvcCcCmd returns a msvc cc command line prefix
+func (b *Builder) MsvcCcCmd(incdir, workdir string) []string {
+ return b.msvcCompilerCmd(b.ccExe(), incdir, workdir)
+}
+
+// MsvcAsmCmd returns a msvc asm command line prefix
+func (b *Builder) MsvcAsmCmd(incdir, workdir string) []string {
+ return b.msvcAssemblerCmd(b.asmExe(), incdir, workdir)
+}
+
+// MsvcLinkCmd returns a msvc link command line prefix
+func (b *Builder) MsvcLinkCmd(incdir, workdir string) []string {
+ return b.msvcLinkCmd(b.ldExe(), incdir, workdir)
}

// gxxCmd returns a g++ command line prefix
// defaultCXX is defined in zdefaultcc.go, written by cmd/dist.
func (b *Builder) GxxCmd(incdir, workdir string) []string {
- return b.compilerCmd(b.cxxExe(), incdir, workdir)
+ return b.gccCompilerCmd(b.cxxExe(), incdir, workdir)
}

// gfortranCmd returns a gfortran command line prefix.
func (b *Builder) gfortranCmd(incdir, workdir string) []string {
- return b.compilerCmd(b.fcExe(), incdir, workdir)
+ return b.gccCompilerCmd(b.fcExe(), incdir, workdir)
}

// 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(cfg.Goos, cfg.Goarch))
+ if cfg.BuildContext.CompilerType == "msvc" {
+ return b.compilerExe(origMSCC, "cl.exe")
+ } else {
+ return b.compilerExe(origCC, cfg.DefaultCC(cfg.Goos, cfg.Goarch))
+ }
+}
+
+// asmExe returns the Assember setting without all the extra flags we add implicitly.
+func (b *Builder) asmExe() []string {
+ if cfg.BuildContext.CompilerType == "msvc" {
+ if cfg.Goarch == "x64" || cfg.Goarch == "amd64" {
+ return b.compilerExe(origASM, "ml64.exe")
+ } else {
+ return b.compilerExe(origASM, "ml.exe")
+ }
+ } else {
+ return b.compilerExe(origASM, cfg.DefaultCC(cfg.Goos, cfg.Goarch))
+ }
+}
+
+// ldExe returns the Linker setting without all the extra flags we add implicitly.
+func (b *Builder) ldExe() []string {
+ if cfg.BuildContext.CompilerType == "msvc" {
+ return b.compilerExe(origLD, "link.exe")
+ } else {
+ return b.compilerExe(origLD, cfg.DefaultCC(cfg.Goos, cfg.Goarch))
+ }
}

// cxxExe returns the CXX compiler setting without all the extra flags we add implicitly.
@@ -2155,9 +2344,9 @@
return compiler
}

-// compilerCmd returns a command line prefix for the given environment
+// gccCompilerCmd returns a command line prefix for the given environment
// variable and using the default command when the variable is empty.
-func (b *Builder) compilerCmd(compiler []string, incdir, workdir string) []string {
+func (b *Builder) gccCompilerCmd(compiler []string, incdir, workdir string) []string {
// NOTE: env.go's mkEnv knows that the first three
// strings returned are "gcc", "-I", incdir (and cuts them off).
a := []string{compiler[0], "-I", incdir}
@@ -2217,6 +2406,29 @@
return a
}

+// msvcCompilerCmd returns a command line prefix for the given environment
+// variable and using the default command when the variable is empty.
+func (b *Builder) msvcCompilerCmd(compiler []string, incdir, workdir string) []string {
+ a := []string{compiler[0], "/I", incdir}
+ a = append(a, compiler[1:]...)
+
+ return a
+}
+
+// msvcLinkCmd returns a command line prefix for the given environment
+// variable and using the default command when the variable is empty.
+func (b *Builder) msvcLinkCmd(compiler []string, incdir, workdir string) []string {
+ a := compiler
+ return a
+}
+
+// msvcAssemblerCmd returns a command line prefix for the given environment
+// variable and using the default command when the variable is empty.
+func (b *Builder) msvcAssemblerCmd(compiler []string, incdir, workdir string) []string {
+ a := compiler
+ return a
+}
+
// gccNoPie returns the flag to use to request non-PIE. On systems
// with PIE (position independent executables) enabled by default,
// -no-pie must be passed when doing a partial link with -Wl,-r.
@@ -2231,6 +2443,51 @@
return ""
}

+// stripMSVCHeader strips extra messanging from executing MSVC tools.
+// MSVC tools always output messaging, there is no way to silence them
+// strip out the known formatting to prevent mistaken assumption of errors
+func (b *Builder) stripMsvcHeader(output []byte, filename string) []byte {
+ var headerless []byte
+ headerless = output
+ if idx := bytes.Index(headerless, []byte("Microsoft (R) C/C++ Optimizing Compiler")); idx == 0 {
+ headerless = headerless[bytes.Index(output, []byte("\n"))+1:]
+ }
+ if idx := bytes.Index(headerless, []byte("Microsoft (R) Incremental Linker Version")); idx == 0 {
+ headerless = headerless[bytes.Index(headerless, []byte("\n"))+1:]
+ }
+ if idx := bytes.Index(headerless, []byte("Assembling: "+filename)); idx == 0 {
+ headerless = headerless[bytes.Index(headerless, []byte("\n"))+1:]
+ }
+ if idx := bytes.Index(headerless, []byte(" Assembling: "+filename)); idx == 0 {
+ headerless = headerless[bytes.Index(headerless, []byte("\n"))+1:]
+ }
+ if idx := bytes.Index(headerless, []byte("\r\n")); idx == 0 {
+ headerless = headerless[bytes.Index(headerless, []byte("\n"))+1:]
+ }
+ if idx := bytes.Index(headerless, []byte("\n")); idx == 0 {
+ headerless = headerless[bytes.Index(headerless, []byte("\n"))+1:]
+ }
+ if idx := bytes.Index(headerless, []byte("Microsoft (R) Macro Assembler")); idx == 0 {
+ headerless = headerless[bytes.Index(headerless, []byte("\n"))+1:]
+ }
+ if idx := bytes.Index(headerless, []byte("Copyright (C) Microsoft Corporation. All rights reserved.")); idx == 0 {
+ headerless = headerless[bytes.Index(headerless, []byte("\n"))+1:]
+ }
+ if idx := bytes.Index(headerless, []byte("\r\n")); idx == 0 {
+ headerless = headerless[bytes.Index(headerless, []byte("\n"))+1:]
+ }
+ if idx := bytes.Index(headerless, []byte("\n")); idx == 0 {
+ headerless = headerless[bytes.Index(headerless, []byte("\n"))+1:]
+ }
+ if idx := bytes.Index(headerless, []byte(filepath.Base(filename))); idx == 0 {
+ headerless = headerless[bytes.Index(headerless, []byte("\n"))+1:]
+ }
+ if idx := bytes.Index(headerless, []byte("Assembling: "+filepath.Base(filename))); idx == 0 || idx == 1 {
+ headerless = headerless[bytes.Index(headerless, []byte("\n"))+1:]
+ }
+ return headerless
+}
+
// gccSupportsFlag checks to see if the compiler supports a flag.
func (b *Builder) gccSupportsFlag(compiler []string, flag string) bool {
key := [2]string{compiler[0], flag}
@@ -2305,6 +2562,9 @@
func (b *Builder) CFlags(p *load.Package) (cppflags, cflags, cxxflags, mscppflags, mscflags, mscxxflags, fflags, msldflags, ldflags []string, err error) {
var defaults string

+ if cfg.BuildContext.CompilerType != "msvc" {
+ defaults = "-g -O2"
+ }

if cppflags, err = buildFlags("CPPFLAGS", "", p.CgoCPPFLAGS, checkCompilerFlags); err != nil {
return
@@ -2315,6 +2575,20 @@
if cxxflags, err = buildFlags("CXXFLAGS", defaults, p.CgoCXXFLAGS, checkCompilerFlags); err != nil {
return
}
+ if cfg.BuildContext.CompilerType == "msvc" {
+ if mscppflags, err = buildFlags("MSCPPFLAGS", "", p.CgoMSCPPFLAGS, checkCompilerFlags); err != nil {
+ return
+ }
+ if mscflags, err = buildFlags("MSCFLAGS", "", p.CgoMSCFLAGS, checkCompilerFlags); err != nil {
+ return
+ }
+ if mscxxflags, err = buildFlags("MSCXXFLAGS", "", p.CgoMSCXXFLAGS, checkCompilerFlags); err != nil {
+ return
+ }
+ if msldflags, err = buildFlags("MSLDFLAGS", "", p.CgoMSLDFLAGS, checkLinkerFlags); err != nil {
+ return
+ }
+ }
if fflags, err = buildFlags("FFLAGS", defaults, p.CgoFFLAGS, checkCompilerFlags); err != nil {
return
}
@@ -2334,7 +2608,7 @@

var cgoRe = regexp.MustCompile(`[/\\:]`)

-func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) {
+func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcMSCFLAGS, pcLDFLAGS, pcMSLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) {
p := a.Package
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoMSCPPFLAGS, cgoMSCFLAGS, cgoMSCXXFLAGS, cgoFFLAGS, cgoMSLDFLAGS, cgoLDFLAGS, err := b.CFlags(p)
if err != nil {
@@ -2343,6 +2617,18 @@

cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
+ if cfg.BuildContext.CompilerType == "msvc" {
+ cgoMSCPPFLAGS = append(cgoMSCPPFLAGS, pcMSCFLAGS...)
+ cgoMSCPPFLAGS = append(cgoMSCPPFLAGS, "/c")
+ cgoMSCPPFLAGS = append(cgoMSCPPFLAGS, "/Wall")
+ cgoMSCPPFLAGS = append(cgoMSCPPFLAGS, "/wd4100")
+ cgoMSCPPFLAGS = append(cgoMSCPPFLAGS, "/wd4255")
+ cgoMSCPPFLAGS = append(cgoMSCPPFLAGS, "/wd4514")
+
+ cgoMSLDFLAGS = append(cgoMSLDFLAGS, pcMSLDFLAGS...)
+ cgoMSLDFLAGS = str.StringList(b.msvcConvertLdFlags(cgoLDFLAGS), cgoMSLDFLAGS)
+ }
+
// If we are compiling Objective-C code, then we need to link against libobjc
if len(mfiles) > 0 {
cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
@@ -2404,6 +2690,15 @@
}
cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")}
}
+ if cfg.BuildContext.CompilerType == "msvc" {
+ if len(cgoMSLDFLAGS) > 0 {
+ flags := make([]string, len(cgoMSLDFLAGS))
+ for i, f := range cgoMSLDFLAGS {
+ flags[i] = strconv.Quote(f)
+ }
+ cgoenv = []string{"CGO_MSLDFLAGS=" + strings.Join(flags, " ")}
+ }
+ }

if cfg.BuildToolchainName == "gccgo" {
switch cfg.Goarch {
@@ -2424,6 +2719,10 @@
cgoflags = append(cgoflags, "-exportheader="+objdir+"_cgo_install.h")
}

+ if cfg.BuildContext.CompilerType == "msvc" {
+ cgoflags = append(cgoflags, "-toolchain=msvc")
+ }
+
if err := b.run(a, p.Dir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, "-objdir", objdir, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil {
return nil, nil, err
}
@@ -2441,11 +2740,18 @@
return objdir + fmt.Sprintf("_x%03d.o", oseq)
}

- // gcc
- cflags := str.StringList(cgoCPPFLAGS, cgoCFLAGS)
+ // gcc/msvc
+ cflags := []string{}
+ passcflags := []string{}
+ if cfg.BuildContext.CompilerType == "msvc" {
+ cflags = str.StringList(b.msvcConvertFlags(cgoCPPFLAGS), b.msvcConvertFlags(cgoCFLAGS), cgoMSCPPFLAGS, cgoMSCFLAGS)
+ passcflags = str.StringList(cgoCPPFLAGS, cgoCFLAGS)
+ } else {
+ cflags = str.StringList(cgoCPPFLAGS, cgoCFLAGS)
+ }
for _, cfile := range cfiles {
ofile := nextOfile()
- if err := b.gcc(a, p, a.Objdir, ofile, cflags, objdir+cfile); err != nil {
+ if err := b.toolchainCc(a, p, a.Objdir, ofile, cflags, objdir+cfile); err != nil {
return nil, nil, err
}
outObj = append(outObj, ofile)
@@ -2453,16 +2759,21 @@

for _, file := range gccfiles {
ofile := nextOfile()
- if err := b.gcc(a, p, a.Objdir, ofile, cflags, file); err != nil {
+ if err := b.toolchainCc(a, p, a.Objdir, ofile, cflags, file); err != nil {
return nil, nil, err
}
outObj = append(outObj, ofile)
}

- cxxflags := str.StringList(cgoCPPFLAGS, cgoCXXFLAGS)
+ cxxflags := []string{}
+ if cfg.BuildContext.CompilerType == "msvc" {
+ cxxflags = str.StringList(b.msvcConvertFlags(cgoCPPFLAGS), b.msvcConvertFlags(cgoCXXFLAGS), cgoMSCPPFLAGS, cgoMSCXXFLAGS)
+ } else {
+ cxxflags = str.StringList(cgoCPPFLAGS, cgoCXXFLAGS)
+ }
for _, file := range gxxfiles {
ofile := nextOfile()
- if err := b.gxx(a, p, a.Objdir, ofile, cxxflags, file); err != nil {
+ if err := b.toolchainGxx(a, p, a.Objdir, ofile, cxxflags, file); err != nil {
return nil, nil, err
}
outObj = append(outObj, ofile)
@@ -2470,7 +2781,7 @@

for _, file := range mfiles {
ofile := nextOfile()
- if err := b.gcc(a, p, a.Objdir, ofile, cflags, file); err != nil {
+ if err := b.toolchainCc(a, p, a.Objdir, ofile, cflags, file); err != nil {
return nil, nil, err
}
outObj = append(outObj, ofile)
@@ -2488,7 +2799,7 @@
switch cfg.BuildToolchainName {
case "gc":
importGo := objdir + "_cgo_import.go"
- if err := b.dynimport(a, p, objdir, importGo, cgoExe, cflags, cgoLDFLAGS, outObj); err != nil {
+ if err := b.dynimport(a, p, objdir, importGo, cgoExe, passcflags, cflags, cgoLDFLAGS, cgoMSLDFLAGS, outObj); err != nil {
return nil, nil, err
}
outGo = append(outGo, importGo)
@@ -2511,11 +2822,17 @@
// dynimport creates a Go source file named importGo containing
// //go:cgo_import_dynamic directives for each symbol or library
// dynamically imported by the object files outObj.
-func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) error {
+func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe string, cflags, mscflags, cgoLDFLAGS, cgoMSLDFLAGS, outObj []string) error {
cfile := objdir + "_cgo_main.c"
ofile := objdir + "_cgo_main.o"
- if err := b.gcc(a, p, objdir, ofile, cflags, cfile); err != nil {
- return err
+ if cfg.BuildContext.CompilerType == "msvc" {
+ if err := b.toolchainCc(a, p, objdir, ofile, mscflags, cfile); err != nil {
+ return err
+ }
+ } else {
+ if err := b.toolchainCc(a, p, objdir, ofile, cflags, cfile); err != nil {
+ return err
+ }
}

linkobj := str.StringList(ofile, outObj, p.SysoFiles)
@@ -2534,8 +2851,14 @@
}
ldflags = append(n, "-pie")
}
- if err := b.gccld(p, objdir, dynobj, ldflags, linkobj); err != nil {
- return err
+ if cfg.BuildContext.CompilerType == "msvc" {
+ if err := b.toolchainLd(p, objdir, dynobj, cgoMSLDFLAGS, linkobj); err != nil {
+ return err
+ }
+ } else {
+ if err := b.toolchainLd(p, objdir, dynobj, ldflags, linkobj); err != nil {
+ return err
+ }
}

// cgo -dynimport
@@ -2779,6 +3102,84 @@
return newGoFile, objdir + gccBase + gccExt, nil
}

+// msvcConvertFlags make a simple effort to convert
+// some of the common gcc flags to msvc
+func (b *Builder) msvcConvertFlags(flags []string) []string {
+ var newFlags []string
+ for i, flag := range flags {
+ flagValue := strings.TrimSpace(flag)
+ if strings.HasPrefix(flagValue, "-D") || strings.HasPrefix(flagValue, "/D") {
+ if strings.TrimSpace(flagValue[2:]) == "" {
+ newFlags = append(newFlags, "/D"+flags[i+1])
+ } else {
+ newFlags = append(newFlags, "/D"+flagValue[2:])
+ }
+ } else if strings.HasPrefix(flagValue, "-I") || strings.HasPrefix(flagValue, "/D") {
+ if strings.TrimSpace(flagValue[2:]) == "" {
+ newFlags = append(newFlags, "/I"+flags[i+1])
+ } else {
+ newFlags = append(newFlags, "/I"+flagValue[2:])
+ }
+ } else if strings.HasPrefix(flagValue, "-Werror") {
+ newFlags = append(newFlags, "/WX")
+ } else if strings.HasPrefix(flagValue, "-std") {
+ newFlags = append(newFlags, "/std:"+flagValue[5:])
+ } else if strings.HasPrefix(flagValue, "/") {
+ newFlags = append(newFlags, flagValue)
+ }
+ }
+ return newFlags
+}
+
+// msvcConvertLdFlags make a simple effort to convert
+// some of the common gcc flags to msvc
+func (b *Builder) msvcConvertLdFlags(flags []string) []string {
+ var newFlags []string
+ for i, flag := range flags {
+ flagValue := strings.TrimSpace(flag)
+ if strings.HasPrefix(flagValue, "-L") {
+ if strings.TrimSpace(flagValue[2:]) == "" {
+ newFlags = append(newFlags, "/LIBPATH:"+flags[i+1])
+ } else {
+ newFlags = append(newFlags, "/LIBPATH:"+flagValue[2:])
+ }
+ } else if flagValue == "-lm" {
+ // Ignore
+ } else if strings.HasPrefix(flagValue, "-l") {
+ if strings.TrimSpace(flagValue[2:]) == "" {
+ newFlags = append(newFlags, "/DEFAULTLIB:"+flags[i+1])
+ } else {
+ newFlags = append(newFlags, "/DEFAULTLIB:"+flagValue[2:])
+ }
+ } else if strings.HasPrefix(flagValue, "/") {
+ newFlags = append(newFlags, flagValue)
+ }
+ }
+ return newFlags
+}
+
+// msvcConvertAsmFlags make a simple effort to convert
+// some of the common gcc flags to msvc
+func (b *Builder) msvcConvertAsmFlags(flags []string) []string {
+ var newFlags []string
+ for _, flag := range flags {
+ flagValue := strings.TrimSpace(flag)
+ if strings.HasPrefix(flagValue, "-W") || strings.HasPrefix(flagValue, "/W") || strings.HasPrefix(flagValue, "/w") {
+ if flagValue == "-Werror" {
+ newFlags = append(newFlags, "/WX")
+ }
+ if flagValue == "/WX" {
+ newFlags = append(newFlags, flagValue)
+ }
+ } else if strings.HasPrefix(flagValue, "/M") {
+ // Ignore
+ } else if strings.HasPrefix(flagValue, "/") {
+ newFlags = append(newFlags, flagValue)
+ }
+ }
+ return newFlags
+}
+
// disableBuildID adjusts a linker command line to avoid creating a
// build ID when creating an object file rather than an executable or
// shared library. Some systems, such as Ubuntu, always add
diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go
index 6e5333c..a5eb25d 100644
--- a/src/cmd/go/internal/work/gc.go
+++ b/src/cmd/go/internal/work/gc.go
@@ -439,10 +439,16 @@
// by the CXX environment variable or defaultCXX if CXX is not set.
// Else, use the CC environment variable and defaultCC as fallback.
var compiler []string
- if cxx {
- compiler = envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch))
+ if cfg.BuildContext.CompilerType == "msvc" {
+ compiler = envList("LD", "link.exe")
+ ldflags = append(ldflags, "-toolchain=msvc")
+ ldflags = append(ldflags, "-rlocbss")
} else {
- compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
+ if cxx {
+ compiler = envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch))
+ } else {
+ compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
+ }
}
ldflags = append(ldflags, "-buildmode="+ldBuildmode)
if root.buildID != "" {
diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go
index d5d1261..4908483 100644
--- a/src/cmd/go/internal/work/security.go
+++ b/src/cmd/go/internal/work/security.go
@@ -43,12 +43,15 @@
re(`-D([A-Za-z_].*)`),
re(`-F([^@\-].*)`),
re(`-I([^@\-].*)`),
+ re(`/I([^@\-].*)`),
re(`-O`),
re(`-O([^@\-].*)`),
re(`-W`),
re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
re(`-Wa,-mbig-obj`),
re(`-Wp,-D([A-Za-z_].*)`),
+ re(`/EHsc`),
+ re(`/M(t|T|Td|TD|td|L|l|D|d|Dd|DD)`),
re(`-ansi`),
re(`-f(no-)?asynchronous-unwind-tables`),
re(`-f(no-)?blocks`),
@@ -131,6 +134,19 @@
re(`-F([^@\-].*)`),
re(`-l([^@\-].*)`),
re(`-L([^@\-].*)`),
+ re(`/LIB:([^@\-].*)`),
+ re(`/DEFAULTLIB:([^@\-].*)`),
+ re(`/LIBPATH:([^@\-].*)`),
+ re(`/DLL`),
+ re(`/ENTRY:([^@\-].*)`),
+ re(`/INCLUDE:([^@\-].*)`),
+ re(`/INCREMENTAL:([^@\-].*)`),
+ re(`/INCREMENTAL`),
+ re(`/NOENTRY`),
+ re(`/FORCE`),
+ re(`/NODEFAULTLIB:([^@\-].*)`),
+ re(`/NODEFAULTLIB`),
+ re(`/M(t|T|Td|TD|td|L|l|D|d|Dd|DD)`),
re(`-O`),
re(`-O([^@\-].*)`),
re(`-f(no-)?(pic|PIC|pie|PIE)`),
diff --git a/src/run.bat b/src/run.bat
index 0e0c413..69a6179 100644
--- a/src/run.bat
+++ b/src/run.bat
@@ -44,9 +44,34 @@
if errorlevel 1 goto fail
echo.

+if not %GOTESTMSVC%==1 goto end
+
+:: run all the tests again for msvc
+set CC_FOR_CGO=%CC%
+set CC=cl.exe
+set GO_TESTINGMSVC=1
+call %GOVSVARSPATH%
+
+:: get CGO_ENABLED
+go env > env.bat
+if errorlevel 1 goto fail
+call env.bat
+del env.bat
+echo.
+
+SET GOCACHE_OLD=%GOCACHE%
+set GOCACHE=off
+go clean -testcache
+go tool dist test
+set CC=%CC_FOR_CGO%
+set GOCACHE=%GOCACHE_OLD%
+if errorlevel 1 goto fail
+echo.
+
goto end

:fail
set GOBUILDFAIL=1

:end
+

To view, visit change 133946. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced
Gerrit-Change-Number: 133946
Gerrit-PatchSet: 1
Gerrit-Owner: Caleb Champlin <caleb.c...@gmail.com>
Gerrit-MessageType: newchange

Caleb Champlin (Gerrit)

unread,
Sep 7, 2018, 12:48:23 PM9/7/18
to Russ Cox, Ian Lance Taylor, Brad Fitzpatrick, Bryan C. Mills, goph...@pubsubhelper.golang.org, Gobot Gobot, golang-co...@googlegroups.com

Caleb Champlin uploaded patch set #2 to this change.

View Change

cmd/compile: add support for MSVC toolchain to go build


Allows building with MSVC as an external compiler/linker.

Setting CC=cl.exe inside an MSVC environment will automatically
build cgo executables using MSVC as the external compiler and
linker.

For the builders setting the environment variable GOVSVARSPATH
to the location of a msvsvars.bat file and setting the
environment variable GOTESTMSVC=1 will automatically cause
all.bat to run tests and compiler with both gcc and MSVC

Updates #20982

Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced
---
M src/cmd/go/internal/work/build.go
M src/cmd/go/internal/work/exec.go
M src/cmd/go/internal/work/gc.go
M src/cmd/go/internal/work/security.go
M src/run.bat
5 files changed, 542 insertions(+), 32 deletions(-)

To view, visit change 133946. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced
Gerrit-Change-Number: 133946
Gerrit-PatchSet: 2
Gerrit-Owner: Caleb Champlin <caleb.c...@gmail.com>
Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
Gerrit-Reviewer: Bryan C. Mills <bcm...@google.com>
Gerrit-Reviewer: Ian Lance Taylor <ia...@golang.org>
Gerrit-Reviewer: Russ Cox <r...@golang.org>
Gerrit-CC: Gobot Gobot <go...@golang.org>
Gerrit-MessageType: newpatchset

Caleb Champlin (Gerrit)

unread,
Sep 8, 2018, 1:28:48 PM9/8/18
to Russ Cox, Ian Lance Taylor, Brad Fitzpatrick, Bryan C. Mills, goph...@pubsubhelper.golang.org, Gobot Gobot, golang-co...@googlegroups.com

Caleb Champlin uploaded patch set #3 to this change.

View Change

cmd/compile: add support for MSVC toolchain to go build


Allows building with MSVC as an external compiler/linker.

Setting CC=cl.exe inside an MSVC environment will automatically
build cgo executables using MSVC as the external compiler and
linker.

For the builders setting the environment variable GOVSVARSPATH
to the location of a msvsvars.bat file and setting the
environment variable GOTESTMSVC=1 will automatically cause
all.bat to run tests and compiler with both gcc and MSVC.


Updates #20982

Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced
---
M src/cmd/go/internal/work/build.go
M src/cmd/go/internal/work/exec.go
M src/cmd/go/internal/work/gc.go
M src/cmd/go/internal/work/security.go
M src/run.bat
5 files changed, 543 insertions(+), 34 deletions(-)

To view, visit change 133946. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced
Gerrit-Change-Number: 133946
Gerrit-PatchSet: 3

Caleb Champlin (Gerrit)

unread,
Dec 29, 2018, 8:06:05 PM12/29/18
to Russ Cox, Ian Lance Taylor, Brad Fitzpatrick, Bryan C. Mills, goph...@pubsubhelper.golang.org, Gobot Gobot, golang-co...@googlegroups.com

Caleb Champlin uploaded patch set #4 to this change.

View Change

cmd/compile: add support for MSVC toolchain to go build


Allows building with MSVC as an external compiler/linker.

Setting CC=cl.exe inside an MSVC environment will automatically
build cgo executables using MSVC as the external compiler and
linker.

For the builders setting the environment variable GOVSVARSPATH
to the location of a msvsvars.bat file and setting the
environment variable GOTESTMSVC=1 will automatically cause
all.bat to run tests and compiler with both gcc and MSVC.


Updates #20982

Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced
---
M src/cmd/go/internal/work/build.go
M src/cmd/go/internal/work/exec.go
M src/cmd/go/internal/work/gc.go
M src/cmd/go/internal/work/security.go
M src/run.bat
5 files changed, 549 insertions(+), 37 deletions(-)

To view, visit change 133946. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced
Gerrit-Change-Number: 133946
Gerrit-PatchSet: 4

Caleb Champlin (Gerrit)

unread,
Dec 30, 2018, 11:27:58 AM12/30/18
to Russ Cox, Ian Lance Taylor, Brad Fitzpatrick, Bryan C. Mills, goph...@pubsubhelper.golang.org, Gobot Gobot, golang-co...@googlegroups.com

Caleb Champlin uploaded patch set #5 to this change.

View Change

cmd/compile: add support for MSVC toolchain to go build


Allows building with MSVC as an external compiler/linker.

Setting CC=cl.exe inside an MSVC environment will automatically
build cgo executables using MSVC as the external compiler and
linker.

For the builders setting the environment variable GOVSVARSPATH
to the location of a msvsvars.bat file and setting the
environment variable GOTESTMSVC=1 will automatically cause
all.bat to run tests and compiler with both gcc and MSVC.


Updates #20982

Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced
---
M src/cmd/go/internal/work/build.go
M src/cmd/go/internal/work/exec.go
M src/cmd/go/internal/work/gc.go
M src/cmd/go/internal/work/security.go
M src/run.bat
5 files changed, 549 insertions(+), 37 deletions(-)

To view, visit change 133946. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced
Gerrit-Change-Number: 133946
Gerrit-PatchSet: 5

Caleb Champlin (Gerrit)

unread,
Nov 18, 2019, 10:02:18 AM11/18/19
to Bryan C. Mills, Brad Fitzpatrick, Ian Lance Taylor, Russ Cox, goph...@pubsubhelper.golang.org, Gobot Gobot, golang-co...@googlegroups.com

Caleb Champlin uploaded patch set #6 to this change.

View Change

cmd/compile: add support for MSVC toolchain to go build


Allows building with MSVC as an external compiler/linker.

Setting CC=cl.exe inside an MSVC environment will automatically
build cgo executables using MSVC as the external compiler and
linker.

For the builders setting the environment variable GOVSVARSPATH
to the location of a msvsvars.bat file and setting the
environment variable GOTESTMSVC=1 will automatically cause
all.bat to run tests and compiler with both gcc and MSVC.


Updates #20982

Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced
---
M src/cmd/go/internal/work/build.go
M src/cmd/go/internal/work/exec.go
M src/cmd/go/internal/work/gc.go
M src/cmd/go/internal/work/security.go
M src/internal/cfg/cfg.go
M src/run.bat
6 files changed, 553 insertions(+), 38 deletions(-)

To view, visit change 133946. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced
Gerrit-Change-Number: 133946
Gerrit-PatchSet: 6

Bryan C. Mills (Gerrit)

unread,
Nov 18, 2019, 1:25:21 PM11/18/19
to Caleb Champlin, goph...@pubsubhelper.golang.org, Bryan C. Mills, Ian Lance Taylor, Brad Fitzpatrick, Russ Cox, Gobot Gobot, golang-co...@googlegroups.com

Note that we are currently in the code freeze for Go 1.14.¹

This stack of changes will need to wait for the tree to open for 1.15 before it can be merged.

¹https://groups.google.com/d/msg/golang-dev/Fdbjn-1UMU0/XZmeI7dNEQAJ

View Change

    To view, visit change 133946. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-Change-Id: I44be1f43aa0d53a688c595bc8336e0364b809ced
    Gerrit-Change-Number: 133946
    Gerrit-PatchSet: 6
    Gerrit-Owner: Caleb Champlin <caleb.c...@gmail.com>
    Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-Reviewer: Bryan C. Mills <bcm...@google.com>
    Gerrit-Reviewer: Ian Lance Taylor <ia...@golang.org>
    Gerrit-Reviewer: Russ Cox <r...@golang.org>
    Gerrit-CC: Gobot Gobot <go...@golang.org>
    Gerrit-Comment-Date: Mon, 18 Nov 2019 18:25:18 +0000
    Gerrit-HasComments: No
    Gerrit-Has-Labels: No
    Gerrit-MessageType: comment
    Reply all
    Reply to author
    Forward
    0 new messages