Initial commit: Go 1.23 release state
This commit is contained in:
21
src/cmd/dist/README
vendored
Normal file
21
src/cmd/dist/README
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
This program, dist, is the bootstrapping tool for the Go distribution.
|
||||
|
||||
As of Go 1.5, dist and other parts of the compiler toolchain are written
|
||||
in Go, making bootstrapping a little more involved than in the past.
|
||||
The approach is to build the current release of Go with an earlier one.
|
||||
|
||||
The process to install Go 1.x, for x ≥ 22, is:
|
||||
|
||||
1. Build cmd/dist with Go 1.20.6.
|
||||
2. Using dist, build Go 1.x compiler toolchain with Go 1.20.6.
|
||||
3. Using dist, rebuild Go 1.x compiler toolchain with itself.
|
||||
4. Using dist, build Go 1.x cmd/go (as go_bootstrap) with Go 1.x compiler toolchain.
|
||||
5. Using go_bootstrap, build the remaining Go 1.x standard library and commands.
|
||||
|
||||
Because of backward compatibility, although the steps above say Go 1.20.6,
|
||||
in practice any release ≥ Go 1.20.6 but < Go 1.x will work as the bootstrap base.
|
||||
Releases ≥ Go 1.x are very likely to work as well.
|
||||
|
||||
See https://go.dev/s/go15bootstrap for more details about the original bootstrap
|
||||
and https://go.dev/issue/54265 for details about later bootstrap version bumps.
|
||||
|
||||
1980
src/cmd/dist/build.go
vendored
Normal file
1980
src/cmd/dist/build.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
26
src/cmd/dist/build_test.go
vendored
Normal file
26
src/cmd/dist/build_test.go
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"internal/platform"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestMustLinkExternal verifies that the mustLinkExternal helper
|
||||
// function matches internal/platform.MustLinkExternal.
|
||||
func TestMustLinkExternal(t *testing.T) {
|
||||
for _, goos := range okgoos {
|
||||
for _, goarch := range okgoarch {
|
||||
for _, cgoEnabled := range []bool{true, false} {
|
||||
got := mustLinkExternal(goos, goarch, cgoEnabled)
|
||||
want := platform.MustLinkExternal(goos, goarch, cgoEnabled)
|
||||
if got != want {
|
||||
t.Errorf("mustLinkExternal(%q, %q, %v) = %v; want %v", goos, goarch, cgoEnabled, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
162
src/cmd/dist/buildgo.go
vendored
Normal file
162
src/cmd/dist/buildgo.go
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
* Helpers for building cmd/go and cmd/cgo.
|
||||
*/
|
||||
|
||||
// generatedHeader is the string that all source files generated by dist start with.
|
||||
//
|
||||
// DO NOT CHANGE THIS STRING. If this string is changed then during
|
||||
//
|
||||
// ./make.bash
|
||||
// git checkout other-rev
|
||||
// ./make.bash
|
||||
//
|
||||
// the second make.bash will not find the files generated by the first make.bash
|
||||
// and will not clean up properly.
|
||||
const generatedHeader = "// Code generated by go tool dist; DO NOT EDIT.\n\n"
|
||||
|
||||
// writeHeader emits the standard "generated by" header for all files generated
|
||||
// by dist.
|
||||
func writeHeader(w io.Writer) {
|
||||
fmt.Fprint(w, generatedHeader)
|
||||
}
|
||||
|
||||
// mkzdefaultcc writes zdefaultcc.go:
|
||||
//
|
||||
// package main
|
||||
// const defaultCC = <defaultcc>
|
||||
// const defaultCXX = <defaultcxx>
|
||||
// const defaultPkgConfig = <defaultpkgconfig>
|
||||
//
|
||||
// It is invoked to write cmd/go/internal/cfg/zdefaultcc.go
|
||||
// but we also write cmd/cgo/zdefaultcc.go
|
||||
func mkzdefaultcc(dir, file string) {
|
||||
if strings.Contains(file, filepath.FromSlash("go/internal/cfg")) {
|
||||
var buf strings.Builder
|
||||
writeHeader(&buf)
|
||||
fmt.Fprintf(&buf, "package cfg\n")
|
||||
fmt.Fprintln(&buf)
|
||||
fmt.Fprintf(&buf, "const DefaultPkgConfig = `%s`\n", defaultpkgconfig)
|
||||
buf.WriteString(defaultCCFunc("DefaultCC", defaultcc))
|
||||
buf.WriteString(defaultCCFunc("DefaultCXX", defaultcxx))
|
||||
writefile(buf.String(), file, writeSkipSame)
|
||||
return
|
||||
}
|
||||
|
||||
var buf strings.Builder
|
||||
writeHeader(&buf)
|
||||
fmt.Fprintf(&buf, "package main\n")
|
||||
fmt.Fprintln(&buf)
|
||||
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 strings.Builder
|
||||
|
||||
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 %s:\n\t\treturn %s\n", quote(k), quote(defaultcc[k]))
|
||||
}
|
||||
fmt.Fprintf(&buf, "\t}\n")
|
||||
if cc := defaultcc[""]; cc != "" {
|
||||
fmt.Fprintf(&buf, "\treturn %s\n", quote(cc))
|
||||
} else {
|
||||
clang, gcc := "clang", "gcc"
|
||||
if strings.HasSuffix(name, "CXX") {
|
||||
clang, gcc = "clang++", "g++"
|
||||
}
|
||||
fmt.Fprintf(&buf, "\tswitch goos {\n")
|
||||
fmt.Fprintf(&buf, "\tcase ")
|
||||
for i, os := range clangos {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(&buf, ", ")
|
||||
}
|
||||
fmt.Fprintf(&buf, "%s", quote(os))
|
||||
}
|
||||
fmt.Fprintf(&buf, ":\n")
|
||||
fmt.Fprintf(&buf, "\t\treturn %s\n", quote(clang))
|
||||
fmt.Fprintf(&buf, "\t}\n")
|
||||
fmt.Fprintf(&buf, "\treturn %s\n", quote(gcc))
|
||||
}
|
||||
fmt.Fprintf(&buf, "}\n")
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// mkzcgo writes zcgo.go for the go/build package:
|
||||
//
|
||||
// package build
|
||||
// const defaultCGO_ENABLED = <CGO_ENABLED>
|
||||
//
|
||||
// It is invoked to write go/build/zcgo.go.
|
||||
func mkzcgo(dir, file string) {
|
||||
var buf strings.Builder
|
||||
writeHeader(&buf)
|
||||
fmt.Fprintf(&buf, "package build\n")
|
||||
fmt.Fprintln(&buf)
|
||||
fmt.Fprintf(&buf, "const defaultCGO_ENABLED = %s\n", quote(os.Getenv("CGO_ENABLED")))
|
||||
|
||||
writefile(buf.String(), file, writeSkipSame)
|
||||
}
|
||||
|
||||
// mktzdata src/time/tzdata/zzipdata.go:
|
||||
//
|
||||
// package tzdata
|
||||
// const zipdata = "PK..."
|
||||
func mktzdata(dir, file string) {
|
||||
zip := readfile(filepath.Join(dir, "../../../lib/time/zoneinfo.zip"))
|
||||
|
||||
var buf strings.Builder
|
||||
writeHeader(&buf)
|
||||
fmt.Fprintf(&buf, "package tzdata\n")
|
||||
fmt.Fprintln(&buf)
|
||||
fmt.Fprintf(&buf, "const zipdata = %s\n", quote(zip))
|
||||
|
||||
writefile(buf.String(), file, writeSkipSame)
|
||||
}
|
||||
|
||||
// quote is like strconv.Quote but simpler and has output
|
||||
// that does not depend on the exact Go bootstrap version.
|
||||
func quote(s string) string {
|
||||
const hex = "0123456789abcdef"
|
||||
var out strings.Builder
|
||||
out.WriteByte('"')
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if 0x20 <= c && c <= 0x7E && c != '"' && c != '\\' {
|
||||
out.WriteByte(c)
|
||||
} else {
|
||||
out.WriteByte('\\')
|
||||
out.WriteByte('x')
|
||||
out.WriteByte(hex[c>>4])
|
||||
out.WriteByte(hex[c&0xf])
|
||||
}
|
||||
}
|
||||
out.WriteByte('"')
|
||||
return out.String()
|
||||
}
|
||||
83
src/cmd/dist/buildruntime.go
vendored
Normal file
83
src/cmd/dist/buildruntime.go
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
* Helpers for building runtime.
|
||||
*/
|
||||
|
||||
// mkzversion writes zversion.go:
|
||||
//
|
||||
// package sys
|
||||
//
|
||||
// (Nothing right now!)
|
||||
func mkzversion(dir, file string) {
|
||||
var buf strings.Builder
|
||||
writeHeader(&buf)
|
||||
fmt.Fprintf(&buf, "package sys\n")
|
||||
writefile(buf.String(), file, writeSkipSame)
|
||||
}
|
||||
|
||||
// mkbuildcfg writes internal/buildcfg/zbootstrap.go:
|
||||
//
|
||||
// package buildcfg
|
||||
//
|
||||
// const defaultGOROOT = <goroot>
|
||||
// const defaultGO386 = <go386>
|
||||
// ...
|
||||
// const defaultGOOS = runtime.GOOS
|
||||
// const defaultGOARCH = runtime.GOARCH
|
||||
//
|
||||
// The use of runtime.GOOS and runtime.GOARCH makes sure that
|
||||
// a cross-compiled compiler expects to compile for its own target
|
||||
// system. That is, if on a Mac you do:
|
||||
//
|
||||
// GOOS=linux GOARCH=ppc64 go build cmd/compile
|
||||
//
|
||||
// the resulting compiler will default to generating linux/ppc64 object files.
|
||||
// This is more useful than having it default to generating objects for the
|
||||
// original target (in this example, a Mac).
|
||||
func mkbuildcfg(file string) {
|
||||
var buf strings.Builder
|
||||
writeHeader(&buf)
|
||||
fmt.Fprintf(&buf, "package buildcfg\n")
|
||||
fmt.Fprintln(&buf)
|
||||
fmt.Fprintf(&buf, "import \"runtime\"\n")
|
||||
fmt.Fprintln(&buf)
|
||||
fmt.Fprintf(&buf, "const defaultGO386 = `%s`\n", go386)
|
||||
fmt.Fprintf(&buf, "const defaultGOAMD64 = `%s`\n", goamd64)
|
||||
fmt.Fprintf(&buf, "const defaultGOARM = `%s`\n", goarm)
|
||||
fmt.Fprintf(&buf, "const defaultGOARM64 = `%s`\n", goarm64)
|
||||
fmt.Fprintf(&buf, "const defaultGOMIPS = `%s`\n", gomips)
|
||||
fmt.Fprintf(&buf, "const defaultGOMIPS64 = `%s`\n", gomips64)
|
||||
fmt.Fprintf(&buf, "const defaultGOPPC64 = `%s`\n", goppc64)
|
||||
fmt.Fprintf(&buf, "const defaultGORISCV64 = `%s`\n", goriscv64)
|
||||
fmt.Fprintf(&buf, "const defaultGOEXPERIMENT = `%s`\n", goexperiment)
|
||||
fmt.Fprintf(&buf, "const defaultGO_EXTLINK_ENABLED = `%s`\n", goextlinkenabled)
|
||||
fmt.Fprintf(&buf, "const defaultGO_LDSO = `%s`\n", defaultldso)
|
||||
fmt.Fprintf(&buf, "const version = `%s`\n", findgoversion())
|
||||
fmt.Fprintf(&buf, "const defaultGOOS = runtime.GOOS\n")
|
||||
fmt.Fprintf(&buf, "const defaultGOARCH = runtime.GOARCH\n")
|
||||
|
||||
writefile(buf.String(), file, writeSkipSame)
|
||||
}
|
||||
|
||||
// mkobjabi writes cmd/internal/objabi/zbootstrap.go:
|
||||
//
|
||||
// package objabi
|
||||
//
|
||||
// (Nothing right now!)
|
||||
func mkobjabi(file string) {
|
||||
var buf strings.Builder
|
||||
writeHeader(&buf)
|
||||
fmt.Fprintf(&buf, "package objabi\n")
|
||||
|
||||
writefile(buf.String(), file, writeSkipSame)
|
||||
}
|
||||
133
src/cmd/dist/buildtag.go
vendored
Normal file
133
src/cmd/dist/buildtag.go
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// exprParser is a //go:build expression parser and evaluator.
|
||||
// The parser is a trivial precedence-based parser which is still
|
||||
// almost overkill for these very simple expressions.
|
||||
type exprParser struct {
|
||||
x string
|
||||
t exprToken // upcoming token
|
||||
}
|
||||
|
||||
// val is the value type result of parsing.
|
||||
// We don't keep a parse tree, just the value of the expression.
|
||||
type val bool
|
||||
|
||||
// exprToken describes a single token in the input.
|
||||
// Prefix operators define a prefix func that parses the
|
||||
// upcoming value. Binary operators define an infix func
|
||||
// that combines two values according to the operator.
|
||||
// In that case, the parsing loop parses the two values.
|
||||
type exprToken struct {
|
||||
tok string
|
||||
prec int
|
||||
prefix func(*exprParser) val
|
||||
infix func(val, val) val
|
||||
}
|
||||
|
||||
var exprTokens []exprToken
|
||||
|
||||
func init() { // init to break init cycle
|
||||
exprTokens = []exprToken{
|
||||
{tok: "&&", prec: 1, infix: func(x, y val) val { return x && y }},
|
||||
{tok: "||", prec: 2, infix: func(x, y val) val { return x || y }},
|
||||
{tok: "!", prec: 3, prefix: (*exprParser).not},
|
||||
{tok: "(", prec: 3, prefix: (*exprParser).paren},
|
||||
{tok: ")"},
|
||||
}
|
||||
}
|
||||
|
||||
// matchexpr parses and evaluates the //go:build expression x.
|
||||
func matchexpr(x string) (matched bool, err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
matched = false
|
||||
err = fmt.Errorf("parsing //go:build line: %v", e)
|
||||
}
|
||||
}()
|
||||
|
||||
p := &exprParser{x: x}
|
||||
p.next()
|
||||
v := p.parse(0)
|
||||
if p.t.tok != "end of expression" {
|
||||
panic("unexpected " + p.t.tok)
|
||||
}
|
||||
return bool(v), nil
|
||||
}
|
||||
|
||||
// parse parses an expression, including binary operators at precedence >= prec.
|
||||
func (p *exprParser) parse(prec int) val {
|
||||
if p.t.prefix == nil {
|
||||
panic("unexpected " + p.t.tok)
|
||||
}
|
||||
v := p.t.prefix(p)
|
||||
for p.t.prec >= prec && p.t.infix != nil {
|
||||
t := p.t
|
||||
p.next()
|
||||
v = t.infix(v, p.parse(t.prec+1))
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// not is the prefix parser for a ! token.
|
||||
func (p *exprParser) not() val {
|
||||
p.next()
|
||||
return !p.parse(100)
|
||||
}
|
||||
|
||||
// paren is the prefix parser for a ( token.
|
||||
func (p *exprParser) paren() val {
|
||||
p.next()
|
||||
v := p.parse(0)
|
||||
if p.t.tok != ")" {
|
||||
panic("missing )")
|
||||
}
|
||||
p.next()
|
||||
return v
|
||||
}
|
||||
|
||||
// next advances the parser to the next token,
|
||||
// leaving the token in p.t.
|
||||
func (p *exprParser) next() {
|
||||
p.x = strings.TrimSpace(p.x)
|
||||
if p.x == "" {
|
||||
p.t = exprToken{tok: "end of expression"}
|
||||
return
|
||||
}
|
||||
for _, t := range exprTokens {
|
||||
if strings.HasPrefix(p.x, t.tok) {
|
||||
p.x = p.x[len(t.tok):]
|
||||
p.t = t
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
i := 0
|
||||
for i < len(p.x) && validtag(p.x[i]) {
|
||||
i++
|
||||
}
|
||||
if i == 0 {
|
||||
panic(fmt.Sprintf("syntax error near %#q", rune(p.x[i])))
|
||||
}
|
||||
tag := p.x[:i]
|
||||
p.x = p.x[i:]
|
||||
p.t = exprToken{
|
||||
tok: "tag",
|
||||
prefix: func(p *exprParser) val {
|
||||
p.next()
|
||||
return val(matchtag(tag))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func validtag(c byte) bool {
|
||||
return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '.' || c == '_'
|
||||
}
|
||||
43
src/cmd/dist/buildtag_test.go
vendored
Normal file
43
src/cmd/dist/buildtag_test.go
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var buildParserTests = []struct {
|
||||
x string
|
||||
matched bool
|
||||
err error
|
||||
}{
|
||||
{"gc", true, nil},
|
||||
{"gccgo", false, nil},
|
||||
{"!gc", false, nil},
|
||||
{"gc && gccgo", false, nil},
|
||||
{"gc || gccgo", true, nil},
|
||||
{"gc || (gccgo && !gccgo)", true, nil},
|
||||
{"gc && (gccgo || !gccgo)", true, nil},
|
||||
{"!(gc && (gccgo || !gccgo))", false, nil},
|
||||
{"gccgo || gc", true, nil},
|
||||
{"!(!(!(gccgo || gc)))", false, nil},
|
||||
{"compiler_bootstrap", false, nil},
|
||||
{"cmd_go_bootstrap", true, nil},
|
||||
{"syntax(error", false, fmt.Errorf("parsing //go:build line: unexpected (")},
|
||||
{"(gc", false, fmt.Errorf("parsing //go:build line: missing )")},
|
||||
{"gc gc", false, fmt.Errorf("parsing //go:build line: unexpected tag")},
|
||||
{"(gc))", false, fmt.Errorf("parsing //go:build line: unexpected )")},
|
||||
}
|
||||
|
||||
func TestBuildParser(t *testing.T) {
|
||||
for _, tt := range buildParserTests {
|
||||
matched, err := matchexpr(tt.x)
|
||||
if matched != tt.matched || !reflect.DeepEqual(err, tt.err) {
|
||||
t.Errorf("matchexpr(%q) = %v, %v; want %v, %v", tt.x, matched, err, tt.matched, tt.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
394
src/cmd/dist/buildtool.go
vendored
Normal file
394
src/cmd/dist/buildtool.go
vendored
Normal file
@@ -0,0 +1,394 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Build toolchain using Go bootstrap version.
|
||||
//
|
||||
// The general strategy is to copy the source files we need into
|
||||
// a new GOPATH workspace, adjust import paths appropriately,
|
||||
// invoke the Go bootstrap toolchains go command to build those sources,
|
||||
// and then copy the binaries back.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// bootstrapDirs is a list of directories holding code that must be
|
||||
// compiled with the Go bootstrap toolchain to produce the bootstrapTargets.
|
||||
// All directories in this list are relative to and must be below $GOROOT/src.
|
||||
//
|
||||
// The list has two kinds of entries: names beginning with cmd/ with
|
||||
// no other slashes, which are commands, and other paths, which are packages
|
||||
// supporting the commands. Packages in the standard library can be listed
|
||||
// if a newer copy needs to be substituted for the Go bootstrap copy when used
|
||||
// by the command packages. Paths ending with /... automatically
|
||||
// include all packages within subdirectories as well.
|
||||
// These will be imported during bootstrap as bootstrap/name, like bootstrap/math/big.
|
||||
var bootstrapDirs = []string{
|
||||
"cmp",
|
||||
"cmd/asm",
|
||||
"cmd/asm/internal/...",
|
||||
"cmd/cgo",
|
||||
"cmd/compile",
|
||||
"cmd/compile/internal/...",
|
||||
"cmd/internal/archive",
|
||||
"cmd/internal/bio",
|
||||
"cmd/internal/codesign",
|
||||
"cmd/internal/dwarf",
|
||||
"cmd/internal/edit",
|
||||
"cmd/internal/gcprog",
|
||||
"cmd/internal/goobj",
|
||||
"cmd/internal/notsha256",
|
||||
"cmd/internal/obj/...",
|
||||
"cmd/internal/objabi",
|
||||
"cmd/internal/pgo",
|
||||
"cmd/internal/pkgpath",
|
||||
"cmd/internal/quoted",
|
||||
"cmd/internal/src",
|
||||
"cmd/internal/sys",
|
||||
"cmd/internal/telemetry",
|
||||
"cmd/internal/telemetry/counter",
|
||||
"cmd/link",
|
||||
"cmd/link/internal/...",
|
||||
"compress/flate",
|
||||
"compress/zlib",
|
||||
"container/heap",
|
||||
"debug/dwarf",
|
||||
"debug/elf",
|
||||
"debug/macho",
|
||||
"debug/pe",
|
||||
"go/build/constraint",
|
||||
"go/constant",
|
||||
"go/version",
|
||||
"internal/abi",
|
||||
"internal/coverage",
|
||||
"cmd/internal/cov/covcmd",
|
||||
"internal/bisect",
|
||||
"internal/buildcfg",
|
||||
"internal/goarch",
|
||||
"internal/godebugs",
|
||||
"internal/goexperiment",
|
||||
"internal/goroot",
|
||||
"internal/gover",
|
||||
"internal/goversion",
|
||||
// internal/lazyregexp is provided by Go 1.17, which permits it to
|
||||
// be imported by other packages in this list, but is not provided
|
||||
// by the Go 1.17 version of gccgo. It's on this list only to
|
||||
// support gccgo, and can be removed if we require gccgo 14 or later.
|
||||
"internal/lazyregexp",
|
||||
"internal/pkgbits",
|
||||
"internal/platform",
|
||||
"internal/profile",
|
||||
"internal/race",
|
||||
"internal/saferio",
|
||||
"internal/syscall/unix",
|
||||
"internal/types/errors",
|
||||
"internal/unsafeheader",
|
||||
"internal/xcoff",
|
||||
"internal/zstd",
|
||||
"math/bits",
|
||||
"sort",
|
||||
}
|
||||
|
||||
// File prefixes that are ignored by go/build anyway, and cause
|
||||
// problems with editor generated temporary files (#18931).
|
||||
var ignorePrefixes = []string{
|
||||
".",
|
||||
"_",
|
||||
"#",
|
||||
}
|
||||
|
||||
// File suffixes that use build tags introduced since Go 1.17.
|
||||
// These must not be copied into the bootstrap build directory.
|
||||
// Also ignore test files.
|
||||
var ignoreSuffixes = []string{
|
||||
"_test.s",
|
||||
"_test.go",
|
||||
// Skip PGO profile. No need to build toolchain1 compiler
|
||||
// with PGO. And as it is not a text file the import path
|
||||
// rewrite will break it.
|
||||
".pgo",
|
||||
// Skip editor backup files.
|
||||
"~",
|
||||
}
|
||||
|
||||
var tryDirs = []string{
|
||||
"sdk/go1.17",
|
||||
"go1.17",
|
||||
}
|
||||
|
||||
func bootstrapBuildTools() {
|
||||
goroot_bootstrap := os.Getenv("GOROOT_BOOTSTRAP")
|
||||
if goroot_bootstrap == "" {
|
||||
home := os.Getenv("HOME")
|
||||
goroot_bootstrap = pathf("%s/go1.4", home)
|
||||
for _, d := range tryDirs {
|
||||
if p := pathf("%s/%s", home, d); isdir(p) {
|
||||
goroot_bootstrap = p
|
||||
}
|
||||
}
|
||||
}
|
||||
xprintf("Building Go toolchain1 using %s.\n", goroot_bootstrap)
|
||||
|
||||
mkbuildcfg(pathf("%s/src/internal/buildcfg/zbootstrap.go", goroot))
|
||||
mkobjabi(pathf("%s/src/cmd/internal/objabi/zbootstrap.go", goroot))
|
||||
|
||||
// Use $GOROOT/pkg/bootstrap as the bootstrap workspace root.
|
||||
// We use a subdirectory of $GOROOT/pkg because that's the
|
||||
// space within $GOROOT where we store all generated objects.
|
||||
// We could use a temporary directory outside $GOROOT instead,
|
||||
// but it is easier to debug on failure if the files are in a known location.
|
||||
workspace := pathf("%s/pkg/bootstrap", goroot)
|
||||
xremoveall(workspace)
|
||||
xatexit(func() { xremoveall(workspace) })
|
||||
base := pathf("%s/src/bootstrap", workspace)
|
||||
xmkdirall(base)
|
||||
|
||||
// Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths.
|
||||
writefile("module bootstrap\ngo 1.20\n", pathf("%s/%s", base, "go.mod"), 0)
|
||||
for _, dir := range bootstrapDirs {
|
||||
recurse := strings.HasSuffix(dir, "/...")
|
||||
dir = strings.TrimSuffix(dir, "/...")
|
||||
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
fatalf("walking bootstrap dirs failed: %v: %v", path, err)
|
||||
}
|
||||
|
||||
name := filepath.Base(path)
|
||||
src := pathf("%s/src/%s", goroot, path)
|
||||
dst := pathf("%s/%s", base, path)
|
||||
|
||||
if info.IsDir() {
|
||||
if !recurse && path != dir || name == "testdata" {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
xmkdirall(dst)
|
||||
if path == "cmd/cgo" {
|
||||
// Write to src because we need the file both for bootstrap
|
||||
// and for later in the main build.
|
||||
mkzdefaultcc("", pathf("%s/zdefaultcc.go", src))
|
||||
mkzdefaultcc("", pathf("%s/zdefaultcc.go", dst))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, pre := range ignorePrefixes {
|
||||
if strings.HasPrefix(name, pre) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
for _, suf := range ignoreSuffixes {
|
||||
if strings.HasSuffix(name, suf) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
text := bootstrapRewriteFile(src)
|
||||
writefile(text, dst, 0)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Set up environment for invoking Go bootstrap toolchains go command.
|
||||
// GOROOT points at Go bootstrap GOROOT,
|
||||
// GOPATH points at our bootstrap workspace,
|
||||
// GOBIN is empty, so that binaries are installed to GOPATH/bin,
|
||||
// and GOOS, GOHOSTOS, GOARCH, and GOHOSTOS are empty,
|
||||
// so that Go bootstrap toolchain builds whatever kind of binary it knows how to build.
|
||||
// Restore GOROOT, GOPATH, and GOBIN when done.
|
||||
// Don't bother with GOOS, GOHOSTOS, GOARCH, and GOHOSTARCH,
|
||||
// because setup will take care of those when bootstrapBuildTools returns.
|
||||
|
||||
defer os.Setenv("GOROOT", os.Getenv("GOROOT"))
|
||||
os.Setenv("GOROOT", goroot_bootstrap)
|
||||
|
||||
defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
|
||||
os.Setenv("GOPATH", workspace)
|
||||
|
||||
defer os.Setenv("GOBIN", os.Getenv("GOBIN"))
|
||||
os.Setenv("GOBIN", "")
|
||||
|
||||
os.Setenv("GOOS", "")
|
||||
os.Setenv("GOHOSTOS", "")
|
||||
os.Setenv("GOARCH", "")
|
||||
os.Setenv("GOHOSTARCH", "")
|
||||
|
||||
// Run Go bootstrap to build binaries.
|
||||
// Use the math_big_pure_go build tag to disable the assembly in math/big
|
||||
// which may contain unsupported instructions.
|
||||
// Use the purego build tag to disable other assembly code,
|
||||
// such as in cmd/internal/notsha256.
|
||||
cmd := []string{
|
||||
pathf("%s/bin/go", goroot_bootstrap),
|
||||
"install",
|
||||
"-tags=math_big_pure_go compiler_bootstrap purego",
|
||||
}
|
||||
if vflag > 0 {
|
||||
cmd = append(cmd, "-v")
|
||||
}
|
||||
if tool := os.Getenv("GOBOOTSTRAP_TOOLEXEC"); tool != "" {
|
||||
cmd = append(cmd, "-toolexec="+tool)
|
||||
}
|
||||
cmd = append(cmd, "bootstrap/cmd/...")
|
||||
run(base, ShowOutput|CheckExit, cmd...)
|
||||
|
||||
// Copy binaries into tool binary directory.
|
||||
for _, name := range bootstrapDirs {
|
||||
if !strings.HasPrefix(name, "cmd/") {
|
||||
continue
|
||||
}
|
||||
name = name[len("cmd/"):]
|
||||
if !strings.Contains(name, "/") {
|
||||
copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec)
|
||||
}
|
||||
}
|
||||
|
||||
if vflag > 0 {
|
||||
xprintf("\n")
|
||||
}
|
||||
}
|
||||
|
||||
var ssaRewriteFileSubstring = filepath.FromSlash("src/cmd/compile/internal/ssa/rewrite")
|
||||
|
||||
// isUnneededSSARewriteFile reports whether srcFile is a
|
||||
// src/cmd/compile/internal/ssa/rewriteARCHNAME.go file for an
|
||||
// architecture that isn't for the given GOARCH.
|
||||
//
|
||||
// When unneeded is true archCaps is the rewrite base filename without
|
||||
// the "rewrite" prefix or ".go" suffix: AMD64, 386, ARM, ARM64, etc.
|
||||
func isUnneededSSARewriteFile(srcFile, goArch string) (archCaps string, unneeded bool) {
|
||||
if !strings.Contains(srcFile, ssaRewriteFileSubstring) {
|
||||
return "", false
|
||||
}
|
||||
fileArch := strings.TrimSuffix(strings.TrimPrefix(filepath.Base(srcFile), "rewrite"), ".go")
|
||||
if fileArch == "" {
|
||||
return "", false
|
||||
}
|
||||
b := fileArch[0]
|
||||
if b == '_' || ('a' <= b && b <= 'z') {
|
||||
return "", false
|
||||
}
|
||||
archCaps = fileArch
|
||||
fileArch = strings.ToLower(fileArch)
|
||||
fileArch = strings.TrimSuffix(fileArch, "splitload")
|
||||
fileArch = strings.TrimSuffix(fileArch, "latelower")
|
||||
if fileArch == goArch {
|
||||
return "", false
|
||||
}
|
||||
if fileArch == strings.TrimSuffix(goArch, "le") {
|
||||
return "", false
|
||||
}
|
||||
return archCaps, true
|
||||
}
|
||||
|
||||
func bootstrapRewriteFile(srcFile string) string {
|
||||
// During bootstrap, generate dummy rewrite files for
|
||||
// irrelevant architectures. We only need to build a bootstrap
|
||||
// binary that works for the current gohostarch.
|
||||
// This saves 6+ seconds of bootstrap.
|
||||
if archCaps, ok := isUnneededSSARewriteFile(srcFile, gohostarch); ok {
|
||||
return fmt.Sprintf(`%spackage ssa
|
||||
|
||||
func rewriteValue%s(v *Value) bool { panic("unused during bootstrap") }
|
||||
func rewriteBlock%s(b *Block) bool { panic("unused during bootstrap") }
|
||||
`, generatedHeader, archCaps, archCaps)
|
||||
}
|
||||
|
||||
return bootstrapFixImports(srcFile)
|
||||
}
|
||||
|
||||
var (
|
||||
importRE = regexp.MustCompile(`\Aimport\s+(\.|[A-Za-z0-9_]+)?\s*"([^"]+)"\s*(//.*)?\n\z`)
|
||||
importBlockRE = regexp.MustCompile(`\A\s*(?:(\.|[A-Za-z0-9_]+)?\s*"([^"]+)")?\s*(//.*)?\n\z`)
|
||||
)
|
||||
|
||||
func bootstrapFixImports(srcFile string) string {
|
||||
text := readfile(srcFile)
|
||||
if !strings.Contains(srcFile, "/cmd/") && !strings.Contains(srcFile, `\cmd\`) {
|
||||
text = regexp.MustCompile(`\bany\b`).ReplaceAllString(text, "interface{}")
|
||||
}
|
||||
lines := strings.SplitAfter(text, "\n")
|
||||
inBlock := false
|
||||
inComment := false
|
||||
for i, line := range lines {
|
||||
if strings.HasSuffix(line, "*/\n") {
|
||||
inComment = false
|
||||
}
|
||||
if strings.HasSuffix(line, "/*\n") {
|
||||
inComment = true
|
||||
}
|
||||
if inComment {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "import (") {
|
||||
inBlock = true
|
||||
continue
|
||||
}
|
||||
if inBlock && strings.HasPrefix(line, ")") {
|
||||
inBlock = false
|
||||
continue
|
||||
}
|
||||
|
||||
var m []string
|
||||
if !inBlock {
|
||||
if !strings.HasPrefix(line, "import ") {
|
||||
continue
|
||||
}
|
||||
m = importRE.FindStringSubmatch(line)
|
||||
if m == nil {
|
||||
fatalf("%s:%d: invalid import declaration: %q", srcFile, i+1, line)
|
||||
}
|
||||
} else {
|
||||
m = importBlockRE.FindStringSubmatch(line)
|
||||
if m == nil {
|
||||
fatalf("%s:%d: invalid import block line", srcFile, i+1)
|
||||
}
|
||||
if m[2] == "" {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
path := m[2]
|
||||
if strings.HasPrefix(path, "cmd/") {
|
||||
path = "bootstrap/" + path
|
||||
} else {
|
||||
for _, dir := range bootstrapDirs {
|
||||
if path == dir {
|
||||
path = "bootstrap/" + dir
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrite use of internal/reflectlite to be plain reflect.
|
||||
if path == "internal/reflectlite" {
|
||||
lines[i] = strings.ReplaceAll(line, `"reflect"`, `reflectlite "reflect"`)
|
||||
continue
|
||||
}
|
||||
|
||||
// Otherwise, reject direct imports of internal packages,
|
||||
// since that implies knowledge of internal details that might
|
||||
// change from one bootstrap toolchain to the next.
|
||||
// There are many internal packages that are listed in
|
||||
// bootstrapDirs and made into bootstrap copies based on the
|
||||
// current repo's source code. Those are fine; this is catching
|
||||
// references to internal packages in the older bootstrap toolchain.
|
||||
if strings.HasPrefix(path, "internal/") {
|
||||
fatalf("%s:%d: bootstrap-copied source file cannot import %s", srcFile, i+1, path)
|
||||
}
|
||||
if path != m[2] {
|
||||
lines[i] = strings.ReplaceAll(line, `"`+m[2]+`"`, `"`+path+`"`)
|
||||
}
|
||||
}
|
||||
|
||||
lines[0] = generatedHeader + "// This is a bootstrap copy of " + srcFile + "\n\n//line " + srcFile + ":1\n" + lines[0]
|
||||
|
||||
return strings.Join(lines, "")
|
||||
}
|
||||
21
src/cmd/dist/doc.go
vendored
Normal file
21
src/cmd/dist/doc.go
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Dist helps bootstrap, build, and test the Go distribution.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// go tool dist [command]
|
||||
//
|
||||
// The commands are:
|
||||
//
|
||||
// banner print installation banner
|
||||
// bootstrap rebuild everything
|
||||
// clean deletes all built files
|
||||
// env [-p] print environment (-p: include $PATH)
|
||||
// install [dir] install individual directory
|
||||
// list [-json] list all supported platforms
|
||||
// test [-h] run Go test(s)
|
||||
// version print Go version
|
||||
package main
|
||||
40
src/cmd/dist/exec.go
vendored
Normal file
40
src/cmd/dist/exec.go
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// setDir sets cmd.Dir to dir, and also adds PWD=dir to cmd's environment.
|
||||
func setDir(cmd *exec.Cmd, dir string) {
|
||||
cmd.Dir = dir
|
||||
if cmd.Env != nil {
|
||||
// os/exec won't set PWD automatically.
|
||||
setEnv(cmd, "PWD", dir)
|
||||
}
|
||||
}
|
||||
|
||||
// setEnv sets cmd.Env so that key = value.
|
||||
func setEnv(cmd *exec.Cmd, key, value string) {
|
||||
cmd.Env = append(cmd.Environ(), key+"="+value)
|
||||
}
|
||||
|
||||
// unsetEnv sets cmd.Env so that key is not present in the environment.
|
||||
func unsetEnv(cmd *exec.Cmd, key string) {
|
||||
cmd.Env = cmd.Environ()
|
||||
|
||||
prefix := key + "="
|
||||
newEnv := []string{}
|
||||
for _, entry := range cmd.Env {
|
||||
if strings.HasPrefix(entry, prefix) {
|
||||
continue
|
||||
}
|
||||
newEnv = append(newEnv, entry)
|
||||
// key may appear multiple times, so keep going.
|
||||
}
|
||||
cmd.Env = newEnv
|
||||
}
|
||||
276
src/cmd/dist/imports.go
vendored
Normal file
276
src/cmd/dist/imports.go
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file is forked from go/build/read.go.
|
||||
// (cmd/dist must not import go/build because we do not want it to be
|
||||
// sensitive to the specific version of go/build present in $GOROOT_BOOTSTRAP.)
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type importReader struct {
|
||||
b *bufio.Reader
|
||||
buf []byte
|
||||
peek byte
|
||||
err error
|
||||
eof bool
|
||||
nerr int
|
||||
}
|
||||
|
||||
func isIdent(c byte) bool {
|
||||
return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= utf8.RuneSelf
|
||||
}
|
||||
|
||||
var (
|
||||
errSyntax = errors.New("syntax error")
|
||||
errNUL = errors.New("unexpected NUL in input")
|
||||
)
|
||||
|
||||
// syntaxError records a syntax error, but only if an I/O error has not already been recorded.
|
||||
func (r *importReader) syntaxError() {
|
||||
if r.err == nil {
|
||||
r.err = errSyntax
|
||||
}
|
||||
}
|
||||
|
||||
// readByte reads the next byte from the input, saves it in buf, and returns it.
|
||||
// If an error occurs, readByte records the error in r.err and returns 0.
|
||||
func (r *importReader) readByte() byte {
|
||||
c, err := r.b.ReadByte()
|
||||
if err == nil {
|
||||
r.buf = append(r.buf, c)
|
||||
if c == 0 {
|
||||
err = errNUL
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
r.eof = true
|
||||
} else if r.err == nil {
|
||||
r.err = err
|
||||
}
|
||||
c = 0
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// peekByte returns the next byte from the input reader but does not advance beyond it.
|
||||
// If skipSpace is set, peekByte skips leading spaces and comments.
|
||||
func (r *importReader) peekByte(skipSpace bool) byte {
|
||||
if r.err != nil {
|
||||
if r.nerr++; r.nerr > 10000 {
|
||||
panic("go/build: import reader looping")
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Use r.peek as first input byte.
|
||||
// Don't just return r.peek here: it might have been left by peekByte(false)
|
||||
// and this might be peekByte(true).
|
||||
c := r.peek
|
||||
if c == 0 {
|
||||
c = r.readByte()
|
||||
}
|
||||
for r.err == nil && !r.eof {
|
||||
if skipSpace {
|
||||
// For the purposes of this reader, semicolons are never necessary to
|
||||
// understand the input and are treated as spaces.
|
||||
switch c {
|
||||
case ' ', '\f', '\t', '\r', '\n', ';':
|
||||
c = r.readByte()
|
||||
continue
|
||||
|
||||
case '/':
|
||||
c = r.readByte()
|
||||
if c == '/' {
|
||||
for c != '\n' && r.err == nil && !r.eof {
|
||||
c = r.readByte()
|
||||
}
|
||||
} else if c == '*' {
|
||||
var c1 byte
|
||||
for (c != '*' || c1 != '/') && r.err == nil {
|
||||
if r.eof {
|
||||
r.syntaxError()
|
||||
}
|
||||
c, c1 = c1, r.readByte()
|
||||
}
|
||||
} else {
|
||||
r.syntaxError()
|
||||
}
|
||||
c = r.readByte()
|
||||
continue
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
r.peek = c
|
||||
return r.peek
|
||||
}
|
||||
|
||||
// nextByte is like peekByte but advances beyond the returned byte.
|
||||
func (r *importReader) nextByte(skipSpace bool) byte {
|
||||
c := r.peekByte(skipSpace)
|
||||
r.peek = 0
|
||||
return c
|
||||
}
|
||||
|
||||
// readKeyword reads the given keyword from the input.
|
||||
// If the keyword is not present, readKeyword records a syntax error.
|
||||
func (r *importReader) readKeyword(kw string) {
|
||||
r.peekByte(true)
|
||||
for i := 0; i < len(kw); i++ {
|
||||
if r.nextByte(false) != kw[i] {
|
||||
r.syntaxError()
|
||||
return
|
||||
}
|
||||
}
|
||||
if isIdent(r.peekByte(false)) {
|
||||
r.syntaxError()
|
||||
}
|
||||
}
|
||||
|
||||
// readIdent reads an identifier from the input.
|
||||
// If an identifier is not present, readIdent records a syntax error.
|
||||
func (r *importReader) readIdent() {
|
||||
c := r.peekByte(true)
|
||||
if !isIdent(c) {
|
||||
r.syntaxError()
|
||||
return
|
||||
}
|
||||
for isIdent(r.peekByte(false)) {
|
||||
r.peek = 0
|
||||
}
|
||||
}
|
||||
|
||||
// readString reads a quoted string literal from the input.
|
||||
// If an identifier is not present, readString records a syntax error.
|
||||
func (r *importReader) readString(save *[]string) {
|
||||
switch r.nextByte(true) {
|
||||
case '`':
|
||||
start := len(r.buf) - 1
|
||||
for r.err == nil {
|
||||
if r.nextByte(false) == '`' {
|
||||
if save != nil {
|
||||
*save = append(*save, string(r.buf[start:]))
|
||||
}
|
||||
break
|
||||
}
|
||||
if r.eof {
|
||||
r.syntaxError()
|
||||
}
|
||||
}
|
||||
case '"':
|
||||
start := len(r.buf) - 1
|
||||
for r.err == nil {
|
||||
c := r.nextByte(false)
|
||||
if c == '"' {
|
||||
if save != nil {
|
||||
*save = append(*save, string(r.buf[start:]))
|
||||
}
|
||||
break
|
||||
}
|
||||
if r.eof || c == '\n' {
|
||||
r.syntaxError()
|
||||
}
|
||||
if c == '\\' {
|
||||
r.nextByte(false)
|
||||
}
|
||||
}
|
||||
default:
|
||||
r.syntaxError()
|
||||
}
|
||||
}
|
||||
|
||||
// readImport reads an import clause - optional identifier followed by quoted string -
|
||||
// from the input.
|
||||
func (r *importReader) readImport(imports *[]string) {
|
||||
c := r.peekByte(true)
|
||||
if c == '.' {
|
||||
r.peek = 0
|
||||
} else if isIdent(c) {
|
||||
r.readIdent()
|
||||
}
|
||||
r.readString(imports)
|
||||
}
|
||||
|
||||
// readComments is like ioutil.ReadAll, except that it only reads the leading
|
||||
// block of comments in the file.
|
||||
func readComments(f io.Reader) ([]byte, error) {
|
||||
r := &importReader{b: bufio.NewReader(f)}
|
||||
r.peekByte(true)
|
||||
if r.err == nil && !r.eof {
|
||||
// Didn't reach EOF, so must have found a non-space byte. Remove it.
|
||||
r.buf = r.buf[:len(r.buf)-1]
|
||||
}
|
||||
return r.buf, r.err
|
||||
}
|
||||
|
||||
// readimports returns the imports found in the named file.
|
||||
func readimports(file string) []string {
|
||||
var imports []string
|
||||
r := &importReader{b: bufio.NewReader(strings.NewReader(readfile(file)))}
|
||||
r.readKeyword("package")
|
||||
r.readIdent()
|
||||
for r.peekByte(true) == 'i' {
|
||||
r.readKeyword("import")
|
||||
if r.peekByte(true) == '(' {
|
||||
r.nextByte(false)
|
||||
for r.peekByte(true) != ')' && r.err == nil {
|
||||
r.readImport(&imports)
|
||||
}
|
||||
r.nextByte(false)
|
||||
} else {
|
||||
r.readImport(&imports)
|
||||
}
|
||||
}
|
||||
|
||||
for i := range imports {
|
||||
unquoted, err := strconv.Unquote(imports[i])
|
||||
if err != nil {
|
||||
fatalf("reading imports from %s: %v", file, err)
|
||||
}
|
||||
imports[i] = unquoted
|
||||
}
|
||||
|
||||
return imports
|
||||
}
|
||||
|
||||
// resolveVendor returns a unique package path imported with the given import
|
||||
// path from srcDir.
|
||||
//
|
||||
// resolveVendor assumes that a package is vendored if and only if its first
|
||||
// path component contains a dot. If a package is vendored, its import path
|
||||
// is returned with a "vendor" or "cmd/vendor" prefix, depending on srcDir.
|
||||
// Otherwise, the import path is returned verbatim.
|
||||
func resolveVendor(imp, srcDir string) string {
|
||||
var first string
|
||||
if i := strings.Index(imp, "/"); i < 0 {
|
||||
first = imp
|
||||
} else {
|
||||
first = imp[:i]
|
||||
}
|
||||
isStandard := !strings.Contains(first, ".")
|
||||
if isStandard {
|
||||
return imp
|
||||
}
|
||||
|
||||
if strings.HasPrefix(srcDir, filepath.Join(goroot, "src", "cmd")) {
|
||||
return path.Join("cmd", "vendor", imp)
|
||||
} else if strings.HasPrefix(srcDir, filepath.Join(goroot, "src")) {
|
||||
return path.Join("vendor", imp)
|
||||
} else {
|
||||
panic(fmt.Sprintf("srcDir %q not in GOOROT/src", srcDir))
|
||||
}
|
||||
}
|
||||
194
src/cmd/dist/main.go
vendored
Normal file
194
src/cmd/dist/main.go
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func usage() {
|
||||
xprintf(`usage: go tool dist [command]
|
||||
Commands are:
|
||||
|
||||
banner print installation banner
|
||||
bootstrap rebuild everything
|
||||
clean deletes all built files
|
||||
env [-p] print environment (-p: include $PATH)
|
||||
install [dir] install individual directory
|
||||
list [-json] [-broken] list all supported platforms
|
||||
test [-h] run Go test(s)
|
||||
version print Go version
|
||||
|
||||
All commands take -v flags to emit extra information.
|
||||
`)
|
||||
xexit(2)
|
||||
}
|
||||
|
||||
// commands records the available commands.
|
||||
var commands = map[string]func(){
|
||||
"banner": cmdbanner,
|
||||
"bootstrap": cmdbootstrap,
|
||||
"clean": cmdclean,
|
||||
"env": cmdenv,
|
||||
"install": cmdinstall,
|
||||
"list": cmdlist,
|
||||
"test": cmdtest,
|
||||
"version": cmdversion,
|
||||
}
|
||||
|
||||
// main takes care of OS-specific startup and dispatches to xmain.
|
||||
func main() {
|
||||
os.Setenv("TERM", "dumb") // disable escape codes in clang errors
|
||||
|
||||
// provide -check-armv6k first, before checking for $GOROOT so that
|
||||
// it is possible to run this check without having $GOROOT available.
|
||||
if len(os.Args) > 1 && os.Args[1] == "-check-armv6k" {
|
||||
useARMv6K() // might fail with SIGILL
|
||||
println("ARMv6K supported.")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
gohostos = runtime.GOOS
|
||||
switch gohostos {
|
||||
case "aix":
|
||||
// uname -m doesn't work under AIX
|
||||
gohostarch = "ppc64"
|
||||
case "plan9":
|
||||
gohostarch = os.Getenv("objtype")
|
||||
if gohostarch == "" {
|
||||
fatalf("$objtype is unset")
|
||||
}
|
||||
case "solaris", "illumos":
|
||||
// Solaris and illumos systems have multi-arch userlands, and
|
||||
// "uname -m" reports the machine hardware name; e.g.,
|
||||
// "i86pc" on both 32- and 64-bit x86 systems. Check for the
|
||||
// native (widest) instruction set on the running kernel:
|
||||
out := run("", CheckExit, "isainfo", "-n")
|
||||
if strings.Contains(out, "amd64") {
|
||||
gohostarch = "amd64"
|
||||
}
|
||||
if strings.Contains(out, "i386") {
|
||||
gohostarch = "386"
|
||||
}
|
||||
case "windows":
|
||||
exe = ".exe"
|
||||
}
|
||||
|
||||
sysinit()
|
||||
|
||||
if gohostarch == "" {
|
||||
// Default Unix system.
|
||||
out := run("", CheckExit, "uname", "-m")
|
||||
outAll := run("", CheckExit, "uname", "-a")
|
||||
switch {
|
||||
case strings.Contains(outAll, "RELEASE_ARM64"):
|
||||
// MacOS prints
|
||||
// Darwin p1.local 21.1.0 Darwin Kernel Version 21.1.0: Wed Oct 13 17:33:01 PDT 2021; root:xnu-8019.41.5~1/RELEASE_ARM64_T6000 x86_64
|
||||
// on ARM64 laptops when there is an x86 parent in the
|
||||
// process tree. Look for the RELEASE_ARM64 to avoid being
|
||||
// confused into building an x86 toolchain.
|
||||
gohostarch = "arm64"
|
||||
case strings.Contains(out, "x86_64"), strings.Contains(out, "amd64"):
|
||||
gohostarch = "amd64"
|
||||
case strings.Contains(out, "86"):
|
||||
gohostarch = "386"
|
||||
if gohostos == "darwin" {
|
||||
// Even on 64-bit platform, some versions of macOS uname -m prints i386.
|
||||
// We don't support any of the OS X versions that run on 32-bit-only hardware anymore.
|
||||
gohostarch = "amd64"
|
||||
}
|
||||
case strings.Contains(out, "aarch64"), strings.Contains(out, "arm64"):
|
||||
gohostarch = "arm64"
|
||||
case strings.Contains(out, "arm"):
|
||||
gohostarch = "arm"
|
||||
if gohostos == "netbsd" && strings.Contains(run("", CheckExit, "uname", "-p"), "aarch64") {
|
||||
gohostarch = "arm64"
|
||||
}
|
||||
case strings.Contains(out, "ppc64le"):
|
||||
gohostarch = "ppc64le"
|
||||
case strings.Contains(out, "ppc64"):
|
||||
gohostarch = "ppc64"
|
||||
case strings.Contains(out, "mips64"):
|
||||
gohostarch = "mips64"
|
||||
if elfIsLittleEndian(os.Args[0]) {
|
||||
gohostarch = "mips64le"
|
||||
}
|
||||
case strings.Contains(out, "mips"):
|
||||
gohostarch = "mips"
|
||||
if elfIsLittleEndian(os.Args[0]) {
|
||||
gohostarch = "mipsle"
|
||||
}
|
||||
case strings.Contains(out, "loongarch64"):
|
||||
gohostarch = "loong64"
|
||||
case strings.Contains(out, "riscv64"):
|
||||
gohostarch = "riscv64"
|
||||
case strings.Contains(out, "s390x"):
|
||||
gohostarch = "s390x"
|
||||
case gohostos == "darwin", gohostos == "ios":
|
||||
if strings.Contains(run("", CheckExit, "uname", "-v"), "RELEASE_ARM64_") {
|
||||
gohostarch = "arm64"
|
||||
}
|
||||
case gohostos == "freebsd":
|
||||
if strings.Contains(run("", CheckExit, "uname", "-p"), "riscv64") {
|
||||
gohostarch = "riscv64"
|
||||
}
|
||||
case gohostos == "openbsd" && strings.Contains(out, "powerpc64"):
|
||||
gohostarch = "ppc64"
|
||||
case gohostos == "openbsd":
|
||||
if strings.Contains(run("", CheckExit, "uname", "-p"), "mips64") {
|
||||
gohostarch = "mips64"
|
||||
}
|
||||
default:
|
||||
fatalf("unknown architecture: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
if gohostarch == "arm" || gohostarch == "mips64" || gohostarch == "mips64le" {
|
||||
maxbg = min(maxbg, runtime.NumCPU())
|
||||
}
|
||||
// For deterministic make.bash debugging and for smallest-possible footprint,
|
||||
// pay attention to GOMAXPROCS=1. This was a bad idea for 1.4 bootstrap, but
|
||||
// the bootstrap version is now 1.17+ and thus this is fine.
|
||||
if runtime.GOMAXPROCS(0) == 1 {
|
||||
maxbg = 1
|
||||
}
|
||||
bginit()
|
||||
|
||||
if len(os.Args) > 1 && os.Args[1] == "-check-goarm" {
|
||||
useVFPv1() // might fail with SIGILL
|
||||
println("VFPv1 OK.")
|
||||
useVFPv3() // might fail with SIGILL
|
||||
println("VFPv3 OK.")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
xinit()
|
||||
xmain()
|
||||
xexit(0)
|
||||
}
|
||||
|
||||
// The OS-specific main calls into the portable code here.
|
||||
func xmain() {
|
||||
if len(os.Args) < 2 {
|
||||
usage()
|
||||
}
|
||||
cmd := os.Args[1]
|
||||
os.Args = os.Args[1:] // for flag parsing during cmd
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "usage: go tool dist %s [options]\n", cmd)
|
||||
flag.PrintDefaults()
|
||||
os.Exit(2)
|
||||
}
|
||||
if f, ok := commands[cmd]; ok {
|
||||
f()
|
||||
} else {
|
||||
xprintf("unknown command %s\n", cmd)
|
||||
usage()
|
||||
}
|
||||
}
|
||||
21
src/cmd/dist/notgo120.go
vendored
Normal file
21
src/cmd/dist/notgo120.go
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Go 1.22 and later requires Go 1.20 as the bootstrap toolchain.
|
||||
// If cmd/dist is built using an earlier Go version, this file will be
|
||||
// included in the build and cause an error like:
|
||||
//
|
||||
// % GOROOT_BOOTSTRAP=$HOME/sdk/go1.16 ./make.bash
|
||||
// Building Go cmd/dist using /Users/rsc/sdk/go1.16. (go1.16 darwin/amd64)
|
||||
// found packages main (build.go) and building_Go_requires_Go_1_20_6_or_later (notgo120.go) in /Users/rsc/go/src/cmd/dist
|
||||
// %
|
||||
//
|
||||
// which is the best we can do under the circumstances.
|
||||
//
|
||||
// See go.dev/issue/44505 for more background on
|
||||
// why Go moved on from Go 1.4 for bootstrap.
|
||||
|
||||
//go:build !go1.20
|
||||
|
||||
package building_Go_requires_Go_1_20_6_or_later
|
||||
53
src/cmd/dist/quoted.go
vendored
Normal file
53
src/cmd/dist/quoted.go
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// quotedSplit is a verbatim copy from cmd/internal/quoted.go:Split and its
|
||||
// dependencies (isSpaceByte). Since this package is built using the host's
|
||||
// Go compiler, it cannot use `cmd/internal/...`. We also don't want to export
|
||||
// it to all Go users.
|
||||
//
|
||||
// Please keep those in sync.
|
||||
func quotedSplit(s string) ([]string, error) {
|
||||
// Split fields allowing '' or "" around elements.
|
||||
// Quotes further inside the string do not count.
|
||||
var f []string
|
||||
for len(s) > 0 {
|
||||
for len(s) > 0 && isSpaceByte(s[0]) {
|
||||
s = s[1:]
|
||||
}
|
||||
if len(s) == 0 {
|
||||
break
|
||||
}
|
||||
// Accepted quoted string. No unescaping inside.
|
||||
if s[0] == '"' || s[0] == '\'' {
|
||||
quote := s[0]
|
||||
s = s[1:]
|
||||
i := 0
|
||||
for i < len(s) && s[i] != quote {
|
||||
i++
|
||||
}
|
||||
if i >= len(s) {
|
||||
return nil, fmt.Errorf("unterminated %c string", quote)
|
||||
}
|
||||
f = append(f, s[:i])
|
||||
s = s[i+1:]
|
||||
continue
|
||||
}
|
||||
i := 0
|
||||
for i < len(s) && !isSpaceByte(s[i]) {
|
||||
i++
|
||||
}
|
||||
f = append(f, s[:i])
|
||||
s = s[i:]
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func isSpaceByte(c byte) bool {
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
|
||||
}
|
||||
48
src/cmd/dist/supported_test.go
vendored
Normal file
48
src/cmd/dist/supported_test.go
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"internal/platform"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestSupported tests that dist and the main tools agree on
|
||||
// which build modes are supported for a given target. We do things
|
||||
// this way because the dist tool needs to be buildable directly by
|
||||
// the bootstrap compiler, and as such can't import internal packages.
|
||||
func TestSupported(t *testing.T) {
|
||||
defer func(a, o string) {
|
||||
goarch = a
|
||||
goos = o
|
||||
}(goarch, goos)
|
||||
|
||||
var modes = []string{
|
||||
// we assume that "exe" and "archive" always work
|
||||
"pie",
|
||||
"c-archive",
|
||||
"c-shared",
|
||||
"shared",
|
||||
"plugin",
|
||||
}
|
||||
|
||||
for _, a := range okgoarch {
|
||||
goarch = a
|
||||
for _, o := range okgoos {
|
||||
if _, ok := cgoEnabled[o+"/"+a]; !ok {
|
||||
continue
|
||||
}
|
||||
goos = o
|
||||
for _, mode := range modes {
|
||||
var dt tester
|
||||
dist := dt.supportedBuildmode(mode)
|
||||
std := platform.BuildModeSupported("gc", mode, o, a)
|
||||
if dist != std {
|
||||
t.Errorf("discrepancy for %s-%s %s: dist says %t, standard library says %t", o, a, mode, dist, std)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/cmd/dist/sys_default.go
vendored
Normal file
10
src/cmd/dist/sys_default.go
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !windows
|
||||
|
||||
package main
|
||||
|
||||
func sysinit() {
|
||||
}
|
||||
57
src/cmd/dist/sys_windows.go
vendored
Normal file
57
src/cmd/dist/sys_windows.go
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
procGetSystemInfo = modkernel32.NewProc("GetSystemInfo")
|
||||
)
|
||||
|
||||
// see https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info
|
||||
type systeminfo struct {
|
||||
wProcessorArchitecture uint16
|
||||
wReserved uint16
|
||||
dwPageSize uint32
|
||||
lpMinimumApplicationAddress uintptr
|
||||
lpMaximumApplicationAddress uintptr
|
||||
dwActiveProcessorMask uintptr
|
||||
dwNumberOfProcessors uint32
|
||||
dwProcessorType uint32
|
||||
dwAllocationGranularity uint32
|
||||
wProcessorLevel uint16
|
||||
wProcessorRevision uint16
|
||||
}
|
||||
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info
|
||||
const (
|
||||
PROCESSOR_ARCHITECTURE_AMD64 = 9
|
||||
PROCESSOR_ARCHITECTURE_INTEL = 0
|
||||
PROCESSOR_ARCHITECTURE_ARM = 5
|
||||
PROCESSOR_ARCHITECTURE_ARM64 = 12
|
||||
PROCESSOR_ARCHITECTURE_IA64 = 6
|
||||
)
|
||||
|
||||
var sysinfo systeminfo
|
||||
|
||||
func sysinit() {
|
||||
syscall.Syscall(procGetSystemInfo.Addr(), 1, uintptr(unsafe.Pointer(&sysinfo)), 0, 0)
|
||||
switch sysinfo.wProcessorArchitecture {
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
gohostarch = "amd64"
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
gohostarch = "386"
|
||||
case PROCESSOR_ARCHITECTURE_ARM:
|
||||
gohostarch = "arm"
|
||||
case PROCESSOR_ARCHITECTURE_ARM64:
|
||||
gohostarch = "arm64"
|
||||
default:
|
||||
fatalf("unknown processor architecture")
|
||||
}
|
||||
}
|
||||
1693
src/cmd/dist/test.go
vendored
Normal file
1693
src/cmd/dist/test.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
204
src/cmd/dist/testjson.go
vendored
Normal file
204
src/cmd/dist/testjson.go
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// lockedWriter serializes Write calls to an underlying Writer.
|
||||
type lockedWriter struct {
|
||||
lock sync.Mutex
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func (w *lockedWriter) Write(b []byte) (int, error) {
|
||||
w.lock.Lock()
|
||||
defer w.lock.Unlock()
|
||||
return w.w.Write(b)
|
||||
}
|
||||
|
||||
// testJSONFilter is an io.Writer filter that replaces the Package field in
|
||||
// test2json output.
|
||||
type testJSONFilter struct {
|
||||
w io.Writer // Underlying writer
|
||||
variant string // Add ":variant" to Package field
|
||||
|
||||
lineBuf bytes.Buffer // Buffer for incomplete lines
|
||||
}
|
||||
|
||||
func (f *testJSONFilter) Write(b []byte) (int, error) {
|
||||
bn := len(b)
|
||||
|
||||
// Process complete lines, and buffer any incomplete lines.
|
||||
for len(b) > 0 {
|
||||
nl := bytes.IndexByte(b, '\n')
|
||||
if nl < 0 {
|
||||
f.lineBuf.Write(b)
|
||||
break
|
||||
}
|
||||
var line []byte
|
||||
if f.lineBuf.Len() > 0 {
|
||||
// We have buffered data. Add the rest of the line from b and
|
||||
// process the complete line.
|
||||
f.lineBuf.Write(b[:nl+1])
|
||||
line = f.lineBuf.Bytes()
|
||||
} else {
|
||||
// Process a complete line from b.
|
||||
line = b[:nl+1]
|
||||
}
|
||||
b = b[nl+1:]
|
||||
f.process(line)
|
||||
f.lineBuf.Reset()
|
||||
}
|
||||
|
||||
return bn, nil
|
||||
}
|
||||
|
||||
func (f *testJSONFilter) Flush() {
|
||||
// Write any remaining partial line to the underlying writer.
|
||||
if f.lineBuf.Len() > 0 {
|
||||
f.w.Write(f.lineBuf.Bytes())
|
||||
f.lineBuf.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func (f *testJSONFilter) process(line []byte) {
|
||||
if len(line) > 0 && line[0] == '{' {
|
||||
// Plausible test2json output. Parse it generically.
|
||||
//
|
||||
// We go to some effort here to preserve key order while doing this
|
||||
// generically. This will stay robust to changes in the test2json
|
||||
// struct, or other additions outside of it. If humans are ever looking
|
||||
// at the output, it's really nice to keep field order because it
|
||||
// preserves a lot of regularity in the output.
|
||||
dec := json.NewDecoder(bytes.NewBuffer(line))
|
||||
dec.UseNumber()
|
||||
val, err := decodeJSONValue(dec)
|
||||
if err == nil && val.atom == json.Delim('{') {
|
||||
// Rewrite the Package field.
|
||||
found := false
|
||||
for i := 0; i < len(val.seq); i += 2 {
|
||||
if val.seq[i].atom == "Package" {
|
||||
if pkg, ok := val.seq[i+1].atom.(string); ok {
|
||||
val.seq[i+1].atom = pkg + ":" + f.variant
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if found {
|
||||
data, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
// Should never happen.
|
||||
panic(fmt.Sprintf("failed to round-trip JSON %q: %s", line, err))
|
||||
}
|
||||
f.w.Write(data)
|
||||
// Copy any trailing text. We expect at most a "\n" here, but
|
||||
// there could be other text and we want to feed that through.
|
||||
io.Copy(f.w, dec.Buffered())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Something went wrong. Just pass the line through.
|
||||
f.w.Write(line)
|
||||
}
|
||||
|
||||
type jsonValue struct {
|
||||
atom json.Token // If json.Delim, then seq will be filled
|
||||
seq []jsonValue // If atom == json.Delim('{'), alternating pairs
|
||||
}
|
||||
|
||||
var jsonPop = errors.New("end of JSON sequence")
|
||||
|
||||
func decodeJSONValue(dec *json.Decoder) (jsonValue, error) {
|
||||
t, err := dec.Token()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return jsonValue{}, err
|
||||
}
|
||||
|
||||
switch t := t.(type) {
|
||||
case json.Delim:
|
||||
if t == '}' || t == ']' {
|
||||
return jsonValue{}, jsonPop
|
||||
}
|
||||
|
||||
var seq []jsonValue
|
||||
for {
|
||||
val, err := decodeJSONValue(dec)
|
||||
if err == jsonPop {
|
||||
break
|
||||
} else if err != nil {
|
||||
return jsonValue{}, err
|
||||
}
|
||||
seq = append(seq, val)
|
||||
}
|
||||
return jsonValue{t, seq}, nil
|
||||
default:
|
||||
return jsonValue{t, nil}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (v jsonValue) MarshalJSON() ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
var marshal1 func(v jsonValue) error
|
||||
marshal1 = func(v jsonValue) error {
|
||||
if t, ok := v.atom.(json.Delim); ok {
|
||||
buf.WriteRune(rune(t))
|
||||
for i, v2 := range v.seq {
|
||||
if t == '{' && i%2 == 1 {
|
||||
buf.WriteByte(':')
|
||||
} else if i > 0 {
|
||||
buf.WriteByte(',')
|
||||
}
|
||||
if err := marshal1(v2); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if t == '{' {
|
||||
buf.WriteByte('}')
|
||||
} else {
|
||||
buf.WriteByte(']')
|
||||
}
|
||||
return nil
|
||||
}
|
||||
bytes, err := json.Marshal(v.atom)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf.Write(bytes)
|
||||
return nil
|
||||
}
|
||||
err := marshal1(v)
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
func synthesizeSkipEvent(enc *json.Encoder, pkg, msg string) {
|
||||
type event struct {
|
||||
Time time.Time
|
||||
Action string
|
||||
Package string
|
||||
Output string `json:",omitempty"`
|
||||
}
|
||||
ev := event{Time: time.Now(), Package: pkg, Action: "start"}
|
||||
enc.Encode(ev)
|
||||
ev.Action = "output"
|
||||
ev.Output = msg
|
||||
enc.Encode(ev)
|
||||
ev.Action = "skip"
|
||||
ev.Output = ""
|
||||
enc.Encode(ev)
|
||||
}
|
||||
85
src/cmd/dist/testjson_test.go
vendored
Normal file
85
src/cmd/dist/testjson_test.go
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJSONFilterRewritePackage(t *testing.T) {
|
||||
const in = `{"Package":"abc"}
|
||||
{"Field1":"1","Package":"abc","Field3":"3"}
|
||||
{"Package":123}
|
||||
{}
|
||||
{"Package":"abc","Unexpected":[null,true,false,99999999999999999999]}
|
||||
`
|
||||
want := strings.ReplaceAll(in, `"Package":"abc"`, `"Package":"abc:variant"`)
|
||||
|
||||
checkJSONFilter(t, in, want)
|
||||
}
|
||||
|
||||
func TestJSONFilterMalformed(t *testing.T) {
|
||||
const in = `unexpected text
|
||||
{"Package":"abc"}
|
||||
more text
|
||||
{"Package":"abc"}trailing text
|
||||
{not json}
|
||||
no newline`
|
||||
const want = `unexpected text
|
||||
{"Package":"abc:variant"}
|
||||
more text
|
||||
{"Package":"abc:variant"}trailing text
|
||||
{not json}
|
||||
no newline`
|
||||
checkJSONFilter(t, in, want)
|
||||
}
|
||||
|
||||
func TestJSONFilterBoundaries(t *testing.T) {
|
||||
const in = `{"Package":"abc"}
|
||||
{"Package":"def"}
|
||||
{"Package":"ghi"}
|
||||
`
|
||||
want := strings.ReplaceAll(in, `"}`, `:variant"}`)
|
||||
|
||||
// Write one bytes at a time.
|
||||
t.Run("bytes", func(t *testing.T) {
|
||||
checkJSONFilterWith(t, want, func(f *testJSONFilter) {
|
||||
for i := 0; i < len(in); i++ {
|
||||
f.Write([]byte{in[i]})
|
||||
}
|
||||
})
|
||||
})
|
||||
// Write a block containing a whole line bordered by two partial lines.
|
||||
t.Run("bytes", func(t *testing.T) {
|
||||
checkJSONFilterWith(t, want, func(f *testJSONFilter) {
|
||||
const b1 = 5
|
||||
const b2 = len(in) - 5
|
||||
f.Write([]byte(in[:b1]))
|
||||
f.Write([]byte(in[b1:b2]))
|
||||
f.Write([]byte(in[b2:]))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func checkJSONFilter(t *testing.T, in, want string) {
|
||||
t.Helper()
|
||||
checkJSONFilterWith(t, want, func(f *testJSONFilter) {
|
||||
f.Write([]byte(in))
|
||||
})
|
||||
}
|
||||
|
||||
func checkJSONFilterWith(t *testing.T, want string, write func(*testJSONFilter)) {
|
||||
t.Helper()
|
||||
|
||||
out := new(strings.Builder)
|
||||
f := &testJSONFilter{w: out, variant: "variant"}
|
||||
write(f)
|
||||
f.Flush()
|
||||
got := out.String()
|
||||
if want != got {
|
||||
t.Errorf("want:\n%s\ngot:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
475
src/cmd/dist/util.go
vendored
Normal file
475
src/cmd/dist/util.go
vendored
Normal file
@@ -0,0 +1,475 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// pathf is fmt.Sprintf for generating paths
|
||||
// (on windows it turns / into \ after the printf).
|
||||
func pathf(format string, args ...interface{}) string {
|
||||
return filepath.Clean(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// filter returns a slice containing the elements x from list for which f(x) == true.
|
||||
func filter(list []string, f func(string) bool) []string {
|
||||
var out []string
|
||||
for _, x := range list {
|
||||
if f(x) {
|
||||
out = append(out, x)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// uniq returns a sorted slice containing the unique elements of list.
|
||||
func uniq(list []string) []string {
|
||||
out := make([]string, len(list))
|
||||
copy(out, list)
|
||||
sort.Strings(out)
|
||||
keep := out[:0]
|
||||
for _, x := range out {
|
||||
if len(keep) == 0 || keep[len(keep)-1] != x {
|
||||
keep = append(keep, x)
|
||||
}
|
||||
}
|
||||
return keep
|
||||
}
|
||||
|
||||
const (
|
||||
CheckExit = 1 << iota
|
||||
ShowOutput
|
||||
Background
|
||||
)
|
||||
|
||||
var outputLock sync.Mutex
|
||||
|
||||
// run is like runEnv with no additional environment.
|
||||
func run(dir string, mode int, cmd ...string) string {
|
||||
return runEnv(dir, mode, nil, cmd...)
|
||||
}
|
||||
|
||||
// runEnv runs the command line cmd in dir with additional environment env.
|
||||
// If mode has ShowOutput set and Background unset, run passes cmd's output to
|
||||
// stdout/stderr directly. Otherwise, run returns cmd's output as a string.
|
||||
// If mode has CheckExit set and the command fails, run calls fatalf.
|
||||
// If mode has Background set, this command is being run as a
|
||||
// Background job. Only bgrun should use the Background mode,
|
||||
// not other callers.
|
||||
func runEnv(dir string, mode int, env []string, cmd ...string) string {
|
||||
if vflag > 1 {
|
||||
errprintf("run: %s\n", strings.Join(cmd, " "))
|
||||
}
|
||||
|
||||
xcmd := exec.Command(cmd[0], cmd[1:]...)
|
||||
if env != nil {
|
||||
xcmd.Env = append(os.Environ(), env...)
|
||||
}
|
||||
setDir(xcmd, dir)
|
||||
var data []byte
|
||||
var err error
|
||||
|
||||
// If we want to show command output and this is not
|
||||
// a background command, assume it's the only thing
|
||||
// running, so we can just let it write directly stdout/stderr
|
||||
// as it runs without fear of mixing the output with some
|
||||
// other command's output. Not buffering lets the output
|
||||
// appear as it is printed instead of once the command exits.
|
||||
// This is most important for the invocation of 'go build -v bootstrap/...'.
|
||||
if mode&(Background|ShowOutput) == ShowOutput {
|
||||
xcmd.Stdout = os.Stdout
|
||||
xcmd.Stderr = os.Stderr
|
||||
err = xcmd.Run()
|
||||
} else {
|
||||
data, err = xcmd.CombinedOutput()
|
||||
}
|
||||
if err != nil && mode&CheckExit != 0 {
|
||||
outputLock.Lock()
|
||||
if len(data) > 0 {
|
||||
xprintf("%s\n", data)
|
||||
}
|
||||
outputLock.Unlock()
|
||||
if mode&Background != 0 {
|
||||
// Prevent fatalf from waiting on our own goroutine's
|
||||
// bghelper to exit:
|
||||
bghelpers.Done()
|
||||
}
|
||||
fatalf("FAILED: %v: %v", strings.Join(cmd, " "), err)
|
||||
}
|
||||
if mode&ShowOutput != 0 {
|
||||
outputLock.Lock()
|
||||
os.Stdout.Write(data)
|
||||
outputLock.Unlock()
|
||||
}
|
||||
if vflag > 2 {
|
||||
errprintf("run: %s DONE\n", strings.Join(cmd, " "))
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
|
||||
var maxbg = 4 /* maximum number of jobs to run at once */
|
||||
|
||||
var (
|
||||
bgwork = make(chan func(), 1e5)
|
||||
|
||||
bghelpers sync.WaitGroup
|
||||
|
||||
dieOnce sync.Once // guards close of dying
|
||||
dying = make(chan struct{})
|
||||
)
|
||||
|
||||
func bginit() {
|
||||
bghelpers.Add(maxbg)
|
||||
for i := 0; i < maxbg; i++ {
|
||||
go bghelper()
|
||||
}
|
||||
}
|
||||
|
||||
func bghelper() {
|
||||
defer bghelpers.Done()
|
||||
for {
|
||||
select {
|
||||
case <-dying:
|
||||
return
|
||||
case w := <-bgwork:
|
||||
// Dying takes precedence over doing more work.
|
||||
select {
|
||||
case <-dying:
|
||||
return
|
||||
default:
|
||||
w()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bgrun is like run but runs the command in the background.
|
||||
// CheckExit|ShowOutput mode is implied (since output cannot be returned).
|
||||
// bgrun adds 1 to wg immediately, and calls Done when the work completes.
|
||||
func bgrun(wg *sync.WaitGroup, dir string, cmd ...string) {
|
||||
wg.Add(1)
|
||||
bgwork <- func() {
|
||||
defer wg.Done()
|
||||
run(dir, CheckExit|ShowOutput|Background, cmd...)
|
||||
}
|
||||
}
|
||||
|
||||
// bgwait waits for pending bgruns to finish.
|
||||
// bgwait must be called from only a single goroutine at a time.
|
||||
func bgwait(wg *sync.WaitGroup) {
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(done)
|
||||
}()
|
||||
select {
|
||||
case <-done:
|
||||
case <-dying:
|
||||
// Don't return to the caller, to avoid reporting additional errors
|
||||
// to the user.
|
||||
select {}
|
||||
}
|
||||
}
|
||||
|
||||
// xgetwd returns the current directory.
|
||||
func xgetwd() string {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
fatalf("%s", err)
|
||||
}
|
||||
return wd
|
||||
}
|
||||
|
||||
// xrealwd returns the 'real' name for the given path.
|
||||
// real is defined as what xgetwd returns in that directory.
|
||||
func xrealwd(path string) string {
|
||||
old := xgetwd()
|
||||
if err := os.Chdir(path); err != nil {
|
||||
fatalf("chdir %s: %v", path, err)
|
||||
}
|
||||
real := xgetwd()
|
||||
if err := os.Chdir(old); err != nil {
|
||||
fatalf("chdir %s: %v", old, err)
|
||||
}
|
||||
return real
|
||||
}
|
||||
|
||||
// isdir reports whether p names an existing directory.
|
||||
func isdir(p string) bool {
|
||||
fi, err := os.Stat(p)
|
||||
return err == nil && fi.IsDir()
|
||||
}
|
||||
|
||||
// isfile reports whether p names an existing file.
|
||||
func isfile(p string) bool {
|
||||
fi, err := os.Stat(p)
|
||||
return err == nil && fi.Mode().IsRegular()
|
||||
}
|
||||
|
||||
// mtime returns the modification time of the file p.
|
||||
func mtime(p string) time.Time {
|
||||
fi, err := os.Stat(p)
|
||||
if err != nil {
|
||||
return time.Time{}
|
||||
}
|
||||
return fi.ModTime()
|
||||
}
|
||||
|
||||
// readfile returns the content of the named file.
|
||||
func readfile(file string) string {
|
||||
data, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
fatalf("%v", err)
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
|
||||
const (
|
||||
writeExec = 1 << iota
|
||||
writeSkipSame
|
||||
)
|
||||
|
||||
// writefile writes text to the named file, creating it if needed.
|
||||
// if exec is non-zero, marks the file as executable.
|
||||
// If the file already exists and has the expected content,
|
||||
// it is not rewritten, to avoid changing the time stamp.
|
||||
func writefile(text, file string, flag int) {
|
||||
new := []byte(text)
|
||||
if flag&writeSkipSame != 0 {
|
||||
old, err := os.ReadFile(file)
|
||||
if err == nil && bytes.Equal(old, new) {
|
||||
return
|
||||
}
|
||||
}
|
||||
mode := os.FileMode(0666)
|
||||
if flag&writeExec != 0 {
|
||||
mode = 0777
|
||||
}
|
||||
xremove(file) // in case of symlink tricks by misc/reboot test
|
||||
err := os.WriteFile(file, new, mode)
|
||||
if err != nil {
|
||||
fatalf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// xmkdir creates the directory p.
|
||||
func xmkdir(p string) {
|
||||
err := os.Mkdir(p, 0777)
|
||||
if err != nil {
|
||||
fatalf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// xmkdirall creates the directory p and its parents, as needed.
|
||||
func xmkdirall(p string) {
|
||||
err := os.MkdirAll(p, 0777)
|
||||
if err != nil {
|
||||
fatalf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// xremove removes the file p.
|
||||
func xremove(p string) {
|
||||
if vflag > 2 {
|
||||
errprintf("rm %s\n", p)
|
||||
}
|
||||
os.Remove(p)
|
||||
}
|
||||
|
||||
// xremoveall removes the file or directory tree rooted at p.
|
||||
func xremoveall(p string) {
|
||||
if vflag > 2 {
|
||||
errprintf("rm -r %s\n", p)
|
||||
}
|
||||
os.RemoveAll(p)
|
||||
}
|
||||
|
||||
// xreaddir replaces dst with a list of the names of the files and subdirectories in dir.
|
||||
// The names are relative to dir; they are not full paths.
|
||||
func xreaddir(dir string) []string {
|
||||
f, err := os.Open(dir)
|
||||
if err != nil {
|
||||
fatalf("%v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
names, err := f.Readdirnames(-1)
|
||||
if err != nil {
|
||||
fatalf("reading %s: %v", dir, err)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// xworkdir creates a new temporary directory to hold object files
|
||||
// and returns the name of that directory.
|
||||
func xworkdir() string {
|
||||
name, err := os.MkdirTemp(os.Getenv("GOTMPDIR"), "go-tool-dist-")
|
||||
if err != nil {
|
||||
fatalf("%v", err)
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// fatalf prints an error message to standard error and exits.
|
||||
func fatalf(format string, args ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, "go tool dist: %s\n", fmt.Sprintf(format, args...))
|
||||
|
||||
dieOnce.Do(func() { close(dying) })
|
||||
|
||||
// Wait for background goroutines to finish,
|
||||
// so that exit handler that removes the work directory
|
||||
// is not fighting with active writes or open files.
|
||||
bghelpers.Wait()
|
||||
|
||||
xexit(2)
|
||||
}
|
||||
|
||||
var atexits []func()
|
||||
|
||||
// xexit exits the process with return code n.
|
||||
func xexit(n int) {
|
||||
for i := len(atexits) - 1; i >= 0; i-- {
|
||||
atexits[i]()
|
||||
}
|
||||
os.Exit(n)
|
||||
}
|
||||
|
||||
// xatexit schedules the exit-handler f to be run when the program exits.
|
||||
func xatexit(f func()) {
|
||||
atexits = append(atexits, f)
|
||||
}
|
||||
|
||||
// xprintf prints a message to standard output.
|
||||
func xprintf(format string, args ...interface{}) {
|
||||
fmt.Printf(format, args...)
|
||||
}
|
||||
|
||||
// errprintf prints a message to standard output.
|
||||
func errprintf(format string, args ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, format, args...)
|
||||
}
|
||||
|
||||
// xsamefile reports whether f1 and f2 are the same file (or dir).
|
||||
func xsamefile(f1, f2 string) bool {
|
||||
fi1, err1 := os.Stat(f1)
|
||||
fi2, err2 := os.Stat(f2)
|
||||
if err1 != nil || err2 != nil {
|
||||
return f1 == f2
|
||||
}
|
||||
return os.SameFile(fi1, fi2)
|
||||
}
|
||||
|
||||
func xgetgoarm() string {
|
||||
// If we're building on an actual arm system, and not building
|
||||
// a cross-compiling toolchain, try to exec ourselves
|
||||
// to detect whether VFP is supported and set the default GOARM.
|
||||
// Windows requires ARMv7, so we can skip the check.
|
||||
// We've always assumed Android is ARMv7 too.
|
||||
if gohostarch == "arm" && goarch == "arm" && goos == gohostos && goos != "windows" && goos != "android" {
|
||||
// Try to exec ourselves in a mode to detect VFP support.
|
||||
// Seeing how far it gets determines which instructions failed.
|
||||
// The test is OS-agnostic.
|
||||
out := run("", 0, os.Args[0], "-check-goarm")
|
||||
v1ok := strings.Contains(out, "VFPv1 OK.")
|
||||
v3ok := strings.Contains(out, "VFPv3 OK.")
|
||||
if v1ok && v3ok {
|
||||
return "7"
|
||||
}
|
||||
if v1ok {
|
||||
return "6"
|
||||
}
|
||||
return "5"
|
||||
}
|
||||
|
||||
// Otherwise, in the absence of local information, assume GOARM=7.
|
||||
//
|
||||
// We used to assume GOARM=5 in certain contexts but not others,
|
||||
// which produced inconsistent results. For example if you cross-compiled
|
||||
// for linux/arm from a windows/amd64 machine, you got GOARM=7 binaries,
|
||||
// but if you cross-compiled for linux/arm from a linux/amd64 machine,
|
||||
// you got GOARM=5 binaries. Now the default is independent of the
|
||||
// host operating system, for better reproducibility of builds.
|
||||
return "7"
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// elfIsLittleEndian detects if the ELF file is little endian.
|
||||
func elfIsLittleEndian(fn string) bool {
|
||||
// read the ELF file header to determine the endianness without using the
|
||||
// debug/elf package.
|
||||
file, err := os.Open(fn)
|
||||
if err != nil {
|
||||
fatalf("failed to open file to determine endianness: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
var hdr [16]byte
|
||||
if _, err := io.ReadFull(file, hdr[:]); err != nil {
|
||||
fatalf("failed to read ELF header to determine endianness: %v", err)
|
||||
}
|
||||
// hdr[5] is EI_DATA byte, 1 is ELFDATA2LSB and 2 is ELFDATA2MSB
|
||||
switch hdr[5] {
|
||||
default:
|
||||
fatalf("unknown ELF endianness of %s: EI_DATA = %d", fn, hdr[5])
|
||||
case 1:
|
||||
return true
|
||||
case 2:
|
||||
return false
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// count is a flag.Value that is like a flag.Bool and a flag.Int.
|
||||
// If used as -name, it increments the count, but -name=x sets the count.
|
||||
// Used for verbose flag -v.
|
||||
type count int
|
||||
|
||||
func (c *count) String() string {
|
||||
return fmt.Sprint(int(*c))
|
||||
}
|
||||
|
||||
func (c *count) Set(s string) error {
|
||||
switch s {
|
||||
case "true":
|
||||
*c++
|
||||
case "false":
|
||||
*c = 0
|
||||
default:
|
||||
n, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid count %q", s)
|
||||
}
|
||||
*c = count(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *count) IsBoolFlag() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func xflagparse(maxargs int) {
|
||||
flag.Var((*count)(&vflag), "v", "verbosity")
|
||||
flag.Parse()
|
||||
if maxargs >= 0 && flag.NArg() > maxargs {
|
||||
flag.Usage()
|
||||
}
|
||||
}
|
||||
20
src/cmd/dist/util_gc.go
vendored
Normal file
20
src/cmd/dist/util_gc.go
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc
|
||||
|
||||
package main
|
||||
|
||||
// useVFPv1 tries to execute one VFPv1 instruction on ARM.
|
||||
// It will crash the current process if VFPv1 is missing.
|
||||
func useVFPv1()
|
||||
|
||||
// useVFPv3 tries to execute one VFPv3 instruction on ARM.
|
||||
// It will crash the current process if VFPv3 is missing.
|
||||
func useVFPv3()
|
||||
|
||||
// useARMv6K tries to run ARMv6K instructions on ARM.
|
||||
// It will crash the current process if it doesn't implement
|
||||
// ARMv6K or above.
|
||||
func useARMv6K()
|
||||
13
src/cmd/dist/util_gccgo.go
vendored
Normal file
13
src/cmd/dist/util_gccgo.go
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gccgo
|
||||
|
||||
package main
|
||||
|
||||
func useVFPv1() {}
|
||||
|
||||
func useVFPv3() {}
|
||||
|
||||
func useARMv6K() {}
|
||||
26
src/cmd/dist/vfp_arm.s
vendored
Normal file
26
src/cmd/dist/vfp_arm.s
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// try to run "vmov.f64 d0, d0" instruction
|
||||
TEXT ·useVFPv1(SB),NOSPLIT,$0
|
||||
WORD $0xeeb00b40 // vmov.f64 d0, d0
|
||||
RET
|
||||
|
||||
// try to run VFPv3-only "vmov.f64 d0, #112" instruction
|
||||
TEXT ·useVFPv3(SB),NOSPLIT,$0
|
||||
WORD $0xeeb70b00 // vmov.f64 d0, #112
|
||||
RET
|
||||
|
||||
// try to run ARMv6K (or above) "ldrexd" instruction
|
||||
TEXT ·useARMv6K(SB),NOSPLIT,$32
|
||||
MOVW R13, R2
|
||||
BIC $15, R13
|
||||
WORD $0xe1bd0f9f // ldrexd r0, r1, [sp]
|
||||
WORD $0xf57ff01f // clrex
|
||||
MOVW R2, R13
|
||||
RET
|
||||
16
src/cmd/dist/vfp_default.s
vendored
Normal file
16
src/cmd/dist/vfp_default.s
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !arm
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·useVFPv1(SB),NOSPLIT,$0
|
||||
RET
|
||||
|
||||
TEXT ·useVFPv3(SB),NOSPLIT,$0
|
||||
RET
|
||||
|
||||
TEXT ·useARMv6K(SB),NOSPLIT,$0
|
||||
RET
|
||||
Reference in New Issue
Block a user