libgo: update to Go1.10rc1
Reviewed-on: https://go-review.googlesource.com/90295 From-SVN: r257126
This commit is contained in:
parent
ace36c8bcc
commit
d779dffc4b
40 changed files with 943 additions and 495 deletions
|
@ -1,4 +1,4 @@
|
|||
13b25c25faa8afd625732d2630a4f9ece5cacb2e
|
||||
4164071703c531b5234b790b76df4931c37a8d9c
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
594668a5a96267a46282ce3007a584ec07adf705
|
||||
5348aed83e39bd1d450d92d7f627e994c2db6ebf
|
||||
|
||||
The first line of this file holds the git revision number of the
|
||||
last merge done from the master library sources.
|
||||
|
|
|
@ -1 +1 @@
|
|||
go1.10beta2
|
||||
go1.10rc1
|
||||
|
|
|
@ -341,69 +341,11 @@ in unexpected and unpredictable ways.
|
|||
Special cases
|
||||
|
||||
A few special C types which would normally be represented by a pointer
|
||||
type in Go are instead represented by a uintptr. Those types are
|
||||
the CF*Ref types from the CoreFoundation library on Darwin, including:
|
||||
type in Go are instead represented by a uintptr. Those include:
|
||||
|
||||
CFAllocatorRef
|
||||
CFArrayRef
|
||||
CFAttributedStringRef
|
||||
CFBagRef
|
||||
CFBinaryHeapRef
|
||||
CFBitVectorRef
|
||||
CFBooleanRef
|
||||
CFBundleRef
|
||||
CFCalendarRef
|
||||
CFCharacterSetRef
|
||||
CFDataRef
|
||||
CFDateFormatterRef
|
||||
CFDateRef
|
||||
CFDictionaryRef
|
||||
CFErrorRef
|
||||
CFFileDescriptorRef
|
||||
CFFileSecurityRef
|
||||
CFLocaleRef
|
||||
CFMachPortRef
|
||||
CFMessagePortRef
|
||||
CFMutableArrayRef
|
||||
CFMutableAttributedStringRef
|
||||
CFMutableBagRef
|
||||
CFMutableBitVectorRef
|
||||
CFMutableCharacterSetRef
|
||||
CFMutableDataRef
|
||||
CFMutableDictionaryRef
|
||||
CFMutableSetRef
|
||||
CFMutableStringRef
|
||||
CFNotificationCenterRef
|
||||
CFNullRef
|
||||
CFNumberFormatterRef
|
||||
CFNumberRef
|
||||
CFPlugInInstanceRef
|
||||
CFPlugInRef
|
||||
CFPropertyListRef
|
||||
CFReadStreamRef
|
||||
CFRunLoopObserverRef
|
||||
CFRunLoopRef
|
||||
CFRunLoopSourceRef
|
||||
CFRunLoopTimerRef
|
||||
CFSetRef
|
||||
CFSocketRef
|
||||
CFStringRef
|
||||
CFStringTokenizerRef
|
||||
CFTimeZoneRef
|
||||
CFTreeRef
|
||||
CFTypeRef
|
||||
CFURLCreateFromFSRef
|
||||
CFURLEnumeratorRef
|
||||
CFURLGetFSRef
|
||||
CFURLRef
|
||||
CFUUIDRef
|
||||
CFUserNotificationRef
|
||||
CFWriteStreamRef
|
||||
CFXMLNodeRef
|
||||
CFXMLParserRef
|
||||
CFXMLTreeRef
|
||||
1. The *Ref types on Darwin, rooted at CoreFoundation's CFTypeRef type.
|
||||
|
||||
Also the object types from Java's JNI interface:
|
||||
2. The object types from Java's JNI interface:
|
||||
|
||||
jobject
|
||||
jclass
|
||||
|
|
|
@ -243,6 +243,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
// Determine kinds for names we already know about,
|
||||
// like #defines or 'struct foo', before bothering with gcc.
|
||||
var names, needType []*Name
|
||||
optional := map[*Name]bool{}
|
||||
for _, key := range nameKeys(f.Name) {
|
||||
n := f.Name[key]
|
||||
// If we've already found this name as a #define
|
||||
|
@ -279,6 +280,14 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
continue
|
||||
}
|
||||
|
||||
if goos == "darwin" && strings.HasSuffix(n.C, "Ref") {
|
||||
// For FooRef, find out if FooGetTypeID exists.
|
||||
s := n.C[:len(n.C)-3] + "GetTypeID"
|
||||
n := &Name{Go: s, C: s}
|
||||
names = append(names, n)
|
||||
optional[n] = true
|
||||
}
|
||||
|
||||
// Otherwise, we'll need to find out from gcc.
|
||||
names = append(names, n)
|
||||
}
|
||||
|
@ -425,6 +434,11 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
for i, n := range names {
|
||||
switch sniff[i] {
|
||||
default:
|
||||
if sniff[i]¬Declared != 0 && optional[n] {
|
||||
// Ignore optional undeclared identifiers.
|
||||
// Don't report an error, and skip adding n to the needType array.
|
||||
continue
|
||||
}
|
||||
error_(f.NamePos[n], "could not determine kind of name for C.%s", fixGo(n.Go))
|
||||
case notStrLiteral | notType:
|
||||
n.Kind = "iconst"
|
||||
|
@ -437,6 +451,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
case notIntConst | notNumConst | notStrLiteral | notType:
|
||||
n.Kind = "not-type"
|
||||
}
|
||||
needType = append(needType, n)
|
||||
}
|
||||
if nerrors > 0 {
|
||||
// Check if compiling the preamble by itself causes any errors,
|
||||
|
@ -450,7 +465,6 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
fatalf("unresolved names")
|
||||
}
|
||||
|
||||
needType = append(needType, names...)
|
||||
return needType
|
||||
}
|
||||
|
||||
|
@ -565,6 +579,11 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
|
|||
// Record types and typedef information.
|
||||
var conv typeConv
|
||||
conv.Init(p.PtrSize, p.IntSize)
|
||||
for i, n := range names {
|
||||
if strings.HasSuffix(n.Go, "GetTypeID") && types[i].String() == "func() CFTypeID" {
|
||||
conv.getTypeIDs[n.Go[:len(n.Go)-9]] = true
|
||||
}
|
||||
}
|
||||
for i, n := range names {
|
||||
if types[i] == nil {
|
||||
continue
|
||||
|
@ -1737,6 +1756,9 @@ type typeConv struct {
|
|||
// Keys of ptrs in insertion order (deterministic worklist)
|
||||
ptrKeys []dwarf.Type
|
||||
|
||||
// Type names X for which there exists an XGetTypeID function with type func() CFTypeID.
|
||||
getTypeIDs map[string]bool
|
||||
|
||||
// Predeclared types.
|
||||
bool ast.Expr
|
||||
byte ast.Expr // denotes padding
|
||||
|
@ -1766,6 +1788,7 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
|
|||
c.intSize = intSize
|
||||
c.m = make(map[dwarf.Type]*Type)
|
||||
c.ptrs = make(map[dwarf.Type][]*Type)
|
||||
c.getTypeIDs = make(map[string]bool)
|
||||
c.bool = c.Ident("bool")
|
||||
c.byte = c.Ident("byte")
|
||||
c.int8 = c.Ident("int8")
|
||||
|
@ -2152,7 +2175,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
name := c.Ident("_Ctype_" + dt.Name)
|
||||
goIdent[name.Name] = name
|
||||
sub := c.Type(dt.Type, pos)
|
||||
if badPointerTypedef(dt) {
|
||||
if c.badPointerTypedef(dt) {
|
||||
// Treat this typedef as a uintptr.
|
||||
s := *sub
|
||||
s.Go = c.uintptr
|
||||
|
@ -2318,7 +2341,7 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
}
|
||||
// ...or the typedef is one in which we expect bad pointers.
|
||||
// It will be a uintptr instead of *X.
|
||||
if badPointerTypedef(dt) {
|
||||
if c.badPointerTypedef(dt) {
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -2666,23 +2689,43 @@ func fieldPrefix(fld []*ast.Field) string {
|
|||
// A typedef is bad if C code sometimes stores non-pointers in this type.
|
||||
// TODO: Currently our best solution is to find these manually and list them as
|
||||
// they come up. A better solution is desired.
|
||||
func badPointerTypedef(dt *dwarf.TypedefType) bool {
|
||||
if badCFType(dt) {
|
||||
func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
|
||||
if c.badCFType(dt) {
|
||||
return true
|
||||
}
|
||||
if badJNI(dt) {
|
||||
if c.badJNI(dt) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func badCFType(dt *dwarf.TypedefType) bool {
|
||||
func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool {
|
||||
// The real bad types are CFNumberRef and CFDateRef.
|
||||
// Sometimes non-pointers are stored in these types.
|
||||
// CFTypeRef is a supertype of those, so it can have bad pointers in it as well.
|
||||
// We return true for the other CF*Ref types just so casting between them is easier.
|
||||
// We return true for the other *Ref types just so casting between them is easier.
|
||||
// We identify the correct set of types as those ending in Ref and for which
|
||||
// there exists a corresponding GetTypeID function.
|
||||
// See comment below for details about the bad pointers.
|
||||
return goos == "darwin" && strings.HasPrefix(dt.Name, "CF") && strings.HasSuffix(dt.Name, "Ref")
|
||||
if goos != "darwin" {
|
||||
return false
|
||||
}
|
||||
s := dt.Name
|
||||
if !strings.HasSuffix(s, "Ref") {
|
||||
return false
|
||||
}
|
||||
s = s[:len(s)-3]
|
||||
if s == "CFType" {
|
||||
return true
|
||||
}
|
||||
if c.getTypeIDs[s] {
|
||||
return true
|
||||
}
|
||||
if i := strings.Index(s, "Mutable"); i >= 0 && c.getTypeIDs[s[:i]+s[i+7:]] {
|
||||
// Mutable and immutable variants share a type ID.
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Comment from Darwin's CFInternal.h
|
||||
|
@ -2720,7 +2763,7 @@ enum {
|
|||
};
|
||||
*/
|
||||
|
||||
func badJNI(dt *dwarf.TypedefType) bool {
|
||||
func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
|
||||
// In Dalvik and ART, the jobject type in the JNI interface of the JVM has the
|
||||
// property that it is sometimes (always?) a small integer instead of a real pointer.
|
||||
// Note: although only the android JVMs are bad in this respect, we declare the JNI types
|
||||
|
|
|
@ -35,14 +35,15 @@
|
|||
// Additional help topics:
|
||||
//
|
||||
// c calling between Go and C
|
||||
// buildmode description of build modes
|
||||
// buildmode build modes
|
||||
// cache build and test caching
|
||||
// filetype file types
|
||||
// gopath GOPATH environment variable
|
||||
// environment environment variables
|
||||
// importpath import path syntax
|
||||
// packages description of package lists
|
||||
// testflag description of testing flags
|
||||
// testfunc description of testing functions
|
||||
// packages package lists
|
||||
// testflag testing flags
|
||||
// testfunc testing functions
|
||||
//
|
||||
// Use "go help [topic]" for more information about that topic.
|
||||
//
|
||||
|
@ -756,39 +757,51 @@
|
|||
// Only a high-confidence subset of the default go vet checks are used.
|
||||
// To disable the running of go vet, use the -vet=off flag.
|
||||
//
|
||||
// Go test runs in two different modes: local directory mode when invoked with
|
||||
// no package arguments (for example, 'go test'), and package list mode when
|
||||
// invoked with package arguments (for example 'go test math', 'go test ./...',
|
||||
// and even 'go test .').
|
||||
// All test output and summary lines are printed to the go command's
|
||||
// standard output, even if the test printed them to its own standard
|
||||
// error. (The go command's standard error is reserved for printing
|
||||
// errors building the tests.)
|
||||
//
|
||||
// In local directory mode, go test compiles and tests the package sources
|
||||
// found in the current directory and then runs the resulting test binary.
|
||||
// In this mode, caching (discussed below) is disabled. After the package test
|
||||
// finishes, go test prints a summary line showing the test status ('ok' or 'FAIL'),
|
||||
// package name, and elapsed time.
|
||||
// Go test runs in two different modes:
|
||||
//
|
||||
// In package list mode, go test compiles and tests each of the packages
|
||||
// listed on the command line. If a package test passes, go test prints only
|
||||
// the final 'ok' summary line. If a package test fails, go test prints the
|
||||
// full test output. If invoked with the -bench or -v flag, go test prints
|
||||
// the full output even for passing package tests, in order to display the
|
||||
// The first, called local directory mode, occurs when go test is
|
||||
// invoked with no package arguments (for example, 'go test' or 'go
|
||||
// test -v'). In this mode, go test compiles the package sources and
|
||||
// tests found in the current directory and then runs the resulting
|
||||
// test binary. In this mode, caching (discussed below) is disabled.
|
||||
// After the package test finishes, go test prints a summary line
|
||||
// showing the test status ('ok' or 'FAIL'), package name, and elapsed
|
||||
// time.
|
||||
//
|
||||
// The second, called package list mode, occurs when go test is invoked
|
||||
// with explicit package arguments (for example 'go test math', 'go
|
||||
// test ./...', and even 'go test .'). In this mode, go test compiles
|
||||
// and tests each of the packages listed on the command line. If a
|
||||
// package test passes, go test prints only the final 'ok' summary
|
||||
// line. If a package test fails, go test prints the full test output.
|
||||
// If invoked with the -bench or -v flag, go test prints the full
|
||||
// output even for passing package tests, in order to display the
|
||||
// requested benchmark results or verbose logging.
|
||||
//
|
||||
// All test output and summary lines are printed to the go command's standard
|
||||
// output, even if the test printed them to its own standard error.
|
||||
// (The go command's standard error is reserved for printing errors building
|
||||
// the tests.)
|
||||
// In package list mode only, go test caches successful package test
|
||||
// results to avoid unnecessary repeated running of tests. When the
|
||||
// result of a test can be recovered from the cache, go test will
|
||||
// redisplay the previous output instead of running the test binary
|
||||
// again. When this happens, go test prints '(cached)' in place of the
|
||||
// elapsed time in the summary line.
|
||||
//
|
||||
// In package list mode, go test also caches successful package test results.
|
||||
// If go test has cached a previous test run using the same test binary and
|
||||
// the same command line consisting entirely of cacheable test flags
|
||||
// (defined as -cpu, -list, -parallel, -run, -short, and -v),
|
||||
// go test will redisplay the previous output instead of running the test
|
||||
// binary again. In the summary line, go test prints '(cached)' in place of
|
||||
// the elapsed time. To disable test caching, use any test flag or argument
|
||||
// other than the cacheable flags. The idiomatic way to disable test caching
|
||||
// explicitly is to use -count=1. A cached result is treated as executing in
|
||||
// no time at all, so a successful package test result will be cached and reused
|
||||
// The rule for a match in the cache is that the run involves the same
|
||||
// test binary and the flags on the command line come entirely from a
|
||||
// restricted set of 'cacheable' test flags, defined as -cpu, -list,
|
||||
// -parallel, -run, -short, and -v. If a run of go test has any test
|
||||
// or non-test flags outside this set, the result is not cached. To
|
||||
// disable test caching, use any test flag or argument other than the
|
||||
// cacheable flags. The idiomatic way to disable test caching explicitly
|
||||
// is to use -count=1. Tests that open files within the package's source
|
||||
// root (usually $GOPATH) or that consult environment variables only
|
||||
// match future runs in which the files and environment variables are unchanged.
|
||||
// A cached test result is treated as executing in no time at all,
|
||||
// so a successful package test result will be cached and reused
|
||||
// regardless of -timeout setting.
|
||||
//
|
||||
// In addition to the build flags, the flags handled by 'go test' itself are:
|
||||
|
@ -893,7 +906,7 @@
|
|||
// the C or C++ compiler, respectively, to use.
|
||||
//
|
||||
//
|
||||
// Description of build modes
|
||||
// Build modes
|
||||
//
|
||||
// The 'go build' and 'go install' commands take a -buildmode argument which
|
||||
// indicates which kind of object file is to be built. Currently supported values
|
||||
|
@ -939,6 +952,45 @@
|
|||
// import, into a Go plugin. Packages not named main are ignored.
|
||||
//
|
||||
//
|
||||
// Build and test caching
|
||||
//
|
||||
// The go command caches build outputs for reuse in future builds.
|
||||
// The default location for cache data is a subdirectory named go-build
|
||||
// in the standard user cache directory for the current operating system.
|
||||
// Setting the GOCACHE environment variable overrides this default,
|
||||
// and running 'go env GOCACHE' prints the current cache directory.
|
||||
//
|
||||
// The go command periodically deletes cached data that has not been
|
||||
// used recently. Running 'go clean -cache' deletes all cached data.
|
||||
//
|
||||
// The build cache correctly accounts for changes to Go source files,
|
||||
// compilers, compiler options, and so on: cleaning the cache explicitly
|
||||
// should not be necessary in typical use. However, the build cache
|
||||
// does not detect changes to C libraries imported with cgo.
|
||||
// If you have made changes to the C libraries on your system, you
|
||||
// will need to clean the cache explicitly or else use the -a build flag
|
||||
// (see 'go help build') to force rebuilding of packages that
|
||||
// depend on the updated C libraries.
|
||||
//
|
||||
// The go command also caches successful package test results.
|
||||
// See 'go help test' for details. Running 'go clean -testcache' removes
|
||||
// all cached test results (but not cached build results).
|
||||
//
|
||||
// The GODEBUG environment variable can enable printing of debugging
|
||||
// information about the state of the cache:
|
||||
//
|
||||
// GODEBUG=gocacheverify=1 causes the go command to bypass the
|
||||
// use of any cache entries and instead rebuild everything and check
|
||||
// that the results match existing cache entries.
|
||||
//
|
||||
// GODEBUG=gocachehash=1 causes the go command to print the inputs
|
||||
// for all of the content hashes it uses to construct cache lookup keys.
|
||||
// The output is voluminous but can be useful for debugging the cache.
|
||||
//
|
||||
// GODEBUG=gocachetest=1 causes the go command to print details of its
|
||||
// decisions about whether to reuse a cached test result.
|
||||
//
|
||||
//
|
||||
// File types
|
||||
//
|
||||
// The go command examines the contents of a restricted set of files
|
||||
|
@ -1396,7 +1448,7 @@
|
|||
// See https://golang.org/s/go14customimport for details.
|
||||
//
|
||||
//
|
||||
// Description of package lists
|
||||
// Package lists
|
||||
//
|
||||
// Many commands apply to a set of packages:
|
||||
//
|
||||
|
@ -1478,7 +1530,7 @@
|
|||
// by the go tool, as are directories named "testdata".
|
||||
//
|
||||
//
|
||||
// Description of testing flags
|
||||
// Testing flags
|
||||
//
|
||||
// The 'go test' command takes both flags that apply to 'go test' itself
|
||||
// and flags that apply to the resulting test binary.
|
||||
|
@ -1705,7 +1757,7 @@
|
|||
// binary, instead of being interpreted as the package list.
|
||||
//
|
||||
//
|
||||
// Description of testing functions
|
||||
// Testing functions
|
||||
//
|
||||
// The 'go test' command expects to find test, benchmark, and example functions
|
||||
// in the "*_test.go" files corresponding to the package under test.
|
||||
|
|
|
@ -2461,6 +2461,17 @@ func TestCoverageRuns(t *testing.T) {
|
|||
checkCoverage(tg, data)
|
||||
}
|
||||
|
||||
func TestCoverageDotImport(t *testing.T) {
|
||||
skipIfGccgo(t, "gccgo has no cover tool")
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
||||
tg.run("test", "-coverpkg=coverdot1,coverdot2", "coverdot2")
|
||||
data := tg.getStdout() + tg.getStderr()
|
||||
checkCoverage(tg, data)
|
||||
}
|
||||
|
||||
// Check that coverage analysis uses set mode.
|
||||
// Also check that coverage profiles merge correctly.
|
||||
func TestCoverageUsesSetMode(t *testing.T) {
|
||||
|
@ -3243,6 +3254,16 @@ func TestGoVetWithFlagsOff(t *testing.T) {
|
|||
tg.run("vet", "-printf=false", "vetpkg")
|
||||
}
|
||||
|
||||
// Issue 23395.
|
||||
func TestGoVetWithOnlyTestFiles(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.tempFile("src/p/p_test.go", "package p; import \"testing\"; func TestMe(*testing.T) {}")
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.run("vet", "p")
|
||||
}
|
||||
|
||||
// Issue 9767, 19769.
|
||||
func TestGoGetDotSlashDownload(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
|
|
5
libgo/go/cmd/go/internal/cache/default.go
vendored
5
libgo/go/cmd/go/internal/cache/default.go
vendored
|
@ -68,6 +68,11 @@ func DefaultDir() string {
|
|||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
dir = os.Getenv("LocalAppData")
|
||||
if dir == "" {
|
||||
// Fall back to %AppData%, the old name of
|
||||
// %LocalAppData% on Windows XP.
|
||||
dir = os.Getenv("AppData")
|
||||
}
|
||||
if dir == "" {
|
||||
return "off"
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ the C or C++ compiler, respectively, to use.
|
|||
|
||||
var HelpPackages = &base.Command{
|
||||
UsageLine: "packages",
|
||||
Short: "description of package lists",
|
||||
Short: "package lists",
|
||||
Long: `
|
||||
Many commands apply to a set of packages:
|
||||
|
||||
|
@ -586,7 +586,7 @@ command.
|
|||
|
||||
var HelpBuildmode = &base.Command{
|
||||
UsageLine: "buildmode",
|
||||
Short: "description of build modes",
|
||||
Short: "build modes",
|
||||
Long: `
|
||||
The 'go build' and 'go install' commands take a -buildmode argument which
|
||||
indicates which kind of object file is to be built. Currently supported values
|
||||
|
@ -632,3 +632,45 @@ are:
|
|||
import, into a Go plugin. Packages not named main are ignored.
|
||||
`,
|
||||
}
|
||||
|
||||
var HelpCache = &base.Command{
|
||||
UsageLine: "cache",
|
||||
Short: "build and test caching",
|
||||
Long: `
|
||||
The go command caches build outputs for reuse in future builds.
|
||||
The default location for cache data is a subdirectory named go-build
|
||||
in the standard user cache directory for the current operating system.
|
||||
Setting the GOCACHE environment variable overrides this default,
|
||||
and running 'go env GOCACHE' prints the current cache directory.
|
||||
|
||||
The go command periodically deletes cached data that has not been
|
||||
used recently. Running 'go clean -cache' deletes all cached data.
|
||||
|
||||
The build cache correctly accounts for changes to Go source files,
|
||||
compilers, compiler options, and so on: cleaning the cache explicitly
|
||||
should not be necessary in typical use. However, the build cache
|
||||
does not detect changes to C libraries imported with cgo.
|
||||
If you have made changes to the C libraries on your system, you
|
||||
will need to clean the cache explicitly or else use the -a build flag
|
||||
(see 'go help build') to force rebuilding of packages that
|
||||
depend on the updated C libraries.
|
||||
|
||||
The go command also caches successful package test results.
|
||||
See 'go help test' for details. Running 'go clean -testcache' removes
|
||||
all cached test results (but not cached build results).
|
||||
|
||||
The GODEBUG environment variable can enable printing of debugging
|
||||
information about the state of the cache:
|
||||
|
||||
GODEBUG=gocacheverify=1 causes the go command to bypass the
|
||||
use of any cache entries and instead rebuild everything and check
|
||||
that the results match existing cache entries.
|
||||
|
||||
GODEBUG=gocachehash=1 causes the go command to print the inputs
|
||||
for all of the content hashes it uses to construct cache lookup keys.
|
||||
The output is voluminous but can be useful for debugging the cache.
|
||||
|
||||
GODEBUG=gocachetest=1 causes the go command to print details of its
|
||||
decisions about whether to reuse a cached test result.
|
||||
`,
|
||||
}
|
||||
|
|
|
@ -1526,3 +1526,153 @@ func GoFilesPackage(gofiles []string) *Package {
|
|||
|
||||
return pkg
|
||||
}
|
||||
|
||||
// GetTestPackagesFor returns package structs ptest, the package p plus
|
||||
// its test files, and pxtest, the external tests of package p.
|
||||
// pxtest may be nil. If there are no test files, forceTest decides
|
||||
// whether this returns a new package struct or just returns p.
|
||||
func GetTestPackagesFor(p *Package, forceTest bool) (ptest, pxtest *Package, err error) {
|
||||
var imports, ximports []*Package
|
||||
var stk ImportStack
|
||||
stk.Push(p.ImportPath + " (test)")
|
||||
rawTestImports := str.StringList(p.TestImports)
|
||||
for i, path := range p.TestImports {
|
||||
p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], UseVendor)
|
||||
if cfg.BuildToolchainName == "gccgo" && p1.Standard {
|
||||
continue
|
||||
}
|
||||
if p1.Error != nil {
|
||||
return nil, nil, p1.Error
|
||||
}
|
||||
if len(p1.DepsErrors) > 0 {
|
||||
err := p1.DepsErrors[0]
|
||||
err.Pos = "" // show full import stack
|
||||
return nil, nil, err
|
||||
}
|
||||
if str.Contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
|
||||
// Same error that loadPackage returns (via reusePackage) in pkg.go.
|
||||
// Can't change that code, because that code is only for loading the
|
||||
// non-test copy of a package.
|
||||
err := &PackageError{
|
||||
ImportStack: testImportStack(stk[0], p1, p.ImportPath),
|
||||
Err: "import cycle not allowed in test",
|
||||
IsImportCycle: true,
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
p.TestImports[i] = p1.ImportPath
|
||||
imports = append(imports, p1)
|
||||
}
|
||||
stk.Pop()
|
||||
stk.Push(p.ImportPath + "_test")
|
||||
pxtestNeedsPtest := false
|
||||
rawXTestImports := str.StringList(p.XTestImports)
|
||||
for i, path := range p.XTestImports {
|
||||
p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], UseVendor)
|
||||
if cfg.BuildToolchainName == "gccgo" && p1.Standard {
|
||||
continue
|
||||
}
|
||||
if p1.Error != nil {
|
||||
return nil, nil, p1.Error
|
||||
}
|
||||
if len(p1.DepsErrors) > 0 {
|
||||
err := p1.DepsErrors[0]
|
||||
err.Pos = "" // show full import stack
|
||||
return nil, nil, err
|
||||
}
|
||||
if p1.ImportPath == p.ImportPath {
|
||||
pxtestNeedsPtest = true
|
||||
} else {
|
||||
ximports = append(ximports, p1)
|
||||
}
|
||||
p.XTestImports[i] = p1.ImportPath
|
||||
}
|
||||
stk.Pop()
|
||||
|
||||
// Test package.
|
||||
if len(p.TestGoFiles) > 0 || forceTest {
|
||||
ptest = new(Package)
|
||||
*ptest = *p
|
||||
ptest.GoFiles = nil
|
||||
ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
|
||||
ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
|
||||
ptest.Target = ""
|
||||
// Note: The preparation of the vet config requires that common
|
||||
// indexes in ptest.Imports, ptest.Internal.Imports, and ptest.Internal.RawImports
|
||||
// all line up (but RawImports can be shorter than the others).
|
||||
// That is, for 0 ≤ i < len(RawImports),
|
||||
// RawImports[i] is the import string in the program text,
|
||||
// Imports[i] is the expanded import string (vendoring applied or relative path expanded away),
|
||||
// and Internal.Imports[i] is the corresponding *Package.
|
||||
// Any implicitly added imports appear in Imports and Internal.Imports
|
||||
// but not RawImports (because they were not in the source code).
|
||||
// We insert TestImports, imports, and rawTestImports at the start of
|
||||
// these lists to preserve the alignment.
|
||||
ptest.Imports = str.StringList(p.TestImports, p.Imports)
|
||||
ptest.Internal.Imports = append(imports, p.Internal.Imports...)
|
||||
ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports)
|
||||
ptest.Internal.ForceLibrary = true
|
||||
ptest.Internal.Build = new(build.Package)
|
||||
*ptest.Internal.Build = *p.Internal.Build
|
||||
m := map[string][]token.Position{}
|
||||
for k, v := range p.Internal.Build.ImportPos {
|
||||
m[k] = append(m[k], v...)
|
||||
}
|
||||
for k, v := range p.Internal.Build.TestImportPos {
|
||||
m[k] = append(m[k], v...)
|
||||
}
|
||||
ptest.Internal.Build.ImportPos = m
|
||||
} else {
|
||||
ptest = p
|
||||
}
|
||||
|
||||
// External test package.
|
||||
if len(p.XTestGoFiles) > 0 {
|
||||
pxtest = &Package{
|
||||
PackagePublic: PackagePublic{
|
||||
Name: p.Name + "_test",
|
||||
ImportPath: p.ImportPath + "_test",
|
||||
Root: p.Root,
|
||||
Dir: p.Dir,
|
||||
GoFiles: p.XTestGoFiles,
|
||||
Imports: p.XTestImports,
|
||||
},
|
||||
Internal: PackageInternal{
|
||||
LocalPrefix: p.Internal.LocalPrefix,
|
||||
Build: &build.Package{
|
||||
ImportPos: p.Internal.Build.XTestImportPos,
|
||||
},
|
||||
Imports: ximports,
|
||||
RawImports: rawXTestImports,
|
||||
|
||||
Asmflags: p.Internal.Asmflags,
|
||||
Gcflags: p.Internal.Gcflags,
|
||||
Ldflags: p.Internal.Ldflags,
|
||||
Gccgoflags: p.Internal.Gccgoflags,
|
||||
},
|
||||
}
|
||||
if pxtestNeedsPtest {
|
||||
pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
|
||||
}
|
||||
}
|
||||
|
||||
return ptest, pxtest, nil
|
||||
}
|
||||
|
||||
func testImportStack(top string, p *Package, target string) []string {
|
||||
stk := []string{top, p.ImportPath}
|
||||
Search:
|
||||
for p.ImportPath != target {
|
||||
for _, p1 := range p.Internal.Imports {
|
||||
if p1.ImportPath == target || str.Contains(p1.Deps, target) {
|
||||
stk = append(stk, p1.ImportPath)
|
||||
p = p1
|
||||
continue Search
|
||||
}
|
||||
}
|
||||
// Can't happen, but in case it does...
|
||||
stk = append(stk, "<lost path to cycle>")
|
||||
break
|
||||
}
|
||||
return stk
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package test
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
|
@ -79,39 +80,51 @@ finds any problems, go test reports those and does not run the test binary.
|
|||
Only a high-confidence subset of the default go vet checks are used.
|
||||
To disable the running of go vet, use the -vet=off flag.
|
||||
|
||||
Go test runs in two different modes: local directory mode when invoked with
|
||||
no package arguments (for example, 'go test'), and package list mode when
|
||||
invoked with package arguments (for example 'go test math', 'go test ./...',
|
||||
and even 'go test .').
|
||||
All test output and summary lines are printed to the go command's
|
||||
standard output, even if the test printed them to its own standard
|
||||
error. (The go command's standard error is reserved for printing
|
||||
errors building the tests.)
|
||||
|
||||
In local directory mode, go test compiles and tests the package sources
|
||||
found in the current directory and then runs the resulting test binary.
|
||||
In this mode, caching (discussed below) is disabled. After the package test
|
||||
finishes, go test prints a summary line showing the test status ('ok' or 'FAIL'),
|
||||
package name, and elapsed time.
|
||||
Go test runs in two different modes:
|
||||
|
||||
In package list mode, go test compiles and tests each of the packages
|
||||
listed on the command line. If a package test passes, go test prints only
|
||||
the final 'ok' summary line. If a package test fails, go test prints the
|
||||
full test output. If invoked with the -bench or -v flag, go test prints
|
||||
the full output even for passing package tests, in order to display the
|
||||
The first, called local directory mode, occurs when go test is
|
||||
invoked with no package arguments (for example, 'go test' or 'go
|
||||
test -v'). In this mode, go test compiles the package sources and
|
||||
tests found in the current directory and then runs the resulting
|
||||
test binary. In this mode, caching (discussed below) is disabled.
|
||||
After the package test finishes, go test prints a summary line
|
||||
showing the test status ('ok' or 'FAIL'), package name, and elapsed
|
||||
time.
|
||||
|
||||
The second, called package list mode, occurs when go test is invoked
|
||||
with explicit package arguments (for example 'go test math', 'go
|
||||
test ./...', and even 'go test .'). In this mode, go test compiles
|
||||
and tests each of the packages listed on the command line. If a
|
||||
package test passes, go test prints only the final 'ok' summary
|
||||
line. If a package test fails, go test prints the full test output.
|
||||
If invoked with the -bench or -v flag, go test prints the full
|
||||
output even for passing package tests, in order to display the
|
||||
requested benchmark results or verbose logging.
|
||||
|
||||
All test output and summary lines are printed to the go command's standard
|
||||
output, even if the test printed them to its own standard error.
|
||||
(The go command's standard error is reserved for printing errors building
|
||||
the tests.)
|
||||
In package list mode only, go test caches successful package test
|
||||
results to avoid unnecessary repeated running of tests. When the
|
||||
result of a test can be recovered from the cache, go test will
|
||||
redisplay the previous output instead of running the test binary
|
||||
again. When this happens, go test prints '(cached)' in place of the
|
||||
elapsed time in the summary line.
|
||||
|
||||
In package list mode, go test also caches successful package test results.
|
||||
If go test has cached a previous test run using the same test binary and
|
||||
the same command line consisting entirely of cacheable test flags
|
||||
(defined as -cpu, -list, -parallel, -run, -short, and -v),
|
||||
go test will redisplay the previous output instead of running the test
|
||||
binary again. In the summary line, go test prints '(cached)' in place of
|
||||
the elapsed time. To disable test caching, use any test flag or argument
|
||||
other than the cacheable flags. The idiomatic way to disable test caching
|
||||
explicitly is to use -count=1. A cached result is treated as executing in
|
||||
no time at all, so a successful package test result will be cached and reused
|
||||
The rule for a match in the cache is that the run involves the same
|
||||
test binary and the flags on the command line come entirely from a
|
||||
restricted set of 'cacheable' test flags, defined as -cpu, -list,
|
||||
-parallel, -run, -short, and -v. If a run of go test has any test
|
||||
or non-test flags outside this set, the result is not cached. To
|
||||
disable test caching, use any test flag or argument other than the
|
||||
cacheable flags. The idiomatic way to disable test caching explicitly
|
||||
is to use -count=1. Tests that open files within the package's source
|
||||
root (usually $GOPATH) or that consult environment variables only
|
||||
match future runs in which the files and environment variables are unchanged.
|
||||
A cached test result is treated as executing in no time at all,
|
||||
so a successful package test result will be cached and reused
|
||||
regardless of -timeout setting.
|
||||
|
||||
` + strings.TrimSpace(testFlag1) + ` See 'go help testflag' for details.
|
||||
|
@ -167,7 +180,7 @@ func Usage() {
|
|||
|
||||
var HelpTestflag = &base.Command{
|
||||
UsageLine: "testflag",
|
||||
Short: "description of testing flags",
|
||||
Short: "testing flags",
|
||||
Long: `
|
||||
The 'go test' command takes both flags that apply to 'go test' itself
|
||||
and flags that apply to the resulting test binary.
|
||||
|
@ -401,7 +414,7 @@ binary, instead of being interpreted as the package list.
|
|||
|
||||
var HelpTestfunc = &base.Command{
|
||||
UsageLine: "testfunc",
|
||||
Short: "description of testing functions",
|
||||
Short: "testing functions",
|
||||
Long: `
|
||||
The 'go test' command expects to find test, benchmark, and example functions
|
||||
in the "*_test.go" files corresponding to the package under test.
|
||||
|
@ -771,62 +784,12 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
|
|||
// pmain - pkg.test binary
|
||||
var ptest, pxtest, pmain *load.Package
|
||||
|
||||
var imports, ximports []*load.Package
|
||||
var stk load.ImportStack
|
||||
stk.Push(p.ImportPath + " (test)")
|
||||
rawTestImports := str.StringList(p.TestImports)
|
||||
for i, path := range p.TestImports {
|
||||
p1 := load.LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], load.UseVendor)
|
||||
if cfg.BuildToolchainName == "gccgo" && p1.Standard {
|
||||
continue
|
||||
}
|
||||
if p1.Error != nil {
|
||||
return nil, nil, nil, p1.Error
|
||||
}
|
||||
if len(p1.DepsErrors) > 0 {
|
||||
err := p1.DepsErrors[0]
|
||||
err.Pos = "" // show full import stack
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if str.Contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
|
||||
// Same error that loadPackage returns (via reusePackage) in pkg.go.
|
||||
// Can't change that code, because that code is only for loading the
|
||||
// non-test copy of a package.
|
||||
err := &load.PackageError{
|
||||
ImportStack: testImportStack(stk[0], p1, p.ImportPath),
|
||||
Err: "import cycle not allowed in test",
|
||||
IsImportCycle: true,
|
||||
}
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
p.TestImports[i] = p1.ImportPath
|
||||
imports = append(imports, p1)
|
||||
localCover := testCover && testCoverPaths == nil
|
||||
|
||||
ptest, pxtest, err = load.GetTestPackagesFor(p, localCover || p.Name == "main")
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
stk.Pop()
|
||||
stk.Push(p.ImportPath + "_test")
|
||||
pxtestNeedsPtest := false
|
||||
rawXTestImports := str.StringList(p.XTestImports)
|
||||
for i, path := range p.XTestImports {
|
||||
p1 := load.LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], load.UseVendor)
|
||||
if cfg.BuildToolchainName == "gccgo" && p1.Standard {
|
||||
continue
|
||||
}
|
||||
if p1.Error != nil {
|
||||
return nil, nil, nil, p1.Error
|
||||
}
|
||||
if len(p1.DepsErrors) > 0 {
|
||||
err := p1.DepsErrors[0]
|
||||
err.Pos = "" // show full import stack
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if p1.ImportPath == p.ImportPath {
|
||||
pxtestNeedsPtest = true
|
||||
} else {
|
||||
ximports = append(ximports, p1)
|
||||
}
|
||||
p.XTestImports[i] = p1.ImportPath
|
||||
}
|
||||
stk.Pop()
|
||||
|
||||
// Use last element of import path, not package name.
|
||||
// They differ when package name is "main".
|
||||
|
@ -844,81 +807,12 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
|
|||
// only for this package and only for this test?
|
||||
// Yes, if -cover is on but -coverpkg has not specified
|
||||
// a list of packages for global coverage.
|
||||
localCover := testCover && testCoverPaths == nil
|
||||
|
||||
// Test package.
|
||||
if len(p.TestGoFiles) > 0 || localCover || p.Name == "main" {
|
||||
ptest = new(load.Package)
|
||||
*ptest = *p
|
||||
ptest.GoFiles = nil
|
||||
ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
|
||||
ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
|
||||
ptest.Target = ""
|
||||
// Note: The preparation of the vet config requires that common
|
||||
// indexes in ptest.Imports, ptest.Internal.Imports, and ptest.Internal.RawImports
|
||||
// all line up (but RawImports can be shorter than the others).
|
||||
// That is, for 0 ≤ i < len(RawImports),
|
||||
// RawImports[i] is the import string in the program text,
|
||||
// Imports[i] is the expanded import string (vendoring applied or relative path expanded away),
|
||||
// and Internal.Imports[i] is the corresponding *Package.
|
||||
// Any implicitly added imports appear in Imports and Internal.Imports
|
||||
// but not RawImports (because they were not in the source code).
|
||||
// We insert TestImports, imports, and rawTestImports at the start of
|
||||
// these lists to preserve the alignment.
|
||||
ptest.Imports = str.StringList(p.TestImports, p.Imports)
|
||||
ptest.Internal.Imports = append(imports, p.Internal.Imports...)
|
||||
ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports)
|
||||
ptest.Internal.ForceLibrary = true
|
||||
ptest.Internal.Build = new(build.Package)
|
||||
*ptest.Internal.Build = *p.Internal.Build
|
||||
m := map[string][]token.Position{}
|
||||
for k, v := range p.Internal.Build.ImportPos {
|
||||
m[k] = append(m[k], v...)
|
||||
}
|
||||
for k, v := range p.Internal.Build.TestImportPos {
|
||||
m[k] = append(m[k], v...)
|
||||
}
|
||||
ptest.Internal.Build.ImportPos = m
|
||||
|
||||
if localCover {
|
||||
ptest.Internal.CoverMode = testCoverMode
|
||||
var coverFiles []string
|
||||
coverFiles = append(coverFiles, ptest.GoFiles...)
|
||||
coverFiles = append(coverFiles, ptest.CgoFiles...)
|
||||
ptest.Internal.CoverVars = declareCoverVars(ptest.ImportPath, coverFiles...)
|
||||
}
|
||||
} else {
|
||||
ptest = p
|
||||
}
|
||||
|
||||
// External test package.
|
||||
if len(p.XTestGoFiles) > 0 {
|
||||
pxtest = &load.Package{
|
||||
PackagePublic: load.PackagePublic{
|
||||
Name: p.Name + "_test",
|
||||
ImportPath: p.ImportPath + "_test",
|
||||
Root: p.Root,
|
||||
Dir: p.Dir,
|
||||
GoFiles: p.XTestGoFiles,
|
||||
Imports: p.XTestImports,
|
||||
},
|
||||
Internal: load.PackageInternal{
|
||||
LocalPrefix: p.Internal.LocalPrefix,
|
||||
Build: &build.Package{
|
||||
ImportPos: p.Internal.Build.XTestImportPos,
|
||||
},
|
||||
Imports: ximports,
|
||||
RawImports: rawXTestImports,
|
||||
|
||||
Asmflags: p.Internal.Asmflags,
|
||||
Gcflags: p.Internal.Gcflags,
|
||||
Ldflags: p.Internal.Ldflags,
|
||||
Gccgoflags: p.Internal.Gccgoflags,
|
||||
},
|
||||
}
|
||||
if pxtestNeedsPtest {
|
||||
pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
|
||||
}
|
||||
if localCover {
|
||||
ptest.Internal.CoverMode = testCoverMode
|
||||
var coverFiles []string
|
||||
coverFiles = append(coverFiles, ptest.GoFiles...)
|
||||
coverFiles = append(coverFiles, ptest.CgoFiles...)
|
||||
ptest.Internal.CoverVars = declareCoverVars(ptest.ImportPath, coverFiles...)
|
||||
}
|
||||
|
||||
testDir := b.NewObjdir()
|
||||
|
@ -948,6 +842,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
|
|||
|
||||
// The generated main also imports testing, regexp, and os.
|
||||
// Also the linker introduces implicit dependencies reported by LinkerDeps.
|
||||
var stk load.ImportStack
|
||||
stk.Push("testmain")
|
||||
deps := testMainDeps // cap==len, so safe for append
|
||||
for _, d := range load.LinkerDeps(p) {
|
||||
|
@ -1153,24 +1048,6 @@ func addTestVet(b *work.Builder, p *load.Package, runAction, installAction *work
|
|||
}
|
||||
}
|
||||
|
||||
func testImportStack(top string, p *load.Package, target string) []string {
|
||||
stk := []string{top, p.ImportPath}
|
||||
Search:
|
||||
for p.ImportPath != target {
|
||||
for _, p1 := range p.Internal.Imports {
|
||||
if p1.ImportPath == target || str.Contains(p1.Deps, target) {
|
||||
stk = append(stk, p1.ImportPath)
|
||||
p = p1
|
||||
continue Search
|
||||
}
|
||||
}
|
||||
// Can't happen, but in case it does...
|
||||
stk = append(stk, "<lost path to cycle>")
|
||||
break
|
||||
}
|
||||
return stk
|
||||
}
|
||||
|
||||
func recompileForTest(pmain, preal, ptest, pxtest *load.Package) {
|
||||
// The "test copy" of preal is ptest.
|
||||
// For each package that depends on preal, make a "test copy"
|
||||
|
@ -1221,13 +1098,21 @@ func isTestFile(file string) bool {
|
|||
func declareCoverVars(importPath string, files ...string) map[string]*load.CoverVar {
|
||||
coverVars := make(map[string]*load.CoverVar)
|
||||
coverIndex := 0
|
||||
// We create the cover counters as new top-level variables in the package.
|
||||
// We need to avoid collisions with user variables (GoCover_0 is unlikely but still)
|
||||
// and more importantly with dot imports of other covered packages,
|
||||
// so we append 12 hex digits from the SHA-256 of the import path.
|
||||
// The point is only to avoid accidents, not to defeat users determined to
|
||||
// break things.
|
||||
sum := sha256.Sum256([]byte(importPath))
|
||||
h := fmt.Sprintf("%x", sum[:6])
|
||||
for _, file := range files {
|
||||
if isTestFile(file) {
|
||||
continue
|
||||
}
|
||||
coverVars[file] = &load.CoverVar{
|
||||
File: filepath.Join(importPath, file),
|
||||
Var: fmt.Sprintf("GoCover_%d", coverIndex),
|
||||
Var: fmt.Sprintf("GoCover_%d_%x", coverIndex, h),
|
||||
}
|
||||
coverIndex++
|
||||
}
|
||||
|
|
|
@ -57,7 +57,21 @@ func runVet(cmd *base.Command, args []string) {
|
|||
|
||||
root := &work.Action{Mode: "go vet"}
|
||||
for _, p := range pkgs {
|
||||
root.Deps = append(root.Deps, b.VetAction(work.ModeBuild, work.ModeBuild, p))
|
||||
ptest, pxtest, err := load.GetTestPackagesFor(p, false)
|
||||
if err != nil {
|
||||
base.Errorf("%v", err)
|
||||
continue
|
||||
}
|
||||
if len(ptest.GoFiles) == 0 && pxtest == nil {
|
||||
base.Errorf("go vet %s: no Go files in %s", p.ImportPath, p.Dir)
|
||||
continue
|
||||
}
|
||||
if len(ptest.GoFiles) > 0 {
|
||||
root.Deps = append(root.Deps, b.VetAction(work.ModeBuild, work.ModeBuild, ptest))
|
||||
}
|
||||
if pxtest != nil {
|
||||
root.Deps = append(root.Deps, b.VetAction(work.ModeBuild, work.ModeBuild, pxtest))
|
||||
}
|
||||
}
|
||||
b.Do(root)
|
||||
}
|
||||
|
|
|
@ -652,11 +652,9 @@ func (b *Builder) linkSharedAction(mode, depMode BuildMode, shlib string, a1 *Ac
|
|||
// it is not present in another shared library, add it here.
|
||||
// TODO(rsc): Maybe this should only happen if "runtime" is in the original package set.
|
||||
// TODO(rsc): This should probably be changed to use load.LinkerDeps(p).
|
||||
// TODO(rsc): Find out and explain here why gccgo is excluded.
|
||||
// If the answer is that gccgo is different in implicit linker deps, maybe
|
||||
// load.LinkerDeps should be used and updated.
|
||||
// Link packages into a shared library.
|
||||
|
||||
// TODO(rsc): We don't add standard library imports for gccgo
|
||||
// because they are all always linked in anyhow.
|
||||
// Maybe load.LinkerDeps should be used and updated.
|
||||
a := &Action{
|
||||
Mode: "go build -buildmode=shared",
|
||||
Package: p,
|
||||
|
|
|
@ -308,7 +308,7 @@ func (b *Builder) build(a *Action) (err error) {
|
|||
// Need to look for install header actions depending on this action,
|
||||
// or depending on a link that depends on this action.
|
||||
needHeader := false
|
||||
if (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-header") {
|
||||
if (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
|
||||
for _, t1 := range a.triggers {
|
||||
if t1.Mode == "install header" {
|
||||
needHeader = true
|
||||
|
|
|
@ -206,7 +206,6 @@ func (gccgoToolchain) pack(b *Builder, a *Action, afile string, ofiles []string)
|
|||
func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string, allactions []*Action, buildmode, desc string) error {
|
||||
// gccgo needs explicit linking with all package dependencies,
|
||||
// and all LDFLAGS from cgo dependencies.
|
||||
apackagePathsSeen := make(map[string]bool)
|
||||
afiles := []string{}
|
||||
shlibs := []string{}
|
||||
ldflags := b.gccArchArgs()
|
||||
|
@ -294,56 +293,57 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string
|
|||
return newArchive, nil
|
||||
}
|
||||
|
||||
actionsSeen := make(map[*Action]bool)
|
||||
// Make a pre-order depth-first traversal of the action graph, taking note of
|
||||
// whether a shared library action has been seen on the way to an action (the
|
||||
// construction of the graph means that if any path to a node passes through
|
||||
// a shared library action, they all do).
|
||||
var walk func(a *Action, seenShlib bool)
|
||||
var err error
|
||||
walk = func(a *Action, seenShlib bool) {
|
||||
if actionsSeen[a] {
|
||||
return
|
||||
}
|
||||
actionsSeen[a] = true
|
||||
if a.Package != nil && !seenShlib {
|
||||
if a.Package.Standard {
|
||||
return
|
||||
// If using -linkshared, find the shared library deps.
|
||||
haveShlib := make(map[string]bool)
|
||||
targetBase := filepath.Base(root.Target)
|
||||
if cfg.BuildLinkshared {
|
||||
for _, a := range root.Deps {
|
||||
p := a.Package
|
||||
if p == nil || p.Shlib == "" {
|
||||
continue
|
||||
}
|
||||
// We record the target of the first time we see a .a file
|
||||
// for a package to make sure that we prefer the 'install'
|
||||
// rather than the 'build' location (which may not exist any
|
||||
// more). We still need to traverse the dependencies of the
|
||||
// build action though so saying
|
||||
// if apackagePathsSeen[a.Package.ImportPath] { return }
|
||||
// doesn't work.
|
||||
if !apackagePathsSeen[a.Package.ImportPath] {
|
||||
apackagePathsSeen[a.Package.ImportPath] = true
|
||||
target := a.built
|
||||
if len(a.Package.CgoFiles) > 0 || a.Package.UsesSwig() {
|
||||
target, err = readAndRemoveCgoFlags(target)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
afiles = append(afiles, target)
|
||||
}
|
||||
}
|
||||
if strings.HasSuffix(a.Target, ".so") {
|
||||
shlibs = append(shlibs, a.Target)
|
||||
seenShlib = true
|
||||
}
|
||||
for _, a1 := range a.Deps {
|
||||
walk(a1, seenShlib)
|
||||
if err != nil {
|
||||
return
|
||||
|
||||
// The .a we are linking into this .so
|
||||
// will have its Shlib set to this .so.
|
||||
// Don't start thinking we want to link
|
||||
// this .so into itself.
|
||||
base := filepath.Base(p.Shlib)
|
||||
if base != targetBase {
|
||||
haveShlib[base] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, a1 := range root.Deps {
|
||||
walk(a1, false)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
// Arrange the deps into afiles and shlibs.
|
||||
addedShlib := make(map[string]bool)
|
||||
for _, a := range root.Deps {
|
||||
p := a.Package
|
||||
if p != nil && p.Shlib != "" && haveShlib[filepath.Base(p.Shlib)] {
|
||||
// This is a package linked into a shared
|
||||
// library that we will put into shlibs.
|
||||
continue
|
||||
}
|
||||
|
||||
if haveShlib[filepath.Base(a.Target)] {
|
||||
// This is a shared library we want to link againt.
|
||||
if !addedShlib[a.Target] {
|
||||
shlibs = append(shlibs, a.Target)
|
||||
addedShlib[a.Target] = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if p != nil {
|
||||
target := a.built
|
||||
if p.UsesCgo() || p.UsesSwig() {
|
||||
var err error
|
||||
target, err = readAndRemoveCgoFlags(target)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
afiles = append(afiles, target)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -511,9 +511,7 @@ func (tools gccgoToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg
|
|||
}
|
||||
|
||||
func (tools gccgoToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error {
|
||||
fakeRoot := *root
|
||||
fakeRoot.Deps = toplevelactions
|
||||
return tools.link(b, &fakeRoot, out, importcfg, allactions, "shared", out)
|
||||
return tools.link(b, root, out, importcfg, allactions, "shared", out)
|
||||
}
|
||||
|
||||
func (tools gccgoToolchain) cc(b *Builder, a *Action, ofile, cfile string) error {
|
||||
|
|
|
@ -56,6 +56,7 @@ func init() {
|
|||
|
||||
help.HelpC,
|
||||
help.HelpBuildmode,
|
||||
help.HelpCache,
|
||||
help.HelpFileType,
|
||||
help.HelpGopath,
|
||||
help.HelpEnvironment,
|
||||
|
|
|
@ -781,7 +781,17 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
|
|||
// If opts.Roots is nil and system roots are unavailable the returned error
|
||||
// will be of type SystemRootsError.
|
||||
//
|
||||
// WARNING: this doesn't do any revocation checking.
|
||||
// Name constraints in the intermediates will be applied to all names claimed
|
||||
// in the chain, not just opts.DNSName. Thus it is invalid for a leaf to claim
|
||||
// example.com if an intermediate doesn't permit it, even if example.com is not
|
||||
// the name being validated. Note that DirectoryName constraints are not
|
||||
// supported.
|
||||
//
|
||||
// Extended Key Usage values are enforced down a chain, so an intermediate or
|
||||
// root that enumerates EKUs prevents a leaf from asserting an EKU not in that
|
||||
// list.
|
||||
//
|
||||
// WARNING: this function doesn't do any revocation checking.
|
||||
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
|
||||
// Platform-specific verification needs the ASN.1 contents so
|
||||
// this makes the behavior consistent across platforms.
|
||||
|
|
|
@ -64,125 +64,128 @@ var (
|
|||
scaniface interface{}
|
||||
)
|
||||
|
||||
var conversionTests = []conversionTest{
|
||||
// Exact conversions (destination pointer type matches source type)
|
||||
{s: "foo", d: &scanstr, wantstr: "foo"},
|
||||
{s: 123, d: &scanint, wantint: 123},
|
||||
{s: someTime, d: &scantime, wanttime: someTime},
|
||||
func conversionTests() []conversionTest {
|
||||
// Return a fresh instance to test so "go test -count 2" works correctly.
|
||||
return []conversionTest{
|
||||
// Exact conversions (destination pointer type matches source type)
|
||||
{s: "foo", d: &scanstr, wantstr: "foo"},
|
||||
{s: 123, d: &scanint, wantint: 123},
|
||||
{s: someTime, d: &scantime, wanttime: someTime},
|
||||
|
||||
// To strings
|
||||
{s: "string", d: &scanstr, wantstr: "string"},
|
||||
{s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"},
|
||||
{s: 123, d: &scanstr, wantstr: "123"},
|
||||
{s: int8(123), d: &scanstr, wantstr: "123"},
|
||||
{s: int64(123), d: &scanstr, wantstr: "123"},
|
||||
{s: uint8(123), d: &scanstr, wantstr: "123"},
|
||||
{s: uint16(123), d: &scanstr, wantstr: "123"},
|
||||
{s: uint32(123), d: &scanstr, wantstr: "123"},
|
||||
{s: uint64(123), d: &scanstr, wantstr: "123"},
|
||||
{s: 1.5, d: &scanstr, wantstr: "1.5"},
|
||||
// To strings
|
||||
{s: "string", d: &scanstr, wantstr: "string"},
|
||||
{s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"},
|
||||
{s: 123, d: &scanstr, wantstr: "123"},
|
||||
{s: int8(123), d: &scanstr, wantstr: "123"},
|
||||
{s: int64(123), d: &scanstr, wantstr: "123"},
|
||||
{s: uint8(123), d: &scanstr, wantstr: "123"},
|
||||
{s: uint16(123), d: &scanstr, wantstr: "123"},
|
||||
{s: uint32(123), d: &scanstr, wantstr: "123"},
|
||||
{s: uint64(123), d: &scanstr, wantstr: "123"},
|
||||
{s: 1.5, d: &scanstr, wantstr: "1.5"},
|
||||
|
||||
// From time.Time:
|
||||
{s: time.Unix(1, 0).UTC(), d: &scanstr, wantstr: "1970-01-01T00:00:01Z"},
|
||||
{s: time.Unix(1453874597, 0).In(time.FixedZone("here", -3600*8)), d: &scanstr, wantstr: "2016-01-26T22:03:17-08:00"},
|
||||
{s: time.Unix(1, 2).UTC(), d: &scanstr, wantstr: "1970-01-01T00:00:01.000000002Z"},
|
||||
{s: time.Time{}, d: &scanstr, wantstr: "0001-01-01T00:00:00Z"},
|
||||
{s: time.Unix(1, 2).UTC(), d: &scanbytes, wantbytes: []byte("1970-01-01T00:00:01.000000002Z")},
|
||||
{s: time.Unix(1, 2).UTC(), d: &scaniface, wantiface: time.Unix(1, 2).UTC()},
|
||||
// From time.Time:
|
||||
{s: time.Unix(1, 0).UTC(), d: &scanstr, wantstr: "1970-01-01T00:00:01Z"},
|
||||
{s: time.Unix(1453874597, 0).In(time.FixedZone("here", -3600*8)), d: &scanstr, wantstr: "2016-01-26T22:03:17-08:00"},
|
||||
{s: time.Unix(1, 2).UTC(), d: &scanstr, wantstr: "1970-01-01T00:00:01.000000002Z"},
|
||||
{s: time.Time{}, d: &scanstr, wantstr: "0001-01-01T00:00:00Z"},
|
||||
{s: time.Unix(1, 2).UTC(), d: &scanbytes, wantbytes: []byte("1970-01-01T00:00:01.000000002Z")},
|
||||
{s: time.Unix(1, 2).UTC(), d: &scaniface, wantiface: time.Unix(1, 2).UTC()},
|
||||
|
||||
// To []byte
|
||||
{s: nil, d: &scanbytes, wantbytes: nil},
|
||||
{s: "string", d: &scanbytes, wantbytes: []byte("string")},
|
||||
{s: []byte("byteslice"), d: &scanbytes, wantbytes: []byte("byteslice")},
|
||||
{s: 123, d: &scanbytes, wantbytes: []byte("123")},
|
||||
{s: int8(123), d: &scanbytes, wantbytes: []byte("123")},
|
||||
{s: int64(123), d: &scanbytes, wantbytes: []byte("123")},
|
||||
{s: uint8(123), d: &scanbytes, wantbytes: []byte("123")},
|
||||
{s: uint16(123), d: &scanbytes, wantbytes: []byte("123")},
|
||||
{s: uint32(123), d: &scanbytes, wantbytes: []byte("123")},
|
||||
{s: uint64(123), d: &scanbytes, wantbytes: []byte("123")},
|
||||
{s: 1.5, d: &scanbytes, wantbytes: []byte("1.5")},
|
||||
// To []byte
|
||||
{s: nil, d: &scanbytes, wantbytes: nil},
|
||||
{s: "string", d: &scanbytes, wantbytes: []byte("string")},
|
||||
{s: []byte("byteslice"), d: &scanbytes, wantbytes: []byte("byteslice")},
|
||||
{s: 123, d: &scanbytes, wantbytes: []byte("123")},
|
||||
{s: int8(123), d: &scanbytes, wantbytes: []byte("123")},
|
||||
{s: int64(123), d: &scanbytes, wantbytes: []byte("123")},
|
||||
{s: uint8(123), d: &scanbytes, wantbytes: []byte("123")},
|
||||
{s: uint16(123), d: &scanbytes, wantbytes: []byte("123")},
|
||||
{s: uint32(123), d: &scanbytes, wantbytes: []byte("123")},
|
||||
{s: uint64(123), d: &scanbytes, wantbytes: []byte("123")},
|
||||
{s: 1.5, d: &scanbytes, wantbytes: []byte("1.5")},
|
||||
|
||||
// To RawBytes
|
||||
{s: nil, d: &scanraw, wantraw: nil},
|
||||
{s: []byte("byteslice"), d: &scanraw, wantraw: RawBytes("byteslice")},
|
||||
{s: "string", d: &scanraw, wantraw: RawBytes("string")},
|
||||
{s: 123, d: &scanraw, wantraw: RawBytes("123")},
|
||||
{s: int8(123), d: &scanraw, wantraw: RawBytes("123")},
|
||||
{s: int64(123), d: &scanraw, wantraw: RawBytes("123")},
|
||||
{s: uint8(123), d: &scanraw, wantraw: RawBytes("123")},
|
||||
{s: uint16(123), d: &scanraw, wantraw: RawBytes("123")},
|
||||
{s: uint32(123), d: &scanraw, wantraw: RawBytes("123")},
|
||||
{s: uint64(123), d: &scanraw, wantraw: RawBytes("123")},
|
||||
{s: 1.5, d: &scanraw, wantraw: RawBytes("1.5")},
|
||||
// time.Time has been placed here to check that the RawBytes slice gets
|
||||
// correctly reset when calling time.Time.AppendFormat.
|
||||
{s: time.Unix(2, 5).UTC(), d: &scanraw, wantraw: RawBytes("1970-01-01T00:00:02.000000005Z")},
|
||||
// To RawBytes
|
||||
{s: nil, d: &scanraw, wantraw: nil},
|
||||
{s: []byte("byteslice"), d: &scanraw, wantraw: RawBytes("byteslice")},
|
||||
{s: "string", d: &scanraw, wantraw: RawBytes("string")},
|
||||
{s: 123, d: &scanraw, wantraw: RawBytes("123")},
|
||||
{s: int8(123), d: &scanraw, wantraw: RawBytes("123")},
|
||||
{s: int64(123), d: &scanraw, wantraw: RawBytes("123")},
|
||||
{s: uint8(123), d: &scanraw, wantraw: RawBytes("123")},
|
||||
{s: uint16(123), d: &scanraw, wantraw: RawBytes("123")},
|
||||
{s: uint32(123), d: &scanraw, wantraw: RawBytes("123")},
|
||||
{s: uint64(123), d: &scanraw, wantraw: RawBytes("123")},
|
||||
{s: 1.5, d: &scanraw, wantraw: RawBytes("1.5")},
|
||||
// time.Time has been placed here to check that the RawBytes slice gets
|
||||
// correctly reset when calling time.Time.AppendFormat.
|
||||
{s: time.Unix(2, 5).UTC(), d: &scanraw, wantraw: RawBytes("1970-01-01T00:00:02.000000005Z")},
|
||||
|
||||
// Strings to integers
|
||||
{s: "255", d: &scanuint8, wantuint: 255},
|
||||
{s: "256", d: &scanuint8, wanterr: "converting driver.Value type string (\"256\") to a uint8: value out of range"},
|
||||
{s: "256", d: &scanuint16, wantuint: 256},
|
||||
{s: "-1", d: &scanint, wantint: -1},
|
||||
{s: "foo", d: &scanint, wanterr: "converting driver.Value type string (\"foo\") to a int: invalid syntax"},
|
||||
// Strings to integers
|
||||
{s: "255", d: &scanuint8, wantuint: 255},
|
||||
{s: "256", d: &scanuint8, wanterr: "converting driver.Value type string (\"256\") to a uint8: value out of range"},
|
||||
{s: "256", d: &scanuint16, wantuint: 256},
|
||||
{s: "-1", d: &scanint, wantint: -1},
|
||||
{s: "foo", d: &scanint, wanterr: "converting driver.Value type string (\"foo\") to a int: invalid syntax"},
|
||||
|
||||
// int64 to smaller integers
|
||||
{s: int64(5), d: &scanuint8, wantuint: 5},
|
||||
{s: int64(256), d: &scanuint8, wanterr: "converting driver.Value type int64 (\"256\") to a uint8: value out of range"},
|
||||
{s: int64(256), d: &scanuint16, wantuint: 256},
|
||||
{s: int64(65536), d: &scanuint16, wanterr: "converting driver.Value type int64 (\"65536\") to a uint16: value out of range"},
|
||||
// int64 to smaller integers
|
||||
{s: int64(5), d: &scanuint8, wantuint: 5},
|
||||
{s: int64(256), d: &scanuint8, wanterr: "converting driver.Value type int64 (\"256\") to a uint8: value out of range"},
|
||||
{s: int64(256), d: &scanuint16, wantuint: 256},
|
||||
{s: int64(65536), d: &scanuint16, wanterr: "converting driver.Value type int64 (\"65536\") to a uint16: value out of range"},
|
||||
|
||||
// True bools
|
||||
{s: true, d: &scanbool, wantbool: true},
|
||||
{s: "True", d: &scanbool, wantbool: true},
|
||||
{s: "TRUE", d: &scanbool, wantbool: true},
|
||||
{s: "1", d: &scanbool, wantbool: true},
|
||||
{s: 1, d: &scanbool, wantbool: true},
|
||||
{s: int64(1), d: &scanbool, wantbool: true},
|
||||
{s: uint16(1), d: &scanbool, wantbool: true},
|
||||
// True bools
|
||||
{s: true, d: &scanbool, wantbool: true},
|
||||
{s: "True", d: &scanbool, wantbool: true},
|
||||
{s: "TRUE", d: &scanbool, wantbool: true},
|
||||
{s: "1", d: &scanbool, wantbool: true},
|
||||
{s: 1, d: &scanbool, wantbool: true},
|
||||
{s: int64(1), d: &scanbool, wantbool: true},
|
||||
{s: uint16(1), d: &scanbool, wantbool: true},
|
||||
|
||||
// False bools
|
||||
{s: false, d: &scanbool, wantbool: false},
|
||||
{s: "false", d: &scanbool, wantbool: false},
|
||||
{s: "FALSE", d: &scanbool, wantbool: false},
|
||||
{s: "0", d: &scanbool, wantbool: false},
|
||||
{s: 0, d: &scanbool, wantbool: false},
|
||||
{s: int64(0), d: &scanbool, wantbool: false},
|
||||
{s: uint16(0), d: &scanbool, wantbool: false},
|
||||
// False bools
|
||||
{s: false, d: &scanbool, wantbool: false},
|
||||
{s: "false", d: &scanbool, wantbool: false},
|
||||
{s: "FALSE", d: &scanbool, wantbool: false},
|
||||
{s: "0", d: &scanbool, wantbool: false},
|
||||
{s: 0, d: &scanbool, wantbool: false},
|
||||
{s: int64(0), d: &scanbool, wantbool: false},
|
||||
{s: uint16(0), d: &scanbool, wantbool: false},
|
||||
|
||||
// Not bools
|
||||
{s: "yup", d: &scanbool, wanterr: `sql/driver: couldn't convert "yup" into type bool`},
|
||||
{s: 2, d: &scanbool, wanterr: `sql/driver: couldn't convert 2 into type bool`},
|
||||
// Not bools
|
||||
{s: "yup", d: &scanbool, wanterr: `sql/driver: couldn't convert "yup" into type bool`},
|
||||
{s: 2, d: &scanbool, wanterr: `sql/driver: couldn't convert 2 into type bool`},
|
||||
|
||||
// Floats
|
||||
{s: float64(1.5), d: &scanf64, wantf64: float64(1.5)},
|
||||
{s: int64(1), d: &scanf64, wantf64: float64(1)},
|
||||
{s: float64(1.5), d: &scanf32, wantf32: float32(1.5)},
|
||||
{s: "1.5", d: &scanf32, wantf32: float32(1.5)},
|
||||
{s: "1.5", d: &scanf64, wantf64: float64(1.5)},
|
||||
// Floats
|
||||
{s: float64(1.5), d: &scanf64, wantf64: float64(1.5)},
|
||||
{s: int64(1), d: &scanf64, wantf64: float64(1)},
|
||||
{s: float64(1.5), d: &scanf32, wantf32: float32(1.5)},
|
||||
{s: "1.5", d: &scanf32, wantf32: float32(1.5)},
|
||||
{s: "1.5", d: &scanf64, wantf64: float64(1.5)},
|
||||
|
||||
// Pointers
|
||||
{s: interface{}(nil), d: &scanptr, wantnil: true},
|
||||
{s: int64(42), d: &scanptr, wantptr: &answer},
|
||||
// Pointers
|
||||
{s: interface{}(nil), d: &scanptr, wantnil: true},
|
||||
{s: int64(42), d: &scanptr, wantptr: &answer},
|
||||
|
||||
// To interface{}
|
||||
{s: float64(1.5), d: &scaniface, wantiface: float64(1.5)},
|
||||
{s: int64(1), d: &scaniface, wantiface: int64(1)},
|
||||
{s: "str", d: &scaniface, wantiface: "str"},
|
||||
{s: []byte("byteslice"), d: &scaniface, wantiface: []byte("byteslice")},
|
||||
{s: true, d: &scaniface, wantiface: true},
|
||||
{s: nil, d: &scaniface},
|
||||
{s: []byte(nil), d: &scaniface, wantiface: []byte(nil)},
|
||||
// To interface{}
|
||||
{s: float64(1.5), d: &scaniface, wantiface: float64(1.5)},
|
||||
{s: int64(1), d: &scaniface, wantiface: int64(1)},
|
||||
{s: "str", d: &scaniface, wantiface: "str"},
|
||||
{s: []byte("byteslice"), d: &scaniface, wantiface: []byte("byteslice")},
|
||||
{s: true, d: &scaniface, wantiface: true},
|
||||
{s: nil, d: &scaniface},
|
||||
{s: []byte(nil), d: &scaniface, wantiface: []byte(nil)},
|
||||
|
||||
// To a user-defined type
|
||||
{s: 1.5, d: new(userDefined), wantusrdef: 1.5},
|
||||
{s: int64(123), d: new(userDefined), wantusrdef: 123},
|
||||
{s: "1.5", d: new(userDefined), wantusrdef: 1.5},
|
||||
{s: []byte{1, 2, 3}, d: new(userDefinedSlice), wanterr: `unsupported Scan, storing driver.Value type []uint8 into type *sql.userDefinedSlice`},
|
||||
{s: "str", d: new(userDefinedString), wantusrstr: "str"},
|
||||
// To a user-defined type
|
||||
{s: 1.5, d: new(userDefined), wantusrdef: 1.5},
|
||||
{s: int64(123), d: new(userDefined), wantusrdef: 123},
|
||||
{s: "1.5", d: new(userDefined), wantusrdef: 1.5},
|
||||
{s: []byte{1, 2, 3}, d: new(userDefinedSlice), wanterr: `unsupported Scan, storing driver.Value type []uint8 into type *sql.userDefinedSlice`},
|
||||
{s: "str", d: new(userDefinedString), wantusrstr: "str"},
|
||||
|
||||
// Other errors
|
||||
{s: complex(1, 2), d: &scanstr, wanterr: `unsupported Scan, storing driver.Value type complex128 into type *string`},
|
||||
// Other errors
|
||||
{s: complex(1, 2), d: &scanstr, wanterr: `unsupported Scan, storing driver.Value type complex128 into type *string`},
|
||||
}
|
||||
}
|
||||
|
||||
func intPtrValue(intptr interface{}) interface{} {
|
||||
|
@ -210,7 +213,7 @@ func timeValue(ptr interface{}) time.Time {
|
|||
}
|
||||
|
||||
func TestConversions(t *testing.T) {
|
||||
for n, ct := range conversionTests {
|
||||
for n, ct := range conversionTests() {
|
||||
err := convertAssign(ct.d, ct.s)
|
||||
errstr := ""
|
||||
if err != nil {
|
||||
|
|
|
@ -154,8 +154,11 @@ func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
|
|||
var v_used bool
|
||||
if ident != nil {
|
||||
if _, obj := check.scope.LookupParent(ident.Name, token.NoPos); obj != nil {
|
||||
v, _ = obj.(*Var)
|
||||
if v != nil {
|
||||
// It's ok to mark non-local variables, but ignore variables
|
||||
// from other packages to avoid potential race conditions with
|
||||
// dot-imported variables.
|
||||
if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
|
||||
v = w
|
||||
v_used = v.used
|
||||
}
|
||||
}
|
||||
|
@ -249,6 +252,7 @@ func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
|
|||
l := len(lhs)
|
||||
get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2)
|
||||
if get == nil {
|
||||
check.useLHS(lhs...)
|
||||
return // error reported by unpack
|
||||
}
|
||||
if l != r {
|
||||
|
|
|
@ -90,15 +90,52 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
|
|||
// use type-checks each argument.
|
||||
// Useful to make sure expressions are evaluated
|
||||
// (and variables are "used") in the presence of other errors.
|
||||
// The arguments may be nil.
|
||||
func (check *Checker) use(arg ...ast.Expr) {
|
||||
var x operand
|
||||
for _, e := range arg {
|
||||
if e != nil { // be safe
|
||||
// The nil check below is necessary since certain AST fields
|
||||
// may legally be nil (e.g., the ast.SliceExpr.High field).
|
||||
if e != nil {
|
||||
check.rawExpr(&x, e, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// useLHS is like use, but doesn't "use" top-level identifiers.
|
||||
// It should be called instead of use if the arguments are
|
||||
// expressions on the lhs of an assignment.
|
||||
// The arguments must not be nil.
|
||||
func (check *Checker) useLHS(arg ...ast.Expr) {
|
||||
var x operand
|
||||
for _, e := range arg {
|
||||
// If the lhs is an identifier denoting a variable v, this assignment
|
||||
// is not a 'use' of v. Remember current value of v.used and restore
|
||||
// after evaluating the lhs via check.rawExpr.
|
||||
var v *Var
|
||||
var v_used bool
|
||||
if ident, _ := unparen(e).(*ast.Ident); ident != nil {
|
||||
// never type-check the blank name on the lhs
|
||||
if ident.Name == "_" {
|
||||
continue
|
||||
}
|
||||
if _, obj := check.scope.LookupParent(ident.Name, token.NoPos); obj != nil {
|
||||
// It's ok to mark non-local variables, but ignore variables
|
||||
// from other packages to avoid potential race conditions with
|
||||
// dot-imported variables.
|
||||
if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
|
||||
v = w
|
||||
v_used = v.used
|
||||
}
|
||||
}
|
||||
}
|
||||
check.rawExpr(&x, e, nil)
|
||||
if v != nil {
|
||||
v.used = v_used // restore v.used
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// useGetter is like use, but takes a getter instead of a list of expressions.
|
||||
// It should be called instead of use if a getter is present to avoid repeated
|
||||
// evaluation of the first argument (since the getter was likely obtained via
|
||||
|
|
|
@ -111,7 +111,11 @@ func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) {
|
|||
if typ != nil {
|
||||
t := check.typ(typ)
|
||||
if !isConstType(t) {
|
||||
check.errorf(typ.Pos(), "invalid constant type %s", t)
|
||||
// don't report an error if the type is an invalid C (defined) type
|
||||
// (issue #22090)
|
||||
if t.Underlying() != Typ[Invalid] {
|
||||
check.errorf(typ.Pos(), "invalid constant type %s", t)
|
||||
}
|
||||
obj.typ = Typ[Invalid]
|
||||
return
|
||||
}
|
||||
|
|
|
@ -731,6 +731,9 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
|||
// declaration, but the post statement must not."
|
||||
if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
|
||||
check.softErrorf(s.Pos(), "cannot declare in post statement")
|
||||
// Don't call useLHS here because we want to use the lhs in
|
||||
// this erroneous statement so that we don't get errors about
|
||||
// these lhs variables being declared but not used.
|
||||
check.use(s.Lhs...) // avoid follow-up errors
|
||||
}
|
||||
check.stmt(inner, s.Body)
|
||||
|
|
25
libgo/go/go/types/testdata/importC.src
vendored
25
libgo/go/go/types/testdata/importC.src
vendored
|
@ -8,3 +8,28 @@ import "C"
|
|||
import _ /* ERROR cannot rename import "C" */ "C"
|
||||
import foo /* ERROR cannot rename import "C" */ "C"
|
||||
import . /* ERROR cannot rename import "C" */ "C"
|
||||
|
||||
// Test cases extracted from issue #22090.
|
||||
|
||||
import "unsafe"
|
||||
|
||||
const _ C.int = 0xff // no error due to invalid constant type
|
||||
|
||||
type T struct {
|
||||
Name string
|
||||
Ordinal int
|
||||
}
|
||||
|
||||
func f(args []T) {
|
||||
var s string
|
||||
for i, v := range args {
|
||||
cname := C.CString(v.Name)
|
||||
args[i].Ordinal = int(C.sqlite3_bind_parameter_index(s, cname)) // no error due to i not being "used"
|
||||
C.free(unsafe.Pointer(cname))
|
||||
}
|
||||
}
|
||||
|
||||
type CType C.Type
|
||||
|
||||
const _ CType = C.X // no error due to invalid constant type
|
||||
const _ = C.X
|
||||
|
|
|
@ -86,6 +86,9 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeNa
|
|||
}
|
||||
|
||||
case *Var:
|
||||
// It's ok to mark non-local variables, but ignore variables
|
||||
// from other packages to avoid potential race conditions with
|
||||
// dot-imported variables.
|
||||
if obj.pkg == check.pkg {
|
||||
obj.used = true
|
||||
}
|
||||
|
|
|
@ -296,7 +296,7 @@ func suitableMethods(typ reflect.Type, reportErr bool) map[string]*methodType {
|
|||
// Method needs three ins: receiver, *args, *reply.
|
||||
if mtype.NumIn() != 3 {
|
||||
if reportErr {
|
||||
log.Println("method", mname, "has wrong number of ins:", mtype.NumIn())
|
||||
log.Printf("rpc.Register: method %q has %d input parameters; needs exactly three\n", mname, mtype.NumIn())
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ func suitableMethods(typ reflect.Type, reportErr bool) map[string]*methodType {
|
|||
argType := mtype.In(1)
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
if reportErr {
|
||||
log.Println(mname, "argument type not exported:", argType)
|
||||
log.Printf("rpc.Register: argument type of method %q is not exported: %q\n", mname, argType)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
@ -312,28 +312,28 @@ func suitableMethods(typ reflect.Type, reportErr bool) map[string]*methodType {
|
|||
replyType := mtype.In(2)
|
||||
if replyType.Kind() != reflect.Ptr {
|
||||
if reportErr {
|
||||
log.Println("method", mname, "reply type not a pointer:", replyType)
|
||||
log.Printf("rpc.Register: reply type of method %q is not a pointer: %q\n", mname, replyType)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Reply type must be exported.
|
||||
if !isExportedOrBuiltinType(replyType) {
|
||||
if reportErr {
|
||||
log.Println("method", mname, "reply type not exported:", replyType)
|
||||
log.Printf("rpc.Register: reply type of method %q is not exported: %q\n", mname, replyType)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Method needs one out.
|
||||
if mtype.NumOut() != 1 {
|
||||
if reportErr {
|
||||
log.Println("method", mname, "has wrong number of outs:", mtype.NumOut())
|
||||
log.Printf("rpc.Register: method %q has %d output parameters; needs exactly one\n", mname, mtype.NumOut())
|
||||
}
|
||||
continue
|
||||
}
|
||||
// The return type of the method must be error.
|
||||
if returnType := mtype.Out(0); returnType != typeOfError {
|
||||
if reportErr {
|
||||
log.Println("method", mname, "returns", returnType.String(), "not error")
|
||||
log.Printf("rpc.Register: return type of method %q is %q, must be error\n", mname, returnType)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
package os
|
||||
|
||||
func isExist(err error) bool {
|
||||
return checkErrMessageContent(err, " exists")
|
||||
return checkErrMessageContent(err, "exists", "is a directory")
|
||||
}
|
||||
|
||||
func isNotExist(err error) bool {
|
||||
|
|
|
@ -24,7 +24,7 @@ var useSyscallwd = func(error) bool { return true }
|
|||
// reached via multiple paths (due to symbolic links),
|
||||
// Getwd may return any one of them.
|
||||
func Getwd() (dir string, err error) {
|
||||
if runtime.GOOS == "windows" {
|
||||
if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
|
||||
return syscall.Getwd()
|
||||
}
|
||||
|
||||
|
|
|
@ -632,3 +632,20 @@ retry:
|
|||
}
|
||||
t.Errorf("test ran %d times without producing expected output", tries)
|
||||
}
|
||||
|
||||
func TestBadTraceback(t *testing.T) {
|
||||
if runtime.Compiler == "gccgo" {
|
||||
t.Skip("gccgo does not do a hex dump")
|
||||
}
|
||||
output := runTestProg(t, "testprog", "BadTraceback")
|
||||
for _, want := range []string{
|
||||
"runtime: unexpected return pc",
|
||||
"called from 0xbad",
|
||||
"00000bad", // Smashed LR in hex dump
|
||||
"<main.badLR", // Symbolization in hex dump (badLR1 or badLR2)
|
||||
} {
|
||||
if !strings.Contains(output, want) {
|
||||
t.Errorf("output does not contain %q:\n%s", want, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,8 +138,7 @@ func typestring(x interface{}) string {
|
|||
return *e._type.string
|
||||
}
|
||||
|
||||
// For calling from C.
|
||||
// Prints an argument passed to panic.
|
||||
// printany prints an argument passed to panic.
|
||||
func printany(i interface{}) {
|
||||
switch v := i.(type) {
|
||||
case nil:
|
||||
|
|
|
@ -403,12 +403,15 @@ func preprintpanics(p *_panic) {
|
|||
}
|
||||
|
||||
// Print all currently active panics. Used when crashing.
|
||||
// Should only be called after preprintpanics.
|
||||
func printpanics(p *_panic) {
|
||||
if p.link != nil {
|
||||
printpanics(p.link)
|
||||
print("\t")
|
||||
}
|
||||
print("panic: ")
|
||||
// Because of preprintpanics, p.arg cannot be an error or
|
||||
// stringer, so this won't call into user code.
|
||||
printany(p.arg)
|
||||
if p.recovered {
|
||||
print(" [recovered]")
|
||||
|
@ -833,7 +836,7 @@ var panicking uint32
|
|||
// so that two concurrent panics don't overlap their output.
|
||||
var paniclk mutex
|
||||
|
||||
// startpanic_m implements unrecoverable panic.
|
||||
// startpanic_m prepares for an unrecoverable panic.
|
||||
//
|
||||
// It can have write barriers because the write barrier explicitly
|
||||
// ignores writes once dying > 0.
|
||||
|
@ -841,14 +844,14 @@ var paniclk mutex
|
|||
//go:yeswritebarrierrec
|
||||
func startpanic() {
|
||||
_g_ := getg()
|
||||
// Uncomment when mheap_ is in Go.
|
||||
// if mheap_.cachealloc.size == 0 { // very early
|
||||
// print("runtime: panic before malloc heap initialized\n")
|
||||
// _g_.m.mallocing = 1 // tell rest of panic not to try to malloc
|
||||
// } else
|
||||
if _g_.m.mcache == nil { // can happen if called from signal handler or throw
|
||||
_g_.m.mcache = allocmcache()
|
||||
if mheap_.cachealloc.size == 0 { // very early
|
||||
print("runtime: panic before malloc heap initialized\n")
|
||||
}
|
||||
// Disallow malloc during an unrecoverable panic. A panic
|
||||
// could happen in a signal handler, or in a throw, or inside
|
||||
// malloc itself. We want to catch if an allocation ever does
|
||||
// happen (even if we're not in one of these situations).
|
||||
_g_.m.mallocing++
|
||||
|
||||
switch _g_.m.dying {
|
||||
case 0:
|
||||
|
@ -934,6 +937,9 @@ func dopanic(unused int) {
|
|||
exit(2)
|
||||
}
|
||||
|
||||
// canpanic returns false if a signal should throw instead of
|
||||
// panicking.
|
||||
//
|
||||
//go:nosplit
|
||||
func canpanic(gp *g) bool {
|
||||
// Note that g is m->gsignal, different from gp.
|
||||
|
|
|
@ -350,7 +350,8 @@ type countProfile interface {
|
|||
// as the pprof-proto format output. Translations from cycle count to time duration
|
||||
// are done because The proto expects count and time (nanoseconds) instead of count
|
||||
// and the number of cycles for block, contention profiles.
|
||||
func printCountCycleProfile(w io.Writer, countName, cycleName string, records []runtime.BlockProfileRecord) error {
|
||||
// Possible 'scaler' functions are scaleBlockProfile and scaleMutexProfile.
|
||||
func printCountCycleProfile(w io.Writer, countName, cycleName string, scaler func(int64, float64) (int64, float64), records []runtime.BlockProfileRecord) error {
|
||||
// Output profile in protobuf form.
|
||||
b := newProfileBuilder(w)
|
||||
b.pbValueType(tagProfile_PeriodType, countName, "count")
|
||||
|
@ -363,8 +364,9 @@ func printCountCycleProfile(w io.Writer, countName, cycleName string, records []
|
|||
values := []int64{0, 0}
|
||||
var locs []uint64
|
||||
for _, r := range records {
|
||||
values[0] = int64(r.Count)
|
||||
values[1] = int64(float64(r.Cycles) / cpuGHz) // to nanoseconds
|
||||
count, nanosec := scaler(r.Count, float64(r.Cycles)/cpuGHz)
|
||||
values[0] = count
|
||||
values[1] = int64(nanosec)
|
||||
locs = locs[:0]
|
||||
for _, addr := range r.Stack() {
|
||||
// For count profiles, all stack addresses are
|
||||
|
@ -820,7 +822,7 @@ func writeBlock(w io.Writer, debug int) error {
|
|||
sort.Slice(p, func(i, j int) bool { return p[i].Cycles > p[j].Cycles })
|
||||
|
||||
if debug <= 0 {
|
||||
return printCountCycleProfile(w, "contentions", "delay", p)
|
||||
return printCountCycleProfile(w, "contentions", "delay", scaleBlockProfile, p)
|
||||
}
|
||||
|
||||
b := bufio.NewWriter(w)
|
||||
|
@ -847,6 +849,14 @@ func writeBlock(w io.Writer, debug int) error {
|
|||
return b.Flush()
|
||||
}
|
||||
|
||||
func scaleBlockProfile(cnt int64, ns float64) (int64, float64) {
|
||||
// Do nothing.
|
||||
// The current way of block profile sampling makes it
|
||||
// hard to compute the unsampled number. The legacy block
|
||||
// profile parse doesn't attempt to scale or unsample.
|
||||
return cnt, ns
|
||||
}
|
||||
|
||||
// writeMutex writes the current mutex profile to w.
|
||||
func writeMutex(w io.Writer, debug int) error {
|
||||
// TODO(pjw): too much common code with writeBlock. FIX!
|
||||
|
@ -864,7 +874,7 @@ func writeMutex(w io.Writer, debug int) error {
|
|||
sort.Slice(p, func(i, j int) bool { return p[i].Cycles > p[j].Cycles })
|
||||
|
||||
if debug <= 0 {
|
||||
return printCountCycleProfile(w, "contentions", "delay", p)
|
||||
return printCountCycleProfile(w, "contentions", "delay", scaleMutexProfile, p)
|
||||
}
|
||||
|
||||
b := bufio.NewWriter(w)
|
||||
|
@ -892,4 +902,9 @@ func writeMutex(w io.Writer, debug int) error {
|
|||
return b.Flush()
|
||||
}
|
||||
|
||||
func scaleMutexProfile(cnt int64, ns float64) (int64, float64) {
|
||||
period := runtime.SetMutexProfileFraction(-1)
|
||||
return cnt * int64(period), ns * float64(period)
|
||||
}
|
||||
|
||||
func runtime_cyclesPerSecond() int64
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
// This is a copy of sync/rwmutex.go rewritten to work in the runtime.
|
||||
|
||||
// An rwmutex is a reader/writer mutual exclusion lock.
|
||||
// A rwmutex is a reader/writer mutual exclusion lock.
|
||||
// The lock can be held by an arbitrary number of readers or a single writer.
|
||||
// This is a variant of sync.RWMutex, for the runtime package.
|
||||
// Like mutex, rwmutex blocks the calling M.
|
||||
|
|
|
@ -40,6 +40,11 @@ func sighandler(sig uint32, info *_siginfo_t, ctxt unsafe.Pointer, gp *g) {
|
|||
if sig < uint32(len(sigtable)) {
|
||||
flags = sigtable[sig].flags
|
||||
}
|
||||
if flags&_SigPanic != 0 && gp.throwsplit {
|
||||
// We can't safely sigpanic because it may grow the
|
||||
// stack. Abort in the signal handler instead.
|
||||
flags = (flags &^ _SigPanic) | _SigThrow
|
||||
}
|
||||
if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
|
||||
// Emulate gc by passing arguments out of band,
|
||||
// although we don't really have to.
|
||||
|
|
|
@ -320,6 +320,12 @@ func sigtrampgo(sig uint32, info *_siginfo_t, ctx unsafe.Pointer) {
|
|||
// the signal handler. The effect is that the program will act as
|
||||
// though the function that got the signal simply called sigpanic
|
||||
// instead.
|
||||
//
|
||||
// This must NOT be nosplit because the linker doesn't know where
|
||||
// sigpanic calls can be injected.
|
||||
//
|
||||
// The signal handler must not inject a call to sigpanic if
|
||||
// getg().throwsplit, since sigpanic may need to grow the stack.
|
||||
func sigpanic() {
|
||||
g := getg()
|
||||
if !canpanic(g) {
|
||||
|
|
|
@ -59,6 +59,7 @@ func (t *timer) assignBucket() *timersBucket {
|
|||
return t.tb
|
||||
}
|
||||
|
||||
//go:notinheap
|
||||
type timersBucket struct {
|
||||
lock mutex
|
||||
gp *g
|
||||
|
|
|
@ -13,11 +13,11 @@ import (
|
|||
// There is a modified copy of this file in runtime/rwmutex.go.
|
||||
// If you make any changes here, see if you should make them there.
|
||||
|
||||
// An RWMutex is a reader/writer mutual exclusion lock.
|
||||
// A RWMutex is a reader/writer mutual exclusion lock.
|
||||
// The lock can be held by an arbitrary number of readers or a single writer.
|
||||
// The zero value for a RWMutex is an unlocked mutex.
|
||||
//
|
||||
// An RWMutex must not be copied after first use.
|
||||
// A RWMutex must not be copied after first use.
|
||||
//
|
||||
// If a goroutine holds a RWMutex for reading and another goroutine might
|
||||
// call Lock, no goroutine should expect to be able to acquire a read lock
|
||||
|
@ -108,7 +108,7 @@ func (rw *RWMutex) Lock() {
|
|||
// not locked for writing on entry to Unlock.
|
||||
//
|
||||
// As with Mutexes, a locked RWMutex is not associated with a particular
|
||||
// goroutine. One goroutine may RLock (Lock) an RWMutex and then
|
||||
// goroutine. One goroutine may RLock (Lock) a RWMutex and then
|
||||
// arrange for another goroutine to RUnlock (Unlock) it.
|
||||
func (rw *RWMutex) Unlock() {
|
||||
if race.Enabled {
|
||||
|
|
|
@ -349,6 +349,14 @@ var ptrTests = []ptrTest{
|
|||
body: `var wg sync.WaitGroup; wg.Add(100); for i := 0; i < 100; i++ { go func(i int) { for j := 0; j < 100; j++ { C.f(); runtime.GOMAXPROCS(i) }; wg.Done() }(i) }; wg.Wait()`,
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
// Test poller deadline with cgocheck=2. Issue #23435.
|
||||
name: "deadline",
|
||||
c: `#define US 10`,
|
||||
imports: []string{"os", "time"},
|
||||
body: `r, _, _ := os.Pipe(); r.SetDeadline(time.Now().Add(C.US * time.Microsecond))`,
|
||||
fail: false,
|
||||
},
|
||||
}
|
||||
|
||||
func TestPointerChecks(t *testing.T) {
|
||||
|
|
|
@ -695,3 +695,50 @@ func TestCompileWithoutShared(t *testing.T) {
|
|||
t.Logf("%s", out)
|
||||
expectSignal(t, err, syscall.SIGPIPE)
|
||||
}
|
||||
|
||||
// Test that installing a second time recreates the header files.
|
||||
func TestCachedInstall(t *testing.T) {
|
||||
defer os.RemoveAll("pkg")
|
||||
|
||||
h1 := filepath.Join("pkg", libgodir, "libgo.h")
|
||||
h2 := filepath.Join("pkg", libgodir, "p.h")
|
||||
|
||||
buildcmd := []string{"go", "install", "-i", "-buildmode=c-archive", "libgo"}
|
||||
|
||||
cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
|
||||
cmd.Env = gopathEnv
|
||||
t.Log(buildcmd)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(h1); err != nil {
|
||||
t.Errorf("libgo.h not installed: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(h2); err != nil {
|
||||
t.Errorf("p.h not installed: %v", err)
|
||||
}
|
||||
|
||||
if err := os.Remove(h1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Remove(h2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cmd = exec.Command(buildcmd[0], buildcmd[1:]...)
|
||||
cmd.Env = gopathEnv
|
||||
t.Log(buildcmd)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(h1); err != nil {
|
||||
t.Errorf("libgo.h not installed in second run: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(h2); err != nil {
|
||||
t.Errorf("p.h not installed in second run: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ package cshared_test
|
|||
import (
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
@ -55,7 +56,8 @@ func TestMain(m *testing.M) {
|
|||
|
||||
androiddir = fmt.Sprintf("/data/local/tmp/testcshared-%d", os.Getpid())
|
||||
if GOOS == "android" {
|
||||
cmd := exec.Command("adb", "shell", "mkdir", "-p", androiddir)
|
||||
args := append(adbCmd(), "shell", "mkdir", "-p", androiddir)
|
||||
cmd := exec.Command(args[0], args[1:]...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Fatalf("setupAndroid failed: %v\n%s\n", err, out)
|
||||
|
@ -154,11 +156,19 @@ func cmdToRun(name string) string {
|
|||
return "./" + name + exeSuffix
|
||||
}
|
||||
|
||||
func adbCmd() []string {
|
||||
cmd := []string{"adb"}
|
||||
if flags := os.Getenv("GOANDROID_ADB_FLAGS"); flags != "" {
|
||||
cmd = append(cmd, strings.Split(flags, " ")...)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func adbPush(t *testing.T, filename string) {
|
||||
if GOOS != "android" {
|
||||
return
|
||||
}
|
||||
args := []string{"adb", "push", filename, fmt.Sprintf("%s/%s", androiddir, filename)}
|
||||
args := append(adbCmd(), "push", filename, fmt.Sprintf("%s/%s", androiddir, filename))
|
||||
cmd := exec.Command(args[0], args[1:]...)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Fatalf("adb command failed: %v\n%s\n", err, out)
|
||||
|
@ -169,7 +179,7 @@ func adbRun(t *testing.T, env []string, adbargs ...string) string {
|
|||
if GOOS != "android" {
|
||||
t.Fatalf("trying to run adb command when operating system is not android.")
|
||||
}
|
||||
args := []string{"adb", "shell"}
|
||||
args := append(adbCmd(), "shell")
|
||||
// Propagate LD_LIBRARY_PATH to the adb shell invocation.
|
||||
for _, e := range env {
|
||||
if strings.Index(e, "LD_LIBRARY_PATH=") != -1 {
|
||||
|
@ -237,7 +247,7 @@ func createHeaders() error {
|
|||
}
|
||||
|
||||
if GOOS == "android" {
|
||||
args = []string{"adb", "push", libgoname, fmt.Sprintf("%s/%s", androiddir, libgoname)}
|
||||
args = append(adbCmd(), "push", libgoname, fmt.Sprintf("%s/%s", androiddir, libgoname))
|
||||
cmd = exec.Command(args[0], args[1:]...)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
|
@ -270,7 +280,8 @@ func cleanupAndroid() {
|
|||
if GOOS != "android" {
|
||||
return
|
||||
}
|
||||
cmd := exec.Command("adb", "shell", "rm", "-rf", androiddir)
|
||||
args := append(adbCmd(), "shell", "rm", "-rf", androiddir)
|
||||
cmd := exec.Command(args[0], args[1:]...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Fatalf("cleanupAndroid failed: %v\n%s\n", err, out)
|
||||
|
@ -477,3 +488,99 @@ func TestPIE(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that installing a second time recreates the header files.
|
||||
func TestCachedInstall(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "cshared")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// defer os.RemoveAll(tmpdir)
|
||||
|
||||
copyFile(t, filepath.Join(tmpdir, "src", "libgo", "libgo.go"), filepath.Join("src", "libgo", "libgo.go"))
|
||||
copyFile(t, filepath.Join(tmpdir, "src", "p", "p.go"), filepath.Join("src", "p", "p.go"))
|
||||
|
||||
env := append(os.Environ(), "GOPATH="+tmpdir)
|
||||
|
||||
buildcmd := []string{"go", "install", "-x", "-i", "-buildmode=c-shared", "-installsuffix", "testcshared", "libgo"}
|
||||
|
||||
cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
|
||||
cmd.Env = env
|
||||
t.Log(buildcmd)
|
||||
out, err := cmd.CombinedOutput()
|
||||
t.Logf("%s", out)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var libgoh, ph string
|
||||
|
||||
walker := func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var ps *string
|
||||
switch filepath.Base(path) {
|
||||
case "libgo.h":
|
||||
ps = &libgoh
|
||||
case "p.h":
|
||||
ps = &ph
|
||||
}
|
||||
if ps != nil {
|
||||
if *ps != "" {
|
||||
t.Fatalf("%s found again", *ps)
|
||||
}
|
||||
*ps = path
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := filepath.Walk(tmpdir, walker); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if libgoh == "" {
|
||||
t.Fatal("libgo.h not installed")
|
||||
}
|
||||
if ph == "" {
|
||||
t.Fatal("p.h not installed")
|
||||
}
|
||||
|
||||
if err := os.Remove(libgoh); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Remove(ph); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cmd = exec.Command(buildcmd[0], buildcmd[1:]...)
|
||||
cmd.Env = env
|
||||
t.Log(buildcmd)
|
||||
out, err = cmd.CombinedOutput()
|
||||
t.Logf("%s", out)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(libgoh); err != nil {
|
||||
t.Errorf("libgo.h not installed in second run: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(ph); err != nil {
|
||||
t.Errorf("p.h not installed in second run: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// copyFile copies src to dst.
|
||||
func copyFile(t *testing.T, dst, src string) {
|
||||
t.Helper()
|
||||
data, err := ioutil.ReadFile(src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(dst, data, 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -351,10 +351,10 @@ func readNotes(f *elf.File) ([]*note, error) {
|
|||
|
||||
func dynStrings(t *testing.T, path string, flag elf.DynTag) []string {
|
||||
f, err := elf.Open(path)
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("elf.Open(%q) failed: %v", path, err)
|
||||
}
|
||||
defer f.Close()
|
||||
dynstrings, err := f.DynString(flag)
|
||||
if err != nil {
|
||||
t.Fatalf("DynString(%s) failed on %s: %v", flag, path, err)
|
||||
|
@ -598,7 +598,6 @@ func TestThreeGopathShlibs(t *testing.T) {
|
|||
// If gccgo is not available or not new enough call t.Skip. Otherwise,
|
||||
// return a build.Context that is set up for gccgo.
|
||||
func prepGccgo(t *testing.T) build.Context {
|
||||
t.Skip("golang.org/issue/22472")
|
||||
gccgoName := os.Getenv("GCCGO")
|
||||
if gccgoName == "" {
|
||||
gccgoName = "gccgo"
|
||||
|
@ -648,8 +647,6 @@ func TestGoPathShlibGccgo(t *testing.T) {
|
|||
// library with gccgo, another GOPATH package that depends on the first and an
|
||||
// executable that links the second library.
|
||||
func TestTwoGopathShlibsGccgo(t *testing.T) {
|
||||
t.Skip("golang.org/issue/22224")
|
||||
|
||||
gccgoContext := prepGccgo(t)
|
||||
|
||||
libgoRE := regexp.MustCompile("libgo.so.[0-9]+")
|
||||
|
|
Loading…
Add table
Reference in a new issue