[dev.link] all: merge branch 'master' into dev.link

Bring in Than's fix of #35779.

The only merge conflict is cmd/link/internal/loadelf/ldelf.go,
with a modification-deletion conflict.

Change-Id: Id2fcfd2094a31120966a6ea9c462b4ec76646b10
This commit is contained in:
Cherry Zhang 2019-12-03 10:38:43 -05:00
commit f7672d39ca
200 changed files with 3558 additions and 2028 deletions

View file

@ -171,6 +171,16 @@ TODO
TODO
</p>
<p><!-- CL 171844 and many others -->
Internal timers, used by
<a href="/pkg/time/#After"><code>time.After</code></a>,
<a href="/pkg/time/#Tick"><code>time.Tick</code></a>,
<a href="/pkg/net/#Conn"><code>net.Conn.SetDeadline</code></a>,
and friends, are more efficient, with less lock contention and fewer
context switches.
This is a performance improvement that should not cause any user
visible changes.
</p>
<h2 id="library">Core library</h2>

View file

@ -5,57 +5,551 @@
}-->
<!-- TODO(jayconrod): ensure golang.org/x/website can render Markdown or convert
this document to HTML before Go 1.14. -->
<!-- TODO(jayconrod): ensure Markdown renderer adds anchors or add them
manually. -->
<!-- TODO(jayconrod): ensure anchors work correctly after Markdown rendering -->
<a id="introduction"></a>
## Introduction
## Glossary
<a id="modules-overview"></a>
## Modules, packages, and versions
## Packages, modules, and versions
A [*module*](#glos-module) is a collection of packages that are released,
versioned, and distributed together. A module is identified by a [*module
path*](#glos-module-path), which is declared in a [`go.mod`
file](#go.mod-files), together with information about the module's
dependencies. The [*module root directory*](#glos-module-root-directory) is the
directory that contains the `go.mod` file. The [*main
module*](#glos-main-module) is the module containing the directory where the
`go` command is invoked.
## go.mod files
Each [*package*](#glos-package) within a module is a collection of source files
in the same directory that are compiled together. A [*package
path*](#glos-package-path) is the module path joined with the subdirectory
containing the package (relative to the module root). For example, the module
`"golang.org/x/net"` contains a package in the directory `"html"`. That
package's path is `"golang.org/x/net/html"`.
### go.mod file format
<a id="versions"></a>
### Versions
A [*version*](#glos-version) identifies an immutable snapshot of a module, which
may be either a [release](#glos-release-version) or a
[pre-release](#glos-pre-release-version). Each version starts with the letter
`v`, followed by a semantic version. See [Semantic Versioning
2.0.0](https://semver.org/spec/v2.0.0.html) for details on how versions are
formatted, interpreted, and compared.
To summarize, a semantic version consists of three non-negative integers (the
major, minor, and patch versions, from left to right) separated by dots. The
patch version may be followed by an optional pre-release string starting with a
hyphen. The pre-release string or patch version may be followed by a build
metadata string starting with a plus. For example, `v0.0.0`, `v1.12.134`,
`v8.0.5-pre`, and `v2.0.9+meta` are valid versions.
Each part of a version indicates whether the version is stable and whether it is
compatible with previous versions.
* The [major version](#glos-major-version) must be incremented and the minor
and patch versions must be set to zero after a backwards incompatible change
is made to the module's public interface or documented functionality, for
example, after a package is removed.
* The [minor version](#glos-minor-version) must be incremented and the patch
version set to zero after a backwards compatible change, for example, after a
new function is added.
* The [patch version](#glos-patch-version) must be incremented after a change
that does not affect the module's public interface, such as a bug fix or
optimization.
* The pre-release suffix indicates a version is a
[pre-release](#glos-pre-release-version). Pre-release versions sort before
the corresponding release versions. For example, `v1.2.3-pre` comes before
`v1.2.3`.
* The build metadata suffix is ignored for the purpose of comparing versions.
Tags with build metadata are ignored in version control repositories, but
build metadata is preserved in versions specified in `go.mod` files. The
suffix `+incompatible` denotes a version released before migrating to modules
version major version 2 or later (see [Compatibility with non-module
repositories](#non-module-compat).
A version is considered unstable if its major version is 0 or it has a
pre-release suffix. Unstable versions are not subject to compatibility
requirements. For example, `v0.2.0` may not be compatible with `v0.1.0`, and
`v1.5.0-beta` may not be compatible with `v1.5.0`.
Go may access modules in version control systems using tags, branches, or
revisions that don't follow these conventions. However, within the main module,
the `go` command will automatically convert revision names that don't follow
this standard into canonical versions. The `go` command will also remove build
metadata suffixes (except for `+incompatible`) as part of this process. This may
result in a [*pseudo-version*](#glos-pseudo-version), a pre-release version that
encodes a revision identifier (such as a Git commit hash) and a timestamp from a
version control system. For example, the command `go get -d
golang.org/x/net@daa7c041` will convert the commit hash `daa7c041` into the
pseudo-version `v0.0.0-20191109021931-daa7c04131f5`. Canonical versions are
required outside the main module, and the `go` command will report an error if a
non-canonical version like `master` appears in a `go.mod` file.
<a id="major-version-suffixes"></a>
### Major version suffixes
Starting with major version 2, module paths must have a [*major version
suffix*](#glos-major-version-suffix) like `/v2` that matches the major
version. For example, if a module has the path `example.com/mod` at `v1.0.0`, it
must have the path `example.com/mod/v2` at version `v2.0.0`.
Major version suffixes implement the [*import compatibility
rule*](https://research.swtch.com/vgo-import):
> If an old package and a new package have the same import path,
> the new package must be backwards compatible with the old package.
By definition, packages in a new major version of a module are not backwards
compatible with the corresponding packages in the previous major version.
Consequently, starting with `v2`, packages need new import paths. This is
accomplished by adding a major version suffix to the module path. Since the
module path is a prefix of the import path for each package within the module,
adding the major version suffix to the module path provides a distinct import
path for each incompatible version.
Major version suffixes are not allowed at major versions `v0` or `v1`. There is
no need to change the module path between `v0` and `v1` because `v0` versions
are unstable and have no compatibility guarantee. Additionally, for most
modules, `v1` is backwards compatible with the last `v0` version; a `v1` version
acts as a commitment to compatibility, rather than an indication of
incompatible changes compared with `v0`.
As a special case, modules paths starting with `gopkg.in/` must always have a
major version suffix, even at `v0` and `v1`. The suffix must start with a dot
rather than a slash (for example, `gopkg.in/yaml.v2`).
Major version suffixes let multiple major versions of a module coexist in the
same build. This may be necessary due to a [diamond dependency
problem](https://research.swtch.com/vgo-import#dependency_story). Ordinarily, if
a module is required at two different versions by transitive dependencies, the
higher version will be used. However, if the two versions are incompatible,
neither version will satisfy all clients. Since incompatible versions must have
different major version numbers, they must also have different module paths due
to major version suffixes. This resolves the conflict: modules with distinct
suffixes are treated as separate modules, and their packages—even packages in
same subdirectory relative to their module roots—are distinct.
Many Go projects released versions at `v2` or higher without using a major
version suffix before migrating to modules (perhaps before modules were even
introduced). These versions are annotated with a `+incompatible` build tag (for
example, `v2.0.0+incompatible`). See [Compatibility with non-module
repositories](#compatibility-with-non-module-repositories) for more information.
<a id="resolve-pkg-mod"></a>
### Resolving a package to a module
When the `go` command loads a package using a [package
path](#glos-package-path), it needs to determine which module provides the
package.
The `go` command starts by searching the [build list](#glos-build-list) for
modules with paths that are prefixes of the package path. For example, if the
package `example.com/a/b` is imported, and the module `example.com/a` is in the
build list, the `go` command will check whether `example.com/a` contains the
package, in the directory `b`. At least one file with the `.go` extension must
be present in a directory for it to be considered a package. [Build
constraints](/pkg/go/build/#hdr-Build_Constraints) are not applied for this
purpose. If exactly one module in the build list provides the package, that
module is used. If two or more modules provide the package, an error is
reported. If no modules provide the package, the `go` command will attempt to
find a new module (unless the flags `-mod=readonly` or `-mod=vendor` are used,
in which case, an error is reported).
<!-- NOTE(golang.org/issue/27899): the go command reports an error when two
or more modules provide a package with the same path as above. In the future,
we may try to upgrade one (or all) of the colliding modules.
-->
When the `go` command looks up a new module for a package path, it checks the
`GOPROXY` environment variable, which is a comma-separated list of proxy URLs or
the keywords `direct` or `off`. A proxy URL indicates the `go` command should
contact a [module proxy](#glos-module-proxy) using the [`GOPROXY`
protocol](#goproxy-protocol). `direct` indicates that the `go` command should
[communicate with a version control system](#communicating-with-vcs). `off`
indicates that no communication should be attempted. The `GOPRIVATE` and
`GONOPROXY` [environment variables](#environment-variables) can also be used to
control this behavior.
For each entry in the `GOPROXY` list, the `go` command requests the latest
version of each module path that might provide the package (that is, each prefix
of the package path). For each successfully requested module path, the `go`
command will download the module at the latest version and check whether the
module contains the requested package. If one or more modules contain the
requested package, the module with the longest path is used. If one or more
modules are found but none contain the requested package, an error is
reported. If no modules are found, the `go` command tries the next entry in the
`GOPROXY` list. If no entries are left, an error is reported.
For example, suppose the `go` command is looking for a module that provides the
package `golang.org/x/net/html`, and `GOPROXY` is set to
`https://corp.example.com,https://proxy.golang.org`. The `go` command may make
the following requests:
* To `https://corp.example.com/` (in parallel):
* Request for latest version of `golang.org/x/net/html`
* Request for latest version of `golang.org/x/net`
* Request for latest version of `golang.org/x`
* Request for latest version of `golang.org`
* To `https://proxy.golang.org/`, if all requests to `https://corp.example.com/`
have failed with 404 or 410:
* Request for latest version of `golang.org/x/net/html`
* Request for latest version of `golang.org/x/net`
* Request for latest version of `golang.org/x`
* Request for latest version of `golang.org`
After a suitable module has been found, the `go` command will add a new
requirement with the new module's path and version to the main module's `go.mod`
file. This ensures that when the same package is loaded in the future, the same
module will be used at the same version. If the resolved package is not imported
by a package in the main module, the new requirement will have an `// indirect`
comment.
<a id="go.mod-files"></a>
## `go.mod` files
<a id="go.mod-file-format"></a>
### `go.mod` file format
<a id="minimal-version-selection"></a>
### Minimal version selection (MVS)
<a id="non-module-compat"></a>
### Compatibility with non-module repositories
<a id="mod-commands"></a>
## Module-aware build commands
<a id="enabling"></a>
### Enabling modules
<a id="initializing"></a>
### Initializing modules
<a id="build-commands"></a>
### Build commands
<a id="vendoring"></a>
### Vendoring
<a id="go-mod-download"></a>
### `go mod download`
<a id="go-mod-verify"></a>
### `go mod verify`
<a id="go-mod-edit"></a>
### `go mod edit`
<a id="go-clean-modcache"></a>
### `go clean -modcache`
<a id="commands-outside"></a>
### Module commands outside a module
<a id="retrieving-modules"></a>
## Retrieving modules
### GOPROXY protocol
<a id="goproxy-protocol"></a>
### `GOPROXY` protocol
### Module zip requirements
A [*module proxy*](#glos-module-proxy) is an HTTP server that can respond to
`GET` requests for paths specified below. The requests have no query parameters,
and no specific headers are required, so even a site serving from a fixed file
system (including a `file://` URL) can be a module proxy.
### Privacy
Successful HTTP responses must have the status code 200 (OK). Redirects (3xx)
are followed. Responses with status codes 4xx and 5xx are treated as errors.
The error codes 404 (Not Found) and 410 (Gone) indicate that the
requested module or version is not available on the proxy, but it may be found
elsewhere. Error responses should have content type `text/plain` with
`charset` either `utf-8` or `us-ascii`.
The `go` command may be configured to contact proxies or source control servers
using the `GOPROXY` environment variable, which is a comma-separated list of
URLs or the keywords `direct` or `off` (see [Environment
variables](#environment-variables) for details). When the `go` command receives
a 404 or 410 response from a proxy, it falls back to later proxies in the
list. The `go` command does not fall back to later proxies in response to other
4xx and 5xx errors. This allows a proxy to act as a gatekeeper, for example, by
responding with error 403 (Forbidden) for modules not on an approved list.
The table below specifies queries that a module proxy must respond to. For each
path, `$base` is the path portion of a proxy URL,`$module` is a module path, and
`$version` is a version. For example, if the proxy URL is
`https://example.com/mod`, and the client is requesting the `go.mod` file for
the module `golang.org/x/text` at version `v0.3.2`, the client would send a
`GET` request for `https://example.com/mod/golang.org/x/text/@v/v0.3.2.mod`.
To avoid ambiguity when serving from case-insensitive file systems,
the `$module` and `$version` elements are case-encoded by replacing every
uppercase letter with an exclamation mark followed by the corresponding
lower-case letter. This allows modules `example.com/M` and `example.com/m` to
both be stored on disk, since the former is encoded as `example.com/!m`.
<!-- TODO(jayconrod): This table has multi-line cells, and GitHub Flavored
Markdown doesn't have syntax for that, so we use raw HTML. Gitiles doesn't
include this table in the rendered HTML. Once x/website has a Markdown renderer,
ensure this table is readable. If the cells are too large, and it's difficult
to scan, use paragraphs or sections below.
-->
<table>
<thead>
<tr>
<th>Path</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>$base/$module/@v/list</code></td>
<td>
Returns a list of known versions of the given module in plain text, one
per line. This list should not include pseudo-versions.
</td>
</tr>
<tr>
<td><code>$base/$module/@v/$version.info</code></td>
<td>
<p>
Returns JSON-formatted metadata about a specific version of a module.
The response must be a JSON object that corresponds to the Go data
structure below:
</p>
<pre>
type Info struct {
Version string // version string
Time time.Time // commit time
}
</pre>
<p>
The <code>Version</code> field is required and must contain a valid,
<a href="#glos-canonical-version">canonical version</a> (see
<a href="#versions">Versions</a>). The <code>$version</code> in the
request path does not need to be the same version or even a valid
version; this endpoint may be used to find versions for branch names
or revision identifiers. However, if <code>$version</code> is a
canonical version with a major version compatible with
<code>$module</code>, the <code>Version</code> field in a successful
response must be the same.
</p>
<p>
The <code>Time</code> field is optional. If present, it must be a
string in RFC 3339 format. It indicates the time when the version
was created.
</p>
<p>
More fields may be added in the future, so other names are reserved.
</p>
</td>
</tr>
<tr>
<td><code>$base/$module/@v/$version.mod</code></td>
<td>
Returns the <code>go.mod</code> file for a specific version of a
module. If the module does not have a <code>go.mod</code> file at the
requested version, a file containing only a <code>module</code>
statement with the requested module path must be returned. Otherwise,
the original, unmodified <code>go.mod</code> file must be returned.
</td>
</tr>
<tr>
<td><code>$base/$module/@v/$version.zip</code></td>
<td>
Returns a zip file containing the contents of a specific version of
a module. See <a href="#zip-format">Module zip format</a> for details
on how this zip file must be formatted.
</td>
</tr>
<tr>
<td><code>$base/$module/@latest</code></td>
<td>
Returns JSON-formatted metadata about the latest known version of a
module in the same format as
<code>$base/$module/@v/$version.info</code>. The latest version should
be the version of the module that the <code>go</code> command should use
if <code>$base/$module/@v/list</code> is empty or no listed version is
suitable. This endpoint is optional, and module proxies are not required
to implement it.
</td>
</tr>
</tbody>
</table>
When resolving the latest version of a module, the `go` command will request
`$base/$module/@v/list`, then, if no suitable versions are found,
`$base/$module/@latest`. The `go` command prefers, in order: the semantically
highest release version, the semantically highest pre-release version, and the
chronologically most recent pseudo-version. In Go 1.12 and earlier, the `go`
command considered pseudo-versions in `$base/$module/@v/list` to be pre-release
versions, but this is no longer true since Go 1.13.
A module proxy must always serve the same content for successful
responses for `$base/$module/$version.mod` and `$base/$module/$version.zip`
queries. This content is [cryptographically authenticated](#authenticating)
using [`go.sum` files](#go.sum-file-format) and, by default, the
[checksum database](#checksum-database).
The `go` command caches most content it downloads from module proxies in its
module cache in `$GOPATH/pkg/mod/cache/download`. Even when downloading directly
from version control systems, the `go` command synthesizes explicit `info`,
`mod`, and `zip` files and stores them in this directory, the same as if it had
downloaded them directly from a proxy. The cache layout is the same as the proxy
URL space, so serving `$GOPATH/pkg/mod/cache/download` at (or copying it to)
`https://example.com/proxy` would let users access cached module versions by
setting `GOPROXY` to `https://example.com/proxy`.
<a id="communicating-with-proxies"></a>
### Communicating with proxies
<a id="communicating-with-vcs"></a>
### Communicating with version control systems
<a id="custom-import-paths"></a>
### Custom import paths
<!-- TODO(jayconrod): custom import paths, details of direct mode -->
<a id="path-constraints"></a>
### File name and path constraints
<a id="zip-format"></a>
### Module zip format
<a id="private-modules"></a>
### Private modules
<a id="authenticating"></a>
## Authenticating modules
<a id="go.sum-file-format"></a>
### go.sum file format
<a id="checksum-database"></a>
### Checksum database
### Privacy
<a id="privacy"></a>
## Privacy
<a id="environment-variables"></a>
## Environment variables
<a id="glossary">
## Glossary
<a id="glos-build-list"></a>
**build list:** The list of module versions that will be used for a build
command such as `go build`, `go list`, or `go test`. The build list is
determined from the [main module's](#glos-main-module) [`go.mod`
file](#glos-go.mod-file) and `go.mod` files in transitively required modules
using [minimal version selection](#glos-minimal-version-selection). The build
list contains versions for all modules in the [module
graph](#glos-module-graph), not just those relevant to a specific command.
<a id="glos-canonical-version">
**canonical version:** A correctly formatted [version](#glos-version) without
a build metadata suffix other than `+incompatible`. For example, `v1.2.3`
is a canonical version, but `v1.2.3+meta` is not.
<a id="glos-go.mod-file"></a>
**`go.mod` file:** The file that defines a module's path, requirements, and
other metadata. Appears in the [module's root
directory](#glos-module-root-directory). See the section on [`go.mod`
files](#go.mod-files).
<a id="glos-import-path"></a>
**import path:** A string used to import a package in a Go source file.
Synonymous with [package path](#glos-package-path).
<a id="glos-main-module"></a>
**main module:** The module in which the `go` command is invoked.
<a id="glos-major-version"></a>
**major version:** The first number in a semantic version (`1` in `v1.2.3`). In
a release with incompatible changes, the major version must be incremented, and
the minor and patch versions must be set to 0. Semantic versions with major
version 0 are considered unstable.
<a id="glos-major-version-suffix"></a>
**major version suffix:** A module path suffix that matches the major version
number. For example, `/v2` in `example.com/mod/v2`. Major version suffixes are
required at `v2.0.0` and later and are not allowed at earlier versions. See
the section on [Major version suffixes](#major-version-suffixes).
<a id="glos-minimal-version-selection"></a>
**minimal version selection (MVS):** The algorithm used to determine the
versions of all modules that will be used in a build. See the section on
[Minimal version selection](#minimal-version-selection) for details.
<a id="glos-minor-version"></a>
**minor version:** The second number in a semantic version (`2` in `v1.2.3`). In
a release with new, backwards compatible functionality, the minor version must
be incremented, and the patch version must be set to 0.
<a id="glos-module"></a>
**module:** A collection of packages that are released, versioned, and
distributed together.
<a id="glos-module-graph"></a>
**module graph:** The directed graph of module requirements, rooted at the [main
module](#glos-main-module). Each vertex in the graph is a module; each edge is a
version from a `require` statement in a `go.mod` file (subject to `replace` and
`exclude` statements in the main module's `go.mod` file.
<a id="glos-module-path"></a>
**module path:** A path that identifies a module and acts as a prefix for
package import paths within the module. For example, `"golang.org/x/net"`.
<a id="glos-module-proxy"></a>
**module proxy:** A web server that implements the [`GOPROXY`
protocol](#goproxy-protocol). The `go` command downloads version information,
`go.mod` files, and module zip files from module proxies.
<a id="glos-module-root-directory"></a>
**module root directory:** The directory that contains the `go.mod` file that
defines a module.
<a id="glos-package"></a>
**package:** A collection of source files in the same directory that are
compiled together. See the [Packages section](/ref/spec#Packages) in the Go
Language Specification.
<a id="glos-package-path"></a>
**package path:** The path that uniquely identifies a package. A package path is
a [module path](#glos-module-path) joined with a subdirectory within the module.
For example `"golang.org/x/net/html"` is the package path for the package in the
module `"golang.org/x/net"` in the `"html"` subdirectory. Synonym of
[import path](#glos-import-path).
<a id="glos-patch-version"></a>
**patch version:** The third number in a semantic version (`3` in `v1.2.3`). In
a release with no changes to the module's public interface, the patch version
must be incremented.
<a id="glos-pre-release-version"></a>
**pre-release version:** A version with a dash followed by a series of
dot-separated identifiers immediately following the patch version, for example,
`v1.2.3-beta4`. Pre-release versions are considered unstable and are not
assumed to be compatible with other versions. A pre-release version sorts before
the corresponding release version: `v1.2.3-pre` comes before `v1.2.3`. See also
[release version](#glos-release-version).
<a id="glos-pseudo-version"></a>
**pseudo-version:** A version that encodes a revision identifier (such as a Git
commit hash) and a timestamp from a version control system. For example,
`v0.0.0-20191109021931-daa7c04131f5`. Used for [compatibility with non-module
repositories](#non-module-compat) and in other situations when a tagged
version is not available.
<a id="glos-release-version"></a>
**release version:** A version without a pre-release suffix. For example,
`v1.2.3`, not `v1.2.3-pre`. See also [pre-release
version](#glos-pre-release-version).
<a id="glos-version"></a>
**version:** An identifier for an immutable snapshot of a module, written as the
letter `v` followed by a semantic version. See the section on
[Versions](#versions).

View file

@ -8,8 +8,8 @@
# Consult https://www.iana.org/time-zones for the latest versions.
# Versions to use.
CODE=2019b
DATA=2019b
CODE=2019c
DATA=2019c
set -e
rm -rf work

Binary file not shown.

View file

@ -28,7 +28,7 @@ case "$FC" in
;;
esac
if ! $FC helloworld/helloworld.f90 -o main.exe >& /dev/null; then
if ! $FC helloworld/helloworld.f90 -o /dev/null >& /dev/null; then
echo "skipping Fortran test: could not build helloworld.f90 with $FC"
exit 0
fi

View file

@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
symBase, err := filepath.Rel(srcRoot, dstRoot)
srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
symBase, err = filepath.Abs(srcRoot)
if err != nil {
return err
}
return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
return os.Mkdir(dstPath, perm|0200)
return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}

View file

@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
symBase, err := filepath.Rel(srcRoot, dstRoot)
srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
symBase, err = filepath.Abs(srcRoot)
if err != nil {
return err
}
return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
return os.Mkdir(dstPath, perm|0200)
return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}

View file

@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
symBase, err := filepath.Rel(srcRoot, dstRoot)
srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
symBase, err = filepath.Abs(srcRoot)
if err != nil {
return err
}
return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
return os.Mkdir(dstPath, perm|0200)
return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}

View file

@ -36,14 +36,21 @@ thread(void *p)
import "C"
import (
"fmt"
"os"
"path/filepath"
"time"
)
func main() {
start := time.Now()
// ensure that we can function normally
var v [][]byte
for i := 0; i < 1000; i++ {
time.Sleep(10 * time.Microsecond)
v = append(v, make([]byte, 64<<10))
}
fmt.Printf("ok\t%s\t%s\n", filepath.Base(os.Args[0]), time.Since(start).Round(time.Millisecond))
}

View file

@ -36,7 +36,10 @@ var exeSuffix string
var GOOS, GOARCH, GOPATH string
var libgodir string
var testWork bool // If true, preserve temporary directories.
func TestMain(m *testing.M) {
flag.BoolVar(&testWork, "testwork", false, "if true, log and preserve the test's temporary working directory")
flag.Parse()
if testing.Short() && os.Getenv("GO_BUILDER_NAME") == "" {
fmt.Printf("SKIP - short mode and $GO_BUILDER_NAME not set\n")
@ -54,7 +57,11 @@ func testMain(m *testing.M) int {
if err != nil {
log.Panic(err)
}
defer os.RemoveAll(GOPATH)
if testWork {
log.Println(GOPATH)
} else {
defer os.RemoveAll(GOPATH)
}
os.Setenv("GOPATH", GOPATH)
// Copy testdata into GOPATH/src/testarchive, along with a go.mod file
@ -164,6 +171,38 @@ func cmdToRun(name string) []string {
return []string{executor, name}
}
// genHeader writes a C header file for the C-exported declarations found in .go
// source files in dir.
//
// TODO(golang.org/issue/35715): This should be simpler.
func genHeader(t *testing.T, header, dir string) {
t.Helper()
// The 'cgo' command generates a number of additional artifacts,
// but we're only interested in the header.
// Shunt the rest of the outputs to a temporary directory.
objDir, err := ioutil.TempDir(GOPATH, "_obj")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(objDir)
files, err := filepath.Glob(filepath.Join(dir, "*.go"))
if err != nil {
t.Fatal(err)
}
cmd := exec.Command("go", "tool", "cgo",
"-objdir", objDir,
"-exportheader", header)
cmd.Args = append(cmd.Args, files...)
t.Log(cmd.Args)
if out, err := cmd.CombinedOutput(); err != nil {
t.Logf("%s", out)
t.Fatal(err)
}
}
func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
t.Helper()
cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
@ -172,10 +211,12 @@ func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
t.Logf("%s", out)
t.Fatal(err)
}
defer func() {
os.Remove(libgoa)
os.Remove(libgoh)
}()
if !testWork {
defer func() {
os.Remove(libgoa)
os.Remove(libgoh)
}()
}
ccArgs := append(cc, "-o", exe, "main.c")
if GOOS == "windows" {
@ -191,7 +232,9 @@ func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
t.Logf("%s", out)
t.Fatal(err)
}
defer os.Remove(exe)
if !testWork {
defer os.Remove(exe)
}
binArgs := append(cmdToRun(exe), "arg1", "arg2")
cmd = exec.Command(binArgs[0], binArgs[1:]...)
@ -227,17 +270,27 @@ func checkLineComments(t *testing.T, hdrname string) {
}
func TestInstall(t *testing.T) {
defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
if !testWork {
defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}
libgoa := "libgo.a"
if runtime.Compiler == "gccgo" {
libgoa = "liblibgo.a"
}
// Generate the p.h header file.
//
// 'go install -i -buildmode=c-archive ./libgo' would do that too, but that
// would also attempt to install transitive standard-library dependencies to
// GOROOT, and we cannot assume that GOROOT is writable. (A non-root user may
// be running this test in a GOROOT owned by root.)
genHeader(t, "p.h", "./p")
testInstall(t, "./testp1"+exeSuffix,
filepath.Join(libgodir, libgoa),
filepath.Join(libgodir, "libgo.h"),
"go", "install", "-i", "-buildmode=c-archive", "./libgo")
"go", "install", "-buildmode=c-archive", "./libgo")
// Test building libgo other than installing it.
// Header files are now present.
@ -259,12 +312,14 @@ func TestEarlySignalHandler(t *testing.T) {
t.Skip("skipping signal test on Windows")
}
defer func() {
os.Remove("libgo2.a")
os.Remove("libgo2.h")
os.Remove("testp")
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
if !testWork {
defer func() {
os.Remove("libgo2.a")
os.Remove("libgo2.h")
os.Remove("testp")
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "./libgo2")
if out, err := cmd.CombinedOutput(); err != nil {
@ -297,12 +352,14 @@ func TestEarlySignalHandler(t *testing.T) {
func TestSignalForwarding(t *testing.T) {
checkSignalForwardingTest(t)
defer func() {
os.Remove("libgo2.a")
os.Remove("libgo2.h")
os.Remove("testp")
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
if !testWork {
defer func() {
os.Remove("libgo2.a")
os.Remove("libgo2.h")
os.Remove("testp")
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "./libgo2")
if out, err := cmd.CombinedOutput(); err != nil {
@ -345,12 +402,14 @@ func TestSignalForwardingExternal(t *testing.T) {
}
checkSignalForwardingTest(t)
defer func() {
os.Remove("libgo2.a")
os.Remove("libgo2.h")
os.Remove("testp")
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
if !testWork {
defer func() {
os.Remove("libgo2.a")
os.Remove("libgo2.h")
os.Remove("testp")
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "./libgo2")
if out, err := cmd.CombinedOutput(); err != nil {
@ -460,12 +519,14 @@ func TestOsSignal(t *testing.T) {
t.Skip("skipping signal test on Windows")
}
defer func() {
os.Remove("libgo3.a")
os.Remove("libgo3.h")
os.Remove("testp")
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
if !testWork {
defer func() {
os.Remove("libgo3.a")
os.Remove("libgo3.h")
os.Remove("testp")
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo3.a", "./libgo3")
if out, err := cmd.CombinedOutput(); err != nil {
@ -495,12 +556,14 @@ func TestSigaltstack(t *testing.T) {
t.Skip("skipping signal test on Windows")
}
defer func() {
os.Remove("libgo4.a")
os.Remove("libgo4.h")
os.Remove("testp")
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
if !testWork {
defer func() {
os.Remove("libgo4.a")
os.Remove("libgo4.h")
os.Remove("testp")
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo4.a", "./libgo4")
if out, err := cmd.CombinedOutput(); err != nil {
@ -544,13 +607,15 @@ func TestExtar(t *testing.T) {
t.Skip("shell scripts are not executable on iOS hosts")
}
defer func() {
os.Remove("libgo4.a")
os.Remove("libgo4.h")
os.Remove("testar")
os.Remove("testar.ran")
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
if !testWork {
defer func() {
os.Remove("libgo4.a")
os.Remove("libgo4.h")
os.Remove("testar")
os.Remove("testar.ran")
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
os.Remove("testar")
dir, err := os.Getwd()
@ -584,12 +649,22 @@ func TestPIE(t *testing.T) {
t.Skipf("skipping PIE test on %s", GOOS)
}
defer func() {
os.Remove("testp" + exeSuffix)
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
if !testWork {
defer func() {
os.Remove("testp" + exeSuffix)
os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}()
}
cmd := exec.Command("go", "install", "-i", "-buildmode=c-archive", "./libgo")
// Generate the p.h header file.
//
// 'go install -i -buildmode=c-archive ./libgo' would do that too, but that
// would also attempt to install transitive standard-library dependencies to
// GOROOT, and we cannot assume that GOROOT is writable. (A non-root user may
// be running this test in a GOROOT owned by root.)
genHeader(t, "p.h", "./p")
cmd := exec.Command("go", "install", "-buildmode=c-archive", "./libgo")
if out, err := cmd.CombinedOutput(); err != nil {
t.Logf("%s", out)
t.Fatal(err)
@ -669,11 +744,13 @@ func TestSIGPROF(t *testing.T) {
t.Parallel()
defer func() {
os.Remove("testp6" + exeSuffix)
os.Remove("libgo6.a")
os.Remove("libgo6.h")
}()
if !testWork {
defer func() {
os.Remove("testp6" + exeSuffix)
os.Remove("libgo6.a")
os.Remove("libgo6.h")
}()
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo6.a", "./libgo6")
if out, err := cmd.CombinedOutput(); err != nil {
@ -709,10 +786,12 @@ func TestCompileWithoutShared(t *testing.T) {
// For simplicity, reuse the signal forwarding test.
checkSignalForwardingTest(t)
defer func() {
os.Remove("libgo2.a")
os.Remove("libgo2.h")
}()
if !testWork {
defer func() {
os.Remove("libgo2.a")
os.Remove("libgo2.h")
}()
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-gcflags=-shared=false", "-o", "libgo2.a", "./libgo2")
t.Log(cmd.Args)
@ -751,7 +830,9 @@ func TestCompileWithoutShared(t *testing.T) {
if err != nil {
t.Fatal(err)
}
defer os.Remove(exe)
if !testWork {
defer os.Remove(exe)
}
binArgs := append(cmdToRun(exe), "1")
t.Log(binArgs)
@ -769,14 +850,15 @@ func TestCompileWithoutShared(t *testing.T) {
}
}
// Test that installing a second time recreates the header files.
// Test that installing a second time recreates the header file.
func TestCachedInstall(t *testing.T) {
defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
if !testWork {
defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
}
h1 := filepath.Join(libgodir, "libgo.h")
h2 := filepath.Join(libgodir, "p.h")
h := filepath.Join(libgodir, "libgo.h")
buildcmd := []string{"go", "install", "-i", "-buildmode=c-archive", "./libgo"}
buildcmd := []string{"go", "install", "-buildmode=c-archive", "./libgo"}
cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
t.Log(buildcmd)
@ -785,17 +867,11 @@ func TestCachedInstall(t *testing.T) {
t.Fatal(err)
}
if _, err := os.Stat(h1); err != nil {
if _, err := os.Stat(h); 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 {
if err := os.Remove(h); err != nil {
t.Fatal(err)
}
@ -806,23 +882,22 @@ func TestCachedInstall(t *testing.T) {
t.Fatal(err)
}
if _, err := os.Stat(h1); err != nil {
if _, err := os.Stat(h); 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)
}
}
// Issue 35294.
func TestManyCalls(t *testing.T) {
t.Parallel()
defer func() {
os.Remove("testp7" + exeSuffix)
os.Remove("libgo7.a")
os.Remove("libgo7.h")
}()
if !testWork {
defer func() {
os.Remove("testp7" + exeSuffix)
os.Remove("libgo7.a")
os.Remove("libgo7.h")
}()
}
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo7.a", "./libgo7")
if out, err := cmd.CombinedOutput(); err != nil {

View file

@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
symBase, err := filepath.Rel(srcRoot, dstRoot)
srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
symBase, err = filepath.Abs(srcRoot)
if err != nil {
return err
}
return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
return os.Mkdir(dstPath, perm|0200)
return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}

View file

@ -130,8 +130,6 @@ func testMain(m *testing.M) int {
defer os.RemoveAll(GOPATH)
os.Setenv("GOPATH", GOPATH)
// Copy testdata into GOPATH/src/testarchive, along with a go.mod file
// declaring the same path.
modRoot := filepath.Join(GOPATH, "src", "testcshared")
if err := overlayDir(modRoot, "testdata"); err != nil {
log.Panic(err)
@ -257,14 +255,38 @@ func runCC(t *testing.T, args ...string) string {
}
func createHeaders() error {
args := []string{"go", "install", "-i", "-buildmode=c-shared",
"-installsuffix", "testcshared", "./libgo"}
// The 'cgo' command generates a number of additional artifacts,
// but we're only interested in the header.
// Shunt the rest of the outputs to a temporary directory.
objDir, err := ioutil.TempDir("", "testcshared_obj")
if err != nil {
return err
}
defer os.RemoveAll(objDir)
// Generate a C header file for p, which is a non-main dependency
// of main package libgo.
//
// TODO(golang.org/issue/35715): This should be simpler.
args := []string{"go", "tool", "cgo",
"-objdir", objDir,
"-exportheader", "p.h",
filepath.Join(".", "p", "p.go")}
cmd := exec.Command(args[0], args[1:]...)
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out)
}
// Generate a C header file for libgo itself.
args = []string{"go", "install", "-buildmode=c-shared",
"-installsuffix", "testcshared", "./libgo"}
cmd = exec.Command(args[0], args[1:]...)
out, err = cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out)
}
args = []string{"go", "build", "-buildmode=c-shared",
"-installsuffix", "testcshared",
"-o", libgoname,
@ -522,7 +544,7 @@ func TestPIE(t *testing.T) {
}
}
// Test that installing a second time recreates the header files.
// Test that installing a second time recreates the header file.
func TestCachedInstall(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "cshared")
if err != nil {
@ -536,7 +558,7 @@ func TestCachedInstall(t *testing.T) {
env := append(os.Environ(), "GOPATH="+tmpdir, "GOBIN="+filepath.Join(tmpdir, "bin"))
buildcmd := []string{"go", "install", "-x", "-i", "-buildmode=c-shared", "-installsuffix", "testcshared", "./libgo"}
buildcmd := []string{"go", "install", "-x", "-buildmode=c-shared", "-installsuffix", "testcshared", "./libgo"}
cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
cmd.Dir = filepath.Join(tmpdir, "src", "testcshared")
@ -577,16 +599,10 @@ func TestCachedInstall(t *testing.T) {
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.Dir = filepath.Join(tmpdir, "src", "testcshared")
@ -601,9 +617,6 @@ func TestCachedInstall(t *testing.T) {
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.

View file

@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
symBase, err := filepath.Rel(srcRoot, dstRoot)
srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
symBase, err = filepath.Abs(srcRoot)
if err != nil {
return err
}
return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
return os.Mkdir(dstPath, perm|0200)
return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}

View file

@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
symBase, err := filepath.Rel(srcRoot, dstRoot)
srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
symBase, err = filepath.Abs(srcRoot)
if err != nil {
return err
}
return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
return os.Mkdir(dstPath, perm|0200)
return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}

View file

@ -70,7 +70,7 @@ func testMain(m *testing.M) int {
os.Setenv("LD_LIBRARY_PATH", modRoot)
goCmd(nil, "build", "-i", "-buildmode=plugin", "./plugin1")
goCmd(nil, "build", "-buildmode=plugin", "./plugin1")
goCmd(nil, "build", "-buildmode=plugin", "./plugin2")
so, err := ioutil.ReadFile("plugin2.so")
if err != nil {

View file

@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
symBase, err := filepath.Rel(srcRoot, dstRoot)
srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
symBase, err = filepath.Abs(srcRoot)
if err != nil {
return err
}
return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
return os.Mkdir(dstPath, perm|0200)
return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}

View file

@ -9,31 +9,33 @@ import (
"bytes"
"debug/elf"
"encoding/binary"
"errors"
"flag"
"fmt"
"go/build"
"io"
"io/ioutil"
"log"
"math/rand"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"sort"
"strings"
"testing"
"time"
)
var gopathInstallDir, gorootInstallDir, suffix string
var gopathInstallDir, gorootInstallDir string
// This is the smallest set of packages we can link into a shared
// library (runtime/cgo is built implicitly).
var minpkgs = []string{"runtime", "sync/atomic"}
var soname = "libruntime,sync-atomic.so"
var testX = flag.Bool("testx", false, "if true, pass -x to 'go' subcommands invoked by the test")
var testWork = flag.Bool("testwork", false, "if true, log and do not delete the temporary working directory")
// run runs a command and calls t.Errorf if it fails.
func run(t *testing.T, msg string, args ...string) {
c := exec.Command(args[0], args[1:]...)
@ -45,31 +47,34 @@ func run(t *testing.T, msg string, args ...string) {
// goCmd invokes the go tool with the installsuffix set up by TestMain. It calls
// t.Fatalf if the command fails.
func goCmd(t *testing.T, args ...string) string {
newargs := []string{args[0], "-installsuffix=" + suffix}
if testing.Verbose() {
newargs := []string{args[0]}
if *testX {
newargs = append(newargs, "-x")
}
newargs = append(newargs, args[1:]...)
c := exec.Command("go", newargs...)
stderr := new(strings.Builder)
var output []byte
var err error
if testing.Verbose() {
fmt.Printf("+ go %s\n", strings.Join(args, " "))
c.Stderr = stderr
if testing.Verbose() && t == nil {
fmt.Fprintf(os.Stderr, "+ go %s\n", strings.Join(args, " "))
c.Stderr = os.Stderr
stderr.WriteString("(output above)")
} else {
c.Stderr = stderr
}
output, err = c.Output()
output, err := c.Output()
if err != nil {
if t != nil {
t.Helper()
t.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, stderr)
} else {
log.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, stderr)
// Panic instead of using log.Fatalf so that deferred cleanup may run in testMain.
log.Panicf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, stderr)
}
}
if testing.Verbose() && t != nil {
t.Logf("go %s", strings.Join(args, " "))
if stderr.Len() > 0 {
t.Logf("%s", stderr)
}
}
return string(bytes.TrimSpace(output))
@ -77,73 +82,61 @@ func goCmd(t *testing.T, args ...string) string {
// TestMain calls testMain so that the latter can use defer (TestMain exits with os.Exit).
func testMain(m *testing.M) (int, error) {
// Because go install -buildmode=shared $standard_library_package always
// installs into $GOROOT, here are some gymnastics to come up with a unique
// installsuffix to use in this test that we can clean up afterwards.
workDir, err := ioutil.TempDir("", "shared_test")
if err != nil {
return 0, err
}
if *testWork || testing.Verbose() {
fmt.Printf("+ mkdir -p %s\n", workDir)
}
if !*testWork {
defer os.RemoveAll(workDir)
}
// Some tests need to edit the source in GOPATH, so copy this directory to a
// temporary directory and chdir to that.
gopath := filepath.Join(workDir, "gopath")
modRoot, err := cloneTestdataModule(gopath)
if err != nil {
return 0, err
}
if testing.Verbose() {
fmt.Printf("+ export GOPATH=%s\n", gopath)
fmt.Printf("+ cd %s\n", modRoot)
}
os.Setenv("GOPATH", gopath)
os.Chdir(modRoot)
os.Setenv("PWD", modRoot)
// The test also needs to install libraries into GOROOT/pkg, so copy the
// subset of GOROOT that we need.
//
// TODO(golang.org/issue/28553): Rework -buildmode=shared so that it does not
// need to write to GOROOT.
goroot := filepath.Join(workDir, "goroot")
if err := cloneGOROOTDeps(goroot); err != nil {
return 0, err
}
if testing.Verbose() {
fmt.Fprintf(os.Stderr, "+ export GOROOT=%s\n", goroot)
}
os.Setenv("GOROOT", goroot)
myContext := build.Default
myContext.GOROOT = goroot
myContext.GOPATH = gopath
runtimeP, err := myContext.Import("runtime", ".", build.ImportComment)
if err != nil {
return 0, fmt.Errorf("import failed: %v", err)
}
for i := 0; i < 10000; i++ {
try := fmt.Sprintf("%s_%d_dynlink", runtimeP.PkgTargetRoot, rand.Int63())
err = os.Mkdir(try, 0700)
if os.IsExist(err) {
continue
}
if err == nil {
gorootInstallDir = try
}
break
}
if err != nil {
return 0, fmt.Errorf("can't create temporary directory: %v", err)
}
if gorootInstallDir == "" {
return 0, errors.New("could not create temporary directory after 10000 tries")
}
if testing.Verbose() {
fmt.Printf("+ mkdir -p %s\n", gorootInstallDir)
}
defer os.RemoveAll(gorootInstallDir)
// Some tests need to edit the source in GOPATH, so copy this directory to a
// temporary directory and chdir to that.
gopath, err := ioutil.TempDir("", "testshared")
if err != nil {
return 0, fmt.Errorf("TempDir failed: %v", err)
}
if testing.Verbose() {
fmt.Printf("+ mkdir -p %s\n", gopath)
}
defer os.RemoveAll(gopath)
modRoot := filepath.Join(gopath, "src", "testshared")
if err := overlayDir(modRoot, "testdata"); err != nil {
return 0, err
}
if testing.Verbose() {
fmt.Printf("+ cd %s\n", modRoot)
}
os.Chdir(modRoot)
os.Setenv("PWD", modRoot)
if err := ioutil.WriteFile("go.mod", []byte("module testshared\n"), 0666); err != nil {
return 0, err
}
os.Setenv("GOPATH", gopath)
if testing.Verbose() {
fmt.Printf("+ export GOPATH=%s\n", gopath)
}
myContext.GOPATH = gopath
gorootInstallDir = runtimeP.PkgTargetRoot + "_dynlink"
// All tests depend on runtime being built into a shared library. Because
// that takes a few seconds, do it here and have all tests use the version
// built here.
suffix = strings.Split(filepath.Base(gorootInstallDir), "_")[2]
goCmd(nil, append([]string{"install", "-buildmode=shared"}, minpkgs...)...)
myContext.InstallSuffix = suffix + "_dynlink"
myContext.InstallSuffix = "_dynlink"
depP, err := myContext.Import("./depBase", ".", build.ImportComment)
if err != nil {
return 0, fmt.Errorf("import failed: %v", err)
@ -171,6 +164,75 @@ func TestMain(m *testing.M) {
os.Exit(exitCode)
}
// cloneTestdataModule clones the packages from src/testshared into gopath.
// It returns the directory within gopath at which the module root is located.
func cloneTestdataModule(gopath string) (string, error) {
modRoot := filepath.Join(gopath, "src", "testshared")
if err := overlayDir(modRoot, "testdata"); err != nil {
return "", err
}
if err := ioutil.WriteFile(filepath.Join(modRoot, "go.mod"), []byte("module testshared\n"), 0644); err != nil {
return "", err
}
return modRoot, nil
}
// cloneGOROOTDeps copies (or symlinks) the portions of GOROOT/src and
// GOROOT/pkg relevant to this test into the given directory.
// It must be run from within the testdata module.
func cloneGOROOTDeps(goroot string) error {
oldGOROOT := strings.TrimSpace(goCmd(nil, "env", "GOROOT"))
if oldGOROOT == "" {
return fmt.Errorf("go env GOROOT returned an empty string")
}
// Before we clone GOROOT, figure out which packages we need to copy over.
listArgs := []string{
"list",
"-deps",
"-f", "{{if and .Standard (not .ForTest)}}{{.ImportPath}}{{end}}",
}
stdDeps := goCmd(nil, append(listArgs, minpkgs...)...)
testdataDeps := goCmd(nil, append(listArgs, "-test", "./...")...)
pkgs := append(strings.Split(strings.TrimSpace(stdDeps), "\n"),
strings.Split(strings.TrimSpace(testdataDeps), "\n")...)
sort.Strings(pkgs)
var pkgRoots []string
for _, pkg := range pkgs {
parentFound := false
for _, prev := range pkgRoots {
if strings.HasPrefix(pkg, prev) {
// We will copy in the source for pkg when we copy in prev.
parentFound = true
break
}
}
if !parentFound {
pkgRoots = append(pkgRoots, pkg)
}
}
gorootDirs := []string{
"pkg/tool",
"pkg/include",
}
for _, pkg := range pkgRoots {
gorootDirs = append(gorootDirs, filepath.Join("src", pkg))
}
for _, dir := range gorootDirs {
if testing.Verbose() {
fmt.Fprintf(os.Stderr, "+ cp -r %s %s\n", filepath.Join(goroot, dir), filepath.Join(oldGOROOT, dir))
}
if err := overlayDir(filepath.Join(goroot, dir), filepath.Join(oldGOROOT, dir)); err != nil {
return err
}
}
return nil
}
// The shared library was built at the expected location.
func TestSOBuilt(t *testing.T) {
_, err := os.Stat(filepath.Join(gorootInstallDir, soname))
@ -219,6 +281,7 @@ func TestNoTextrel(t *testing.T) {
}
// The shared library does not contain symbols called ".dup"
// (See golang.org/issue/14841.)
func TestNoDupSymbols(t *testing.T) {
sopath := filepath.Join(gorootInstallDir, soname)
f, err := elf.Open(sopath)
@ -695,7 +758,7 @@ func resetFileStamps() {
}
reset := func(path string) {
if err := filepath.Walk(path, chtime); err != nil {
log.Fatalf("resetFileStamps failed: %v", err)
log.Panicf("resetFileStamps failed: %v", err)
}
}
@ -708,6 +771,7 @@ func resetFileStamps() {
// touch changes path and returns a function that changes it back.
// It also sets the time of the file, so that we can see if it is rewritten.
func touch(t *testing.T, path string) (cleanup func()) {
t.Helper()
data, err := ioutil.ReadFile(path)
if err != nil {
t.Fatal(err)
@ -736,14 +800,32 @@ func touch(t *testing.T, path string) (cleanup func()) {
// assume it's a text file
data = append(data, '\n')
}
if err := ioutil.WriteFile(path, data, 0666); err != nil {
// If the file is still a symlink from an overlay, delete it so that we will
// replace it with a regular file instead of overwriting the symlinked one.
fi, err := os.Lstat(path)
if err == nil && !fi.Mode().IsRegular() {
fi, err = os.Stat(path)
if err := os.Remove(path); err != nil {
t.Fatal(err)
}
}
if err != nil {
t.Fatal(err)
}
// If we're replacing a symlink to a read-only file, make the new file
// user-writable.
perm := fi.Mode().Perm() | 0200
if err := ioutil.WriteFile(path, data, perm); err != nil {
t.Fatal(err)
}
if err := os.Chtimes(path, nearlyNew, nearlyNew); err != nil {
t.Fatal(err)
}
return func() {
if err := ioutil.WriteFile(path, old, 0666); err != nil {
if err := ioutil.WriteFile(path, old, perm); err != nil {
t.Fatal(err)
}
}

View file

@ -25,6 +25,7 @@ static void sigsegv() {
static void segvhandler(int signum) {
if (signum == SIGSEGV) {
fprintf(stdout, "ok\ttestsigfwd\n");
exit(0); // success
}
}

View file

@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
symBase, err := filepath.Rel(srcRoot, dstRoot)
srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
symBase, err = filepath.Abs(srcRoot)
if err != nil {
return err
}
return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
return os.Mkdir(dstPath, perm|0200)
return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}

View file

@ -21,12 +21,9 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
symBase, err := filepath.Rel(srcRoot, dstRoot)
srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
symBase, err = filepath.Abs(srcRoot)
if err != nil {
return err
}
return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
@ -52,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
return os.Mkdir(dstPath, perm|0200)
return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}

View file

@ -1,7 +1,7 @@
chrome.omnibox.onInputEntered.addListener(function(t) {
var url = urlForInput(t);
if (url) {
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.query({ "active": true, "currentWindow": true }, function(tab) {
if (!tab) return;
chrome.tabs.update(tab.id, { "url": url, "selected": true });
});

View file

@ -21,9 +21,7 @@ func overlayDir(dstRoot, srcRoot string) error {
return err
}
// If we don't use the absolute path here, exec'ing make.bash fails with
// “too many levels of symbolic links”.
symBase, err := filepath.Abs(srcRoot)
srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
return err
}
@ -51,11 +49,11 @@ func overlayDir(dstRoot, srcRoot string) error {
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
return os.Mkdir(dstPath, perm|0200)
return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
if err := os.Symlink(filepath.Join(symBase, suffix), dstPath); err == nil {
if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}

View file

@ -8,6 +8,7 @@ import (
"bytes"
"encoding/binary"
"encoding/hex"
"internal/obscuretestdata"
"io"
"io/ioutil"
"os"
@ -19,11 +20,12 @@ import (
)
type ZipTest struct {
Name string
Source func() (r io.ReaderAt, size int64) // if non-nil, used instead of testdata/<Name> file
Comment string
File []ZipTestFile
Error error // the error that Opening this file should return
Name string
Source func() (r io.ReaderAt, size int64) // if non-nil, used instead of testdata/<Name> file
Comment string
File []ZipTestFile
Obscured bool // needed for Apple notarization (golang.org/issue/34986)
Error error // the error that Opening this file should return
}
type ZipTestFile struct {
@ -189,8 +191,12 @@ var tests = []ZipTest{
},
{
// created by Go, before we wrote the "optional" data
// descriptor signatures (which are required by OS X)
Name: "go-no-datadesc-sig.zip",
// descriptor signatures (which are required by macOS).
// Use obscured file to avoid Apples notarization service
// rejecting the toolchain due to an inability to unzip this archive.
// See golang.org/issue/34986
Name: "go-no-datadesc-sig.zip.base64",
Obscured: true,
File: []ZipTestFile{
{
Name: "foo.txt",
@ -208,7 +214,7 @@ var tests = []ZipTest{
},
{
// created by Go, after we wrote the "optional" data
// descriptor signatures (which are required by OS X)
// descriptor signatures (which are required by macOS)
Name: "go-with-datadesc-sig.zip",
File: []ZipTestFile{
{
@ -496,8 +502,18 @@ func readTestZip(t *testing.T, zt ZipTest) {
rat, size := zt.Source()
z, err = NewReader(rat, size)
} else {
path := filepath.Join("testdata", zt.Name)
if zt.Obscured {
tf, err := obscuretestdata.DecodeToTempFile(path)
if err != nil {
t.Errorf("obscuretestdata.DecodeToTempFile(%s): %v", path, err)
return
}
defer os.Remove(tf)
path = tf
}
var rc *ReadCloser
rc, err = OpenReader(filepath.Join("testdata", zt.Name))
rc, err = OpenReader(path)
if err == nil {
defer rc.Close()
z = &rc.Reader

Binary file not shown.

View file

@ -0,0 +1 @@
UEsDBBQACAAAAGWHaECoZTJ+BAAAAAQAAAAHABgAZm9vLnR4dFVUBQAD3lVZT3V4CwABBPUBAAAEFAAAAGZvbwqoZTJ+BAAAAAQAAABQSwMEFAAIAAAAZodoQOmzogQEAAAABAAAAAcAGABiYXIudHh0VVQFAAPgVVlPdXgLAAEE9QEAAAQUAAAAYmFyCumzogQEAAAABAAAAFBLAQIUAxQACAAAAGWHaECoZTJ+BAAAAAQAAAAHABgAAAAAAAAAAACkgQAAAABmb28udHh0VVQFAAPeVVlPdXgLAAEE9QEAAAQUAAAAUEsBAhQDFAAIAAAAZodoQOmzogQEAAAABAAAAAcAGAAAAAAAAAAAAKSBTQAAAGJhci50eHRVVAUAA+BVWU91eAsAAQT1AQAABBQAAABQSwUGAAAAAAIAAgCaAAAAmgAAAAAA

View file

@ -1313,8 +1313,10 @@ func gccgoPkgpathToSymbolNew(ppath string) string {
for _, c := range []byte(ppath) {
switch {
case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z',
'0' <= c && c <= '9', c == '_', c == '.':
'0' <= c && c <= '9', c == '_':
bsl = append(bsl, c)
case c == '.':
bsl = append(bsl, ".x2e"...)
default:
changed = true
encbytes := []byte(fmt.Sprintf("..z%02x", c))

View file

@ -94,7 +94,7 @@ func fmtFlag(s fmt.State, verb rune) FmtFlag {
// *types.Sym, *types.Type, and *Node types use the flags below to set the format mode
const (
FErr = iota
FErr fmtMode = iota
FDbg
FTypeId
FTypeIdName // same as FTypeId, but use package name instead of prefix

View file

@ -525,7 +525,7 @@ func Main(archInit func(*Arch)) {
}
types.FmtLeft = int(FmtLeft)
types.FmtUnsigned = int(FmtUnsigned)
types.FErr = FErr
types.FErr = int(FErr)
types.Ctxt = Ctxt
initUniverse()

View file

@ -6041,6 +6041,12 @@ func genssa(f *ssa.Func, pp *Progs) {
if s.bstart[b.ID] == s.pp.next && len(b.Succs) == 1 && b.Succs[0].Block() == b {
p := thearch.Ginsnop(s.pp)
p.Pos = p.Pos.WithIsStmt()
if b.Pos == src.NoXPos {
b.Pos = p.Pos // It needs a file, otherwise a no-file non-zero line causes confusion. See #35652.
if b.Pos == src.NoXPos {
b.Pos = pp.Text.Pos // Sometimes p.Pos is empty. See #35695.
}
}
b.Pos = b.Pos.WithBogusLine() // Debuggers are not good about infinite loops, force a change in line number
}
// Emit control flow instructions for block

23
src/cmd/dist/test.go vendored
View file

@ -692,7 +692,7 @@ func (t *tester) registerTests() {
t.registerTest("testplugin", "../misc/cgo/testplugin", t.goTest(), t.timeout(600), ".")
}
if gohostos == "linux" && goarch == "amd64" {
t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go")
t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", ".")
}
if mSanSupported(goos, goarch) {
t.registerHostTest("testsanitizers/msan", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".")
@ -701,7 +701,7 @@ func (t *tester) registerTests() {
t.registerHostTest("cgo_errors", "../misc/cgo/errors", "misc/cgo/errors", ".")
}
if gohostos == "linux" && t.extLink() {
t.registerTest("testsigfwd", "../misc/cgo/testsigfwd", "go", "run", "main.go")
t.registerTest("testsigfwd", "../misc/cgo/testsigfwd", "go", "run", ".")
}
}
@ -1327,7 +1327,6 @@ func (t *tester) runFlag(rx string) string {
}
func (t *tester) raceTest(dt *distTest) error {
t.addCmd(dt, "src", t.goTest(), "-race", "-i", "runtime/race", "flag", "os", "os/exec")
t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("Output"), "runtime/race")
t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace|TestFdRace|TestFdReadRace|TestFileCloseRace"), "flag", "net", "os", "os/exec", "encoding/gob")
// We don't want the following line, because it
@ -1449,7 +1448,25 @@ func (t *tester) makeGOROOTUnwritable() (undo func()) {
}
}
gocache := os.Getenv("GOCACHE")
if gocache == "" {
panic("GOCACHE not set")
}
gocacheSubdir, _ := filepath.Rel(dir, gocache)
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if suffix := strings.TrimPrefix(path, dir+string(filepath.Separator)); suffix != "" {
if suffix == gocacheSubdir {
// Leave GOCACHE writable: we may need to write test binaries into it.
return filepath.SkipDir
}
if suffix == ".git" {
// Leave Git metadata in whatever state it was in. It may contain a lot
// of files, and it is highly unlikely that a test will try to modify
// anything within that directory.
return filepath.SkipDir
}
}
if err == nil {
mode := info.Mode()
if mode&0222 != 0 && (mode.IsDir() || mode.IsRegular()) {

View file

@ -203,10 +203,8 @@ func processFile(filename string, useStdin bool) error {
return ioutil.WriteFile(f.Name(), newSrc, 0)
}
var gofmtBuf bytes.Buffer
func gofmt(n interface{}) string {
gofmtBuf.Reset()
var gofmtBuf bytes.Buffer
if err := format.Node(&gofmtBuf, fset, n); err != nil {
return "<" + err.Error() + ">"
}

View file

@ -76,6 +76,7 @@ func parseFixPrint(t *testing.T, fn func(*ast.File) bool, desc, in string, mustB
func TestRewrite(t *testing.T) {
for _, tt := range testCases {
tt := tt
t.Run(tt.Name, func(t *testing.T) {
t.Parallel()
// Apply fix: should get tt.Out.

View file

@ -7,7 +7,7 @@ require (
github.com/ianlancetaylor/demangle v0.0.0-20180524225900-fc6590592b44 // indirect
golang.org/x/arch v0.0.0-20190815191158-8a70ba74b3a1
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee
golang.org/x/mod v0.1.1-0.20191126161957-788aebd06792
golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82 // indirect
golang.org/x/tools v0.0.0-20191104222624-6b7b8b79ae80
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e
)

View file

@ -7,8 +7,8 @@ golang.org/x/arch v0.0.0-20190815191158-8a70ba74b3a1/go.mod h1:flIaEI6LNU6xOCD5P
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191126161957-788aebd06792 h1:04Uqz7R2BD7irAGgQtrKNW5tLa50RgSW71y4ofoaivk=
golang.org/x/mod v0.1.1-0.20191126161957-788aebd06792/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -18,8 +18,8 @@ golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82 h1:vsphBvatvfbhlb4PO1BYSr9dz
golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191104222624-6b7b8b79ae80 h1:6CcDC1SXj4DrJP955osT9RJmKsH3LQBZJ59D5v4Rw0s=
golang.org/x/tools v0.0.0-20191104222624-6b7b8b79ae80/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e h1:aZzprAO9/8oim3qStq3wc1Xuxx4QmAGriC4VU4ojemQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View file

@ -1010,7 +1010,7 @@
//
// Usage:
//
// go mod download [-json] [modules]
// go mod download [-x] [-json] [modules]
//
// Download downloads the named modules, which can be module patterns selecting
// dependencies of the main module or module queries of the form path@version.
@ -1037,6 +1037,8 @@
// GoModSum string // checksum for go.mod (as in go.sum)
// }
//
// The -x flag causes download to print the commands download executes.
//
// See 'go help modules' for more about module queries.
//
//

View file

@ -683,8 +683,11 @@ func (tg *testgoData) creatingTemp(path string) {
// If we have changed the working directory, make sure we have
// an absolute path, because we are going to change directory
// back before we remove the temporary.
if tg.wd != "" && !filepath.IsAbs(path) {
path = filepath.Join(tg.pwd(), path)
if !filepath.IsAbs(path) {
if tg.wd == "" || strings.HasPrefix(tg.wd, testGOROOT) {
tg.t.Fatalf("internal testsuite error: creatingTemp(%q) within GOROOT/src", path)
}
path = filepath.Join(tg.wd, path)
}
tg.must(robustio.RemoveAll(path))
tg.temps = append(tg.temps, path)
@ -943,7 +946,7 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
return err
}
tg.tempFile(dest, string(data))
if err := os.Chmod(tg.path(dest), info.Mode()); err != nil {
if err := os.Chmod(tg.path(dest), info.Mode()|0200); err != nil {
return err
}
return nil
@ -1008,128 +1011,6 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with old release")
}
func testLocalRun(tg *testgoData, exepath, local, match string) {
tg.t.Helper()
out, err := exec.Command(exepath).Output()
if err != nil {
tg.t.Fatalf("error running %v: %v", exepath, err)
}
if !regexp.MustCompile(match).Match(out) {
tg.t.Log(string(out))
tg.t.Errorf("testdata/%s/easy.go did not generate expected output", local)
}
}
func testLocalEasy(tg *testgoData, local string) {
tg.t.Helper()
exepath := "./easy" + exeSuffix
tg.creatingTemp(exepath)
tg.run("build", "-o", exepath, filepath.Join("testdata", local, "easy.go"))
testLocalRun(tg, exepath, local, `(?m)^easysub\.Hello`)
}
func testLocalEasySub(tg *testgoData, local string) {
tg.t.Helper()
exepath := "./easysub" + exeSuffix
tg.creatingTemp(exepath)
tg.run("build", "-o", exepath, filepath.Join("testdata", local, "easysub", "main.go"))
testLocalRun(tg, exepath, local, `(?m)^easysub\.Hello`)
}
func testLocalHard(tg *testgoData, local string) {
tg.t.Helper()
exepath := "./hard" + exeSuffix
tg.creatingTemp(exepath)
tg.run("build", "-o", exepath, filepath.Join("testdata", local, "hard.go"))
testLocalRun(tg, exepath, local, `(?m)^sub\.Hello`)
}
func testLocalInstall(tg *testgoData, local string) {
tg.t.Helper()
tg.runFail("install", filepath.Join("testdata", local, "easy.go"))
}
func TestLocalImportsEasy(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
testLocalEasy(tg, "local")
}
func TestLocalImportsEasySub(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
testLocalEasySub(tg, "local")
}
func TestLocalImportsHard(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
testLocalHard(tg, "local")
}
func TestLocalImportsGoInstallShouldFail(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
testLocalInstall(tg, "local")
}
const badDirName = `#$%:, &()*;<=>?\^{}`
func copyBad(tg *testgoData) {
tg.t.Helper()
if runtime.GOOS == "windows" {
tg.t.Skipf("skipping test because %q is an invalid directory name", badDirName)
}
tg.must(filepath.Walk("testdata/local",
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
var data []byte
data, err = ioutil.ReadFile(path)
if err != nil {
return err
}
newpath := strings.Replace(path, "local", badDirName, 1)
tg.tempFile(newpath, string(data))
return nil
}))
tg.cd(tg.path("."))
}
func TestBadImportsEasy(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
// TODO: tg.parallel()
copyBad(tg)
testLocalEasy(tg, badDirName)
}
func TestBadImportsEasySub(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
copyBad(tg)
testLocalEasySub(tg, badDirName)
}
func TestBadImportsHard(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
copyBad(tg)
testLocalHard(tg, badDirName)
}
func TestBadImportsGoInstallShouldFail(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
copyBad(tg)
testLocalInstall(tg, badDirName)
}
func TestInternalPackagesInGOROOTAreRespected(t *testing.T) {
skipIfGccgo(t, "gccgo does not have GOROOT")
tg := testgo(t)
@ -1167,48 +1048,6 @@ func TestRunPkg(t *testing.T) {
tg.grepStderr("hello, world", "did not find hello, world")
}
func testMove(t *testing.T, vcs, url, base, config string) {
testenv.MustHaveExternalNetwork(t)
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.tempDir("src")
tg.must(os.Mkdir(tg.path(".hg"), 0700))
tg.must(ioutil.WriteFile(filepath.Join(tg.path(".hg"), "hgrc"), nil, 0600))
tg.setenv("GOPATH", tg.path("."))
tg.run("get", "-d", url)
tg.run("get", "-d", "-u", url)
switch vcs {
case "svn":
// SVN doesn't believe in text files so we can't just edit the config.
// Check out a different repo into the wrong place.
tg.must(robustio.RemoveAll(tg.path("src/code.google.com/p/rsc-svn")))
tg.run("get", "-d", "-u", "code.google.com/p/rsc-svn2/trunk")
tg.must(os.Rename(tg.path("src/code.google.com/p/rsc-svn2"), tg.path("src/code.google.com/p/rsc-svn")))
default:
path := tg.path(filepath.Join("src", config))
data, err := ioutil.ReadFile(path)
tg.must(err)
data = bytes.ReplaceAll(data, []byte(base), []byte(base+"XXX"))
tg.must(ioutil.WriteFile(path, data, 0644))
}
if vcs == "git" {
// git will ask for a username and password when we
// run go get -d -f -u. An empty username and
// password will work. Prevent asking by setting
// GIT_ASKPASS.
tg.creatingTemp("sink" + exeSuffix)
tg.tempFile("src/sink/sink.go", `package main; func main() {}`)
tg.run("build", "-o", "sink"+exeSuffix, "sink")
tg.setenv("GIT_ASKPASS", filepath.Join(tg.pwd(), "sink"+exeSuffix))
}
tg.runFail("get", "-d", "-u", url)
tg.grepStderr("is a custom import path for", "go get -d -u "+url+" failed for wrong reason")
tg.runFail("get", "-d", "-f", "-u", url)
tg.grepStderr("validating server certificate|[nN]ot [fF]ound", "go get -d -f -u "+url+" failed for wrong reason")
}
func TestInternalPackageErrorsAreHandled(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@ -1223,21 +1062,6 @@ func TestInternalCache(t *testing.T) {
tg.grepStderr("internal", "did not fail to build p")
}
func TestMoveGit(t *testing.T) {
testenv.MustHaveExecPath(t, "git")
testMove(t, "git", "rsc.io/pdf", "pdf", "rsc.io/pdf/.git/config")
}
func TestMoveHG(t *testing.T) {
testenv.MustHaveExecPath(t, "hg")
testMove(t, "hg", "vcs-test.golang.org/go/custom-hg-hello", "custom-hg-hello", "vcs-test.golang.org/go/custom-hg-hello/.hg/hgrc")
}
// TODO(rsc): Set up a test case on SourceForge (?) for svn.
// func testMoveSVN(t *testing.T) {
// testMove(t, "svn", "code.google.com/p/rsc-svn/trunk", "-", "-")
// }
func TestImportCommandMatch(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@ -1491,72 +1315,6 @@ func TestRelativeGOBINFail(t *testing.T) {
tg.grepStderr("cannot install, GOBIN must be an absolute path", "go install must fail if $GOBIN is a relative path")
}
// Test that without $GOBIN set, binaries get installed
// into the GOPATH bin directory.
func TestInstallIntoGOPATH(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("testdata/bin/go-cmd-test" + exeSuffix)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.run("install", "go-cmd-test")
tg.wantExecutable("testdata/bin/go-cmd-test"+exeSuffix, "go install go-cmd-test did not write to testdata/bin/go-cmd-test")
}
// Issue 12407
func TestBuildOutputToDevNull(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
fi1, err1 := os.Lstat(os.DevNull)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.run("build", "-o", os.DevNull, "go-cmd-test")
fi2, err2 := os.Lstat(os.DevNull)
if err1 == nil {
if err2 != nil {
t.Errorf("second stat of /dev/null failed: %v", err2)
} else if !os.SameFile(fi1, fi2) {
t.Errorf("/dev/null changed: now %v was %v", fi1, fi2)
}
}
}
// Issue 28549.
func TestTestOutputToDevNull(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
fi1, err1 := os.Lstat(os.DevNull)
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
tg.tempFile("src/p/p.go", "package p\n")
tg.tempFile("src/p/p_test.go", "package p\nimport \"testing\"\nfunc TestX(t *testing.T) {}\n")
tg.run("test", "-o", os.DevNull, "-c", "p")
tg.mustNotExist("p.test")
fi2, err2 := os.Lstat(os.DevNull)
if err1 == nil {
if err2 != nil {
t.Errorf("second stat of /dev/null failed: %v", err2)
} else if !os.SameFile(fi1, fi2) {
t.Errorf("/dev/null changed: now %v was %v", fi1, fi2)
}
}
}
func TestPackageMainTestImportsArchiveNotBinary(t *testing.T) {
tooSlow(t)
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
gobin := filepath.Join(tg.pwd(), "testdata", "bin")
tg.creatingTemp(gobin)
tg.setenv("GOBIN", gobin)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.must(os.Chtimes("./testdata/src/main_test/m.go", time.Now(), time.Now()))
tg.sleep()
tg.run("test", "main_test")
tg.run("install", "main_test")
tg.wantNotStale("main_test", "", "after go install, main listed as stale")
tg.run("test", "main_test")
}
func TestPackageMainTestCompilerFlags(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@ -1589,51 +1347,6 @@ func TestPackageNotStaleWithTrailingSlash(t *testing.T) {
tg.wantNotStale("io", "", "with trailing slash in GOROOT, io listed as stale")
}
// With $GOBIN set, binaries get installed to $GOBIN.
func TestInstallIntoGOBIN(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
gobin := filepath.Join(tg.pwd(), "testdata", "bin1")
tg.creatingTemp(gobin)
tg.setenv("GOBIN", gobin)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.run("install", "go-cmd-test")
tg.wantExecutable("testdata/bin1/go-cmd-test"+exeSuffix, "go install go-cmd-test did not write to testdata/bin1/go-cmd-test")
}
// Issue 11065
func TestInstallToCurrentDirectoryCreatesExecutable(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
pkg := filepath.Join(tg.pwd(), "testdata", "src", "go-cmd-test")
tg.creatingTemp(filepath.Join(pkg, "go-cmd-test"+exeSuffix))
tg.setenv("GOBIN", pkg)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.cd(pkg)
tg.run("install")
tg.wantExecutable("go-cmd-test"+exeSuffix, "go install did not write to current directory")
}
// Without $GOBIN set, installing a program outside $GOPATH should fail
// (there is nowhere to install it).
func TestInstallWithoutDestinationFails(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("install", "testdata/src/go-cmd-test/helloworld.go")
tg.grepStderr("no install location for .go files listed on command line", "wrong error")
}
// With $GOBIN set, should install there.
func TestInstallToGOBINCommandLinePackage(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
gobin := filepath.Join(tg.pwd(), "testdata", "bin1")
tg.creatingTemp(gobin)
tg.setenv("GOBIN", gobin)
tg.run("install", "testdata/src/go-cmd-test/helloworld.go")
tg.wantExecutable("testdata/bin1/helloworld"+exeSuffix, "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld")
}
func TestGoGetNonPkg(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
testenv.MustHaveExecPath(t, "git")
@ -1663,94 +1376,6 @@ func TestGoGetTestOnlyPkg(t *testing.T) {
tg.run("get", "-t", "golang.org/x/tour/content...")
}
func TestInstalls(t *testing.T) {
if testing.Short() {
t.Skip("don't install into GOROOT in short mode")
}
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.tempDir("gobin")
tg.setenv("GOPATH", tg.path("."))
goroot := runtime.GOROOT()
tg.setenv("GOROOT", goroot)
// cmd/fix installs into tool
tg.run("env", "GOOS")
goos := strings.TrimSpace(tg.getStdout())
tg.setenv("GOOS", goos)
tg.run("env", "GOARCH")
goarch := strings.TrimSpace(tg.getStdout())
tg.setenv("GOARCH", goarch)
fixbin := filepath.Join(goroot, "pkg", "tool", goos+"_"+goarch, "fix") + exeSuffix
tg.must(robustio.RemoveAll(fixbin))
tg.run("install", "cmd/fix")
tg.wantExecutable(fixbin, "did not install cmd/fix to $GOROOT/pkg/tool")
tg.must(os.Remove(fixbin))
tg.setenv("GOBIN", tg.path("gobin"))
tg.run("install", "cmd/fix")
tg.wantExecutable(fixbin, "did not install cmd/fix to $GOROOT/pkg/tool with $GOBIN set")
tg.unsetenv("GOBIN")
// gopath program installs into GOBIN
tg.tempFile("src/progname/p.go", `package main; func main() {}`)
tg.setenv("GOBIN", tg.path("gobin"))
tg.run("install", "progname")
tg.unsetenv("GOBIN")
tg.wantExecutable(tg.path("gobin/progname")+exeSuffix, "did not install progname to $GOBIN/progname")
// gopath program installs into GOPATH/bin
tg.run("install", "progname")
tg.wantExecutable(tg.path("bin/progname")+exeSuffix, "did not install progname to $GOPATH/bin/progname")
}
func TestRejectRelativeDotPathInGOPATHCommandLinePackage(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", ".")
tg.runFail("build", "testdata/src/go-cmd-test/helloworld.go")
tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries")
}
func TestRejectRelativePathsInGOPATH(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", sep+filepath.Join(tg.pwd(), "testdata")+sep+".")
tg.runFail("build", "go-cmd-test")
tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries")
}
func TestRejectRelativePathsInGOPATHCommandLinePackage(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", "testdata")
tg.runFail("build", "testdata/src/go-cmd-test/helloworld.go")
tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries")
}
// Issue 21928.
func TestRejectBlankPathsInGOPATH(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", " "+sep+filepath.Join(tg.pwd(), "testdata"))
tg.runFail("build", "go-cmd-test")
tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries")
}
// Issue 21928.
func TestIgnoreEmptyPathsInGOPATH(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("testdata/bin/go-cmd-test" + exeSuffix)
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", ""+sep+filepath.Join(tg.pwd(), "testdata"))
tg.run("install", "go-cmd-test")
tg.wantExecutable("testdata/bin/go-cmd-test"+exeSuffix, "go install go-cmd-test did not write to testdata/bin/go-cmd-test")
}
// Issue 4104.
func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
tooSlow(t)
@ -2536,57 +2161,6 @@ func TestCoverageDotImport(t *testing.T) {
checkCoverage(tg, data)
}
// Check that coverage analysis uses set mode.
// Also check that coverage profiles merge correctly.
func TestCoverageUsesSetMode(t *testing.T) {
skipIfGccgo(t, "gccgo has no cover tool")
tooSlow(t)
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("testdata/cover.out")
tg.run("test", "-short", "-cover", "encoding/binary", "errors", "-coverprofile=testdata/cover.out")
data := tg.getStdout() + tg.getStderr()
if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil {
t.Error(err)
} else {
if !bytes.Contains(out, []byte("mode: set")) {
t.Error("missing mode: set")
}
if !bytes.Contains(out, []byte("errors.go")) {
t.Error("missing errors.go")
}
if !bytes.Contains(out, []byte("binary.go")) {
t.Error("missing binary.go")
}
if bytes.Count(out, []byte("mode: set")) != 1 {
t.Error("too many mode: set")
}
}
checkCoverage(tg, data)
}
func TestCoverageUsesAtomicModeForRace(t *testing.T) {
tooSlow(t)
if !canRace {
t.Skip("skipping because race detector not supported")
}
skipIfGccgo(t, "gccgo has no cover tool")
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("testdata/cover.out")
tg.run("test", "-short", "-race", "-cover", "encoding/binary", "-coverprofile=testdata/cover.out")
data := tg.getStdout() + tg.getStderr()
if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil {
t.Error(err)
} else {
if !bytes.Contains(out, []byte("mode: atomic")) {
t.Error("missing mode: atomic")
}
}
checkCoverage(tg, data)
}
func TestCoverageSyncAtomicImport(t *testing.T) {
skipIfGccgo(t, "gccgo has no cover tool")
tooSlow(t)
@ -3081,53 +2655,6 @@ func TestIssue7108(t *testing.T) {
tg.runFail("test", "notest")
}
// cmd/go: go test -a foo does not rebuild regexp.
func TestIssue6844(t *testing.T) {
if testing.Short() {
t.Skip("don't rebuild the standard library in short mode")
}
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("deps.test" + exeSuffix)
tg.run("test", "-x", "-a", "-c", "testdata/dep_test.go")
tg.grepStderr("regexp", "go test -x -a -c testdata/dep-test.go did not rebuild regexp")
}
func TestBuildDashIInstallsDependencies(t *testing.T) {
tooSlow(t)
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.tempFile("src/x/y/foo/foo.go", `package foo
func F() {}`)
tg.tempFile("src/x/y/bar/bar.go", `package bar
import "x/y/foo"
func F() { foo.F() }`)
tg.setenv("GOPATH", tg.path("."))
// don't let build -i overwrite runtime
tg.wantNotStale("runtime", "", "must be non-stale before build -i")
checkbar := func(desc string) {
tg.run("build", "-v", "-i", "x/y/bar")
tg.grepBoth("x/y/foo", "first build -i "+desc+" did not build x/y/foo")
tg.run("build", "-v", "-i", "x/y/bar")
tg.grepBothNot("x/y/foo", "second build -i "+desc+" built x/y/foo")
}
checkbar("pkg")
tg.creatingTemp("bar" + exeSuffix)
tg.sleep()
tg.tempFile("src/x/y/foo/foo.go", `package foo
func F() { F() }`)
tg.tempFile("src/x/y/bar/bar.go", `package main
import "x/y/foo"
func main() { foo.F() }`)
checkbar("cmd")
}
func TestGoBuildTestOnly(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@ -3412,95 +2939,6 @@ func TestGoGetDotSlashDownload(t *testing.T) {
tg.run("get", "./pprof_mac_fix")
}
// Test that you cannot import a main package.
// See golang.org/issue/4210 and golang.org/issue/17475.
func TestImportMain(t *testing.T) {
tooSlow(t)
tg := testgo(t)
tg.parallel()
defer tg.cleanup()
// Importing package main from that package main's test should work.
tg.tempFile("src/x/main.go", `package main
var X int
func main() {}`)
tg.tempFile("src/x/main_test.go", `package main_test
import xmain "x"
import "testing"
var _ = xmain.X
func TestFoo(t *testing.T) {}
`)
tg.setenv("GOPATH", tg.path("."))
tg.creatingTemp("x" + exeSuffix)
tg.run("build", "x")
tg.run("test", "x")
// Importing package main from another package should fail.
tg.tempFile("src/p1/p.go", `package p1
import xmain "x"
var _ = xmain.X
`)
tg.runFail("build", "p1")
tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
// ... even in that package's test.
tg.tempFile("src/p2/p.go", `package p2
`)
tg.tempFile("src/p2/p_test.go", `package p2
import xmain "x"
import "testing"
var _ = xmain.X
func TestFoo(t *testing.T) {}
`)
tg.run("build", "p2")
tg.runFail("test", "p2")
tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
// ... even if that package's test is an xtest.
tg.tempFile("src/p3/p.go", `package p
`)
tg.tempFile("src/p3/p_test.go", `package p_test
import xmain "x"
import "testing"
var _ = xmain.X
func TestFoo(t *testing.T) {}
`)
tg.run("build", "p3")
tg.runFail("test", "p3")
tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
// ... even if that package is a package main
tg.tempFile("src/p4/p.go", `package main
func main() {}
`)
tg.tempFile("src/p4/p_test.go", `package main
import xmain "x"
import "testing"
var _ = xmain.X
func TestFoo(t *testing.T) {}
`)
tg.creatingTemp("p4" + exeSuffix)
tg.run("build", "p4")
tg.runFail("test", "p4")
tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
// ... even if that package is a package main using an xtest.
tg.tempFile("src/p5/p.go", `package main
func main() {}
`)
tg.tempFile("src/p5/p_test.go", `package main_test
import xmain "x"
import "testing"
var _ = xmain.X
func TestFoo(t *testing.T) {}
`)
tg.creatingTemp("p5" + exeSuffix)
tg.run("build", "p5")
tg.runFail("test", "p5")
tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
}
// Test that you cannot use a local import in a package
// accessed by a non-local import (found in a GOPATH/GOROOT).
// See golang.org/issue/17475.
@ -3811,7 +3249,17 @@ func TestGoTestRaceInstallCgo(t *testing.T) {
cgo := strings.TrimSpace(tg.stdout.String())
old, err := os.Stat(cgo)
tg.must(err)
tg.run("test", "-race", "-i", "runtime/race")
// For this test, we don't actually care whether 'go test -race -i' succeeds.
// It may fail, for example, if GOROOT was installed from source as root and
// is now read-only.
// We only care that — regardless of whether it succeeds — it does not
// overwrite cmd/cgo.
runArgs := []string{"test", "-race", "-i", "runtime/race"}
if status := tg.doRun(runArgs); status != nil {
tg.t.Logf("go %v failure ignored: %v", runArgs, status)
}
new, err := os.Stat(cgo)
tg.must(err)
if !new.ModTime().Equal(old.ModTime()) {
@ -4789,36 +4237,6 @@ func TestNeedVersion(t *testing.T) {
tg.grepStderr("compile", "does not match go tool version")
}
// Test that user can override default code generation flags.
func TestUserOverrideFlags(t *testing.T) {
skipIfGccgo(t, "gccgo does not use -gcflags")
if !canCgo {
t.Skip("skipping because cgo not enabled")
}
if runtime.GOOS != "linux" {
// We are testing platform-independent code, so it's
// OK to skip cases that work differently.
t.Skipf("skipping on %s because test only works if c-archive implies -shared", runtime.GOOS)
}
tg := testgo(t)
defer tg.cleanup()
// Don't call tg.parallel, as creating override.h and override.a may
// confuse other tests.
tg.tempFile("override.go", `package main
import "C"
//export GoFunc
func GoFunc() {}
func main() {}`)
tg.creatingTemp("override.a")
tg.creatingTemp("override.h")
tg.run("build", "-x", "-buildmode=c-archive", "-gcflags=all=-shared=false", tg.path("override.go"))
tg.grepStderr("compile .*-shared .*-shared=false", "user can not override code generation flag")
}
func TestCgoFlagContainsSpace(t *testing.T) {
tooSlow(t)
if !canCgo {
@ -5403,122 +4821,6 @@ func TestTestCache(t *testing.T) {
}
}
func TestTestCacheInputs(t *testing.T) {
tooSlow(t)
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
t.Skip("GODEBUG gocacheverify")
}
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.makeTempdir()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.setenv("GOCACHE", tg.path("cache"))
defer os.Remove(filepath.Join(tg.pwd(), "testdata/src/testcache/file.txt"))
defer os.Remove(filepath.Join(tg.pwd(), "testdata/src/testcache/script.sh"))
tg.must(ioutil.WriteFile(filepath.Join(tg.pwd(), "testdata/src/testcache/file.txt"), []byte("x"), 0644))
old := time.Now().Add(-1 * time.Minute)
tg.must(os.Chtimes(filepath.Join(tg.pwd(), "testdata/src/testcache/file.txt"), old, old))
info, err := os.Stat(filepath.Join(tg.pwd(), "testdata/src/testcache/file.txt"))
if err != nil {
t.Fatal(err)
}
t.Logf("file.txt: old=%v, info.ModTime=%v", old, info.ModTime()) // help debug when Chtimes lies about succeeding
tg.setenv("TESTKEY", "x")
tg.must(ioutil.WriteFile(filepath.Join(tg.pwd(), "testdata/src/testcache/script.sh"), []byte("#!/bin/sh\nexit 0\n"), 0755))
tg.must(os.Chtimes(filepath.Join(tg.pwd(), "testdata/src/testcache/script.sh"), old, old))
tg.run("test", "testcache")
tg.run("test", "testcache")
tg.grepStdout(`\(cached\)`, "did not cache")
tg.setenv("TESTKEY", "y")
tg.run("test", "testcache")
tg.grepStdoutNot(`\(cached\)`, "did not notice env var change")
tg.run("test", "testcache")
tg.grepStdout(`\(cached\)`, "did not cache")
tg.run("test", "testcache", "-run=FileSize")
tg.run("test", "testcache", "-run=FileSize")
tg.grepStdout(`\(cached\)`, "did not cache")
tg.must(ioutil.WriteFile(filepath.Join(tg.pwd(), "testdata/src/testcache/file.txt"), []byte("xxx"), 0644))
tg.run("test", "testcache", "-run=FileSize")
tg.grepStdoutNot(`\(cached\)`, "did not notice file size change")
tg.run("test", "testcache", "-run=FileSize")
tg.grepStdout(`\(cached\)`, "did not cache")
tg.run("test", "testcache", "-run=Chdir")
tg.run("test", "testcache", "-run=Chdir")
tg.grepStdout(`\(cached\)`, "did not cache")
tg.must(ioutil.WriteFile(filepath.Join(tg.pwd(), "testdata/src/testcache/file.txt"), []byte("xxxxx"), 0644))
tg.run("test", "testcache", "-run=Chdir")
tg.grepStdoutNot(`\(cached\)`, "did not notice file size change")
tg.run("test", "testcache", "-run=Chdir")
tg.grepStdout(`\(cached\)`, "did not cache")
tg.must(os.Chtimes(filepath.Join(tg.pwd(), "testdata/src/testcache/file.txt"), old, old))
tg.run("test", "testcache", "-run=FileContent")
tg.run("test", "testcache", "-run=FileContent")
tg.grepStdout(`\(cached\)`, "did not cache")
tg.must(ioutil.WriteFile(filepath.Join(tg.pwd(), "testdata/src/testcache/file.txt"), []byte("yyy"), 0644))
old2 := old.Add(10 * time.Second)
tg.must(os.Chtimes(filepath.Join(tg.pwd(), "testdata/src/testcache/file.txt"), old2, old2))
tg.run("test", "testcache", "-run=FileContent")
tg.grepStdoutNot(`\(cached\)`, "did not notice file content change")
tg.run("test", "testcache", "-run=FileContent")
tg.grepStdout(`\(cached\)`, "did not cache")
tg.run("test", "testcache", "-run=DirList")
tg.run("test", "testcache", "-run=DirList")
tg.grepStdout(`\(cached\)`, "did not cache")
tg.must(os.Remove(filepath.Join(tg.pwd(), "testdata/src/testcache/file.txt")))
tg.run("test", "testcache", "-run=DirList")
tg.grepStdoutNot(`\(cached\)`, "did not notice directory change")
tg.run("test", "testcache", "-run=DirList")
tg.grepStdout(`\(cached\)`, "did not cache")
tg.tempFile("file.txt", "")
tg.must(ioutil.WriteFile(filepath.Join(tg.pwd(), "testdata/src/testcache/testcachetmp_test.go"), []byte(`package testcache
import (
"os"
"testing"
)
func TestExternalFile(t *testing.T) {
os.Open(`+fmt.Sprintf("%q", tg.path("file.txt"))+`)
_, err := os.Stat(`+fmt.Sprintf("%q", tg.path("file.txt"))+`)
if err != nil {
t.Fatal(err)
}
}
`), 0666))
defer os.Remove(filepath.Join(tg.pwd(), "testdata/src/testcache/testcachetmp_test.go"))
tg.run("test", "testcache", "-run=ExternalFile")
tg.run("test", "testcache", "-run=ExternalFile")
tg.grepStdout(`\(cached\)`, "did not cache")
tg.must(os.Remove(filepath.Join(tg.tempdir, "file.txt")))
tg.run("test", "testcache", "-run=ExternalFile")
tg.grepStdout(`\(cached\)`, "did not cache")
switch runtime.GOOS {
case "plan9", "windows":
// no shell scripts
default:
tg.run("test", "testcache", "-run=Exec")
tg.run("test", "testcache", "-run=Exec")
tg.grepStdout(`\(cached\)`, "did not cache")
tg.must(os.Chtimes(filepath.Join(tg.pwd(), "testdata/src/testcache/script.sh"), old2, old2))
tg.run("test", "testcache", "-run=Exec")
tg.grepStdoutNot(`\(cached\)`, "did not notice script change")
tg.run("test", "testcache", "-run=Exec")
tg.grepStdout(`\(cached\)`, "did not cache")
}
}
func TestTestVet(t *testing.T) {
tooSlow(t)
tg := testgo(t)

View file

@ -1584,7 +1584,10 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
p.Target = ""
} else {
p.Target = p.Internal.Build.PkgObj
if cfg.BuildLinkshared {
if cfg.BuildLinkshared && p.Target != "" {
// TODO(bcmills): The reliance on p.Target implies that -linkshared does
// not work for any package that lacks a Target — such as a non-main
// package in module mode. We should probably fix that.
shlibnamefile := p.Target[:len(p.Target)-2] + ".shlibname"
shlib, err := ioutil.ReadFile(shlibnamefile)
if err != nil && !os.IsNotExist(err) {

View file

@ -19,7 +19,7 @@ import (
)
var cmdDownload = &base.Command{
UsageLine: "go mod download [-json] [modules]",
UsageLine: "go mod download [-x] [-json] [modules]",
Short: "download modules to local cache",
Long: `
Download downloads the named modules, which can be module patterns selecting
@ -47,6 +47,8 @@ corresponding to this Go struct:
GoModSum string // checksum for go.mod (as in go.sum)
}
The -x flag causes download to print the commands download executes.
See 'go help modules' for more about module queries.
`,
}
@ -56,6 +58,8 @@ var downloadJSON = cmdDownload.Flag.Bool("json", false, "")
func init() {
cmdDownload.Run = runDownload // break init cycle
// TODO(jayconrod): https://golang.org/issue/35849 Apply -x to other 'go mod' commands.
cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
work.AddModCommonFlags(cmdDownload)
}

View file

@ -458,7 +458,9 @@ func runGet(cmd *base.Command, args []string) {
modOnly := make(map[string]*query)
for _, q := range queries {
if q.m.Version == "none" {
modOnlyMu.Lock()
modOnly[q.m.Path] = q
modOnlyMu.Unlock()
continue
}
if q.path == q.m.Path {

View file

@ -57,8 +57,8 @@ func listModules(args []string, listVersions bool) []*modinfo.ModulePublic {
if search.IsRelativePath(arg) {
base.Fatalf("go: cannot use relative path %s to specify module", arg)
}
if !HasModRoot() && arg == "all" {
base.Fatalf(`go: cannot match "all": working directory is not part of a module`)
if !HasModRoot() && (arg == "all" || strings.Contains(arg, "...")) {
base.Fatalf("go: cannot match %q: working directory is not part of a module", arg)
}
if i := strings.Index(arg, "@"); i >= 0 {
path := arg[:i]

View file

@ -1036,7 +1036,7 @@ func (b *Builder) vet(a *Action) error {
// There's too much unsafe.Pointer code
// that vet doesn't like in low-level packages
// like runtime, sync, and reflect.
vetFlags = []string{"-unsafeptr=false"}
vetFlags = append(vetFlags, string("-unsafeptr=false"))
}
// Note: We could decide that vet should compute export data for

View file

@ -86,7 +86,11 @@ func instrumentInit() {
func buildModeInit() {
gccgo := cfg.BuildToolchainName == "gccgo"
var codegenArg string
platform := cfg.Goos + "/" + cfg.Goarch
// Configure the build mode first, then verify that it is supported.
// That way, if the flag is completely bogus we will prefer to error out with
// "-buildmode=%s not supported" instead of naming the specific platform.
switch cfg.BuildBuildmode {
case "archive":
pkgsFilter = pkgsNotMain
@ -95,20 +99,18 @@ func buildModeInit() {
if gccgo {
codegenArg = "-fPIC"
} else {
switch platform {
case "darwin/arm", "darwin/arm64":
codegenArg = "-shared"
default:
switch cfg.Goos {
case "dragonfly", "freebsd", "illumos", "linux", "netbsd", "openbsd", "solaris":
if platform == "linux/ppc64" {
base.Fatalf("-buildmode=c-archive not supported on %s\n", platform)
}
// Use -shared so that the result is
// suitable for inclusion in a PIE or
// shared library.
switch cfg.Goos {
case "darwin":
switch cfg.Goarch {
case "arm", "arm64":
codegenArg = "-shared"
}
case "dragonfly", "freebsd", "illumos", "linux", "netbsd", "openbsd", "solaris":
// Use -shared so that the result is
// suitable for inclusion in a PIE or
// shared library.
codegenArg = "-shared"
}
}
cfg.ExeSuffix = ".a"
@ -118,27 +120,25 @@ func buildModeInit() {
if gccgo {
codegenArg = "-fPIC"
} else {
switch platform {
case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/s390x",
"android/amd64", "android/arm", "android/arm64", "android/386",
"freebsd/amd64":
switch cfg.Goos {
case "linux", "android", "freebsd":
codegenArg = "-shared"
case "darwin/amd64", "darwin/386":
case "windows/amd64", "windows/386":
case "windows":
// Do not add usual .exe suffix to the .dll file.
cfg.ExeSuffix = ""
default:
base.Fatalf("-buildmode=c-shared not supported on %s\n", platform)
}
}
ldBuildmode = "c-shared"
case "default":
switch platform {
case "android/arm", "android/arm64", "android/amd64", "android/386":
switch cfg.Goos {
case "android":
codegenArg = "-shared"
ldBuildmode = "pie"
case "darwin/arm", "darwin/arm64":
codegenArg = "-shared"
case "darwin":
switch cfg.Goarch {
case "arm", "arm64":
codegenArg = "-shared"
}
fallthrough
default:
ldBuildmode = "exe"
@ -161,18 +161,8 @@ func buildModeInit() {
}
if gccgo {
codegenArg = "-fPIE"
} else {
switch platform {
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
"android/amd64", "android/arm", "android/arm64", "android/386",
"freebsd/amd64":
codegenArg = "-shared"
case "darwin/amd64":
codegenArg = "-shared"
case "aix/ppc64":
default:
base.Fatalf("-buildmode=pie not supported on %s\n", platform)
}
} else if cfg.Goos != "aix" {
codegenArg = "-shared"
}
ldBuildmode = "pie"
case "shared":
@ -180,11 +170,6 @@ func buildModeInit() {
if gccgo {
codegenArg = "-fPIC"
} else {
switch platform {
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
default:
base.Fatalf("-buildmode=shared not supported on %s\n", platform)
}
codegenArg = "-dynlink"
}
if cfg.BuildO != "" {
@ -196,14 +181,6 @@ func buildModeInit() {
if gccgo {
codegenArg = "-fPIC"
} else {
switch platform {
case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/s390x", "linux/ppc64le",
"android/amd64", "android/arm", "android/arm64", "android/386":
case "darwin/amd64":
case "freebsd/amd64":
default:
base.Fatalf("-buildmode=plugin not supported on %s\n", platform)
}
codegenArg = "-dynlink"
}
cfg.ExeSuffix = ".so"
@ -211,16 +188,19 @@ func buildModeInit() {
default:
base.Fatalf("buildmode=%s not supported", cfg.BuildBuildmode)
}
if !sys.BuildModeSupported(cfg.BuildToolchainName, cfg.BuildBuildmode, cfg.Goos, cfg.Goarch) {
base.Fatalf("-buildmode=%s not supported on %s/%s\n", cfg.BuildBuildmode, cfg.Goos, cfg.Goarch)
}
if cfg.BuildLinkshared {
if !sys.BuildModeSupported(cfg.BuildToolchainName, "shared", cfg.Goos, cfg.Goarch) {
base.Fatalf("-linkshared not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
}
if gccgo {
codegenArg = "-fPIC"
} else {
switch platform {
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
forcedAsmflags = append(forcedAsmflags, "-D=GOBUILDMODE_shared=1")
default:
base.Fatalf("-linkshared not supported on %s\n", platform)
}
forcedAsmflags = append(forcedAsmflags, "-D=GOBUILDMODE_shared=1")
codegenArg = "-dynlink"
forcedGcflags = append(forcedGcflags, "-linkshared")
// TODO(mwhudson): remove -w when that gets fixed in linker.

View file

@ -30,6 +30,7 @@ import (
"cmd/go/internal/robustio"
"cmd/go/internal/txtar"
"cmd/go/internal/work"
"cmd/internal/sys"
)
// TestScript runs the tests in testdata/script/*.txt.
@ -303,6 +304,11 @@ Script:
}
break
}
if strings.HasPrefix(cond.tag, "buildmode:") {
value := strings.TrimPrefix(cond.tag, "buildmode:")
ok = sys.BuildModeSupported(runtime.Compiler, value, runtime.GOOS, runtime.GOARCH)
break
}
if !imports.KnownArch[cond.tag] && !imports.KnownOS[cond.tag] && cond.tag != "gc" && cond.tag != "gccgo" {
ts.fatalf("unknown condition %q", cond.tag)
}
@ -580,26 +586,31 @@ func (ts *testScript) cmdEnv(neg bool, args []string) {
args = args[1:]
}
var out strings.Builder
if len(args) == 0 {
printed := make(map[string]bool) // env list can have duplicates; only print effective value (from envMap) once
for _, kv := range ts.env {
k := kv[:strings.Index(kv, "=")]
if !printed[k] {
fmt.Fprintf(&ts.log, "%s=%s\n", k, ts.envMap[k])
fmt.Fprintf(&out, "%s=%s\n", k, ts.envMap[k])
}
}
return
}
for _, env := range args {
i := strings.Index(env, "=")
if i < 0 {
// Display value instead of setting it.
fmt.Fprintf(&ts.log, "%s=%s\n", env, ts.envMap[env])
continue
} else {
for _, env := range args {
i := strings.Index(env, "=")
if i < 0 {
// Display value instead of setting it.
fmt.Fprintf(&out, "%s=%s\n", env, ts.envMap[env])
continue
}
key, val := env[:i], conv(env[i+1:])
ts.env = append(ts.env, key+"="+val)
ts.envMap[key] = val
}
key, val := env[:i], conv(env[i+1:])
ts.env = append(ts.env, key+"="+val)
ts.envMap[key] = val
}
if out.Len() > 0 || len(args) > 0 {
ts.stdout = out.String()
ts.log.WriteString(out.String())
}
}

View file

@ -1,7 +0,0 @@
// Copyright 2014 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 deps
import _ "testing"

View file

@ -1,7 +0,0 @@
package main
import "./easysub"
func main() {
easysub.Hello()
}

View file

@ -1,7 +0,0 @@
package easysub
import "fmt"
func Hello() {
fmt.Println("easysub.Hello")
}

View file

@ -1,9 +0,0 @@
// +build ignore
package main
import "."
func main() {
easysub.Hello()
}

View file

@ -1,7 +0,0 @@
package main
import "./sub"
func main() {
sub.Hello()
}

View file

@ -1,12 +0,0 @@
package sub
import (
"fmt"
subsub "./sub"
)
func Hello() {
fmt.Println("sub.Hello")
subsub.Hello()
}

View file

@ -1,7 +0,0 @@
package subsub
import "fmt"
func Hello() {
fmt.Println("subsub.Hello")
}

View file

@ -38,6 +38,7 @@ Scripts also have access to these other environment variables:
TMPDIR=$WORK/tmp
devnull=<value of os.DevNull>
goversion=<current Go version; for example, 1.12>
:=<OS-specific path list separator>
The scripts supporting files are unpacked relative to $GOPATH/src (aka $WORK/gopath/src)
and then the script begins execution in that directory as well. Thus the example above runs
@ -78,6 +79,7 @@ should only run when the condition is satisfied. The available conditions are:
- [symlink] for testenv.HasSymlink()
- [exec:prog] for whether prog is available for execution (found by exec.LookPath)
- [GODEBUG:value] for whether value is one of the comma-separated entries in the GODEBUG variable
- [buildmode:value] for whether -buildmode=value is supported
A condition can be negated: [!short] means to run the rest of the line
when testing.Short() is false. Multiple conditions may be given for a single
@ -114,7 +116,8 @@ The commands are:
from the most recent exec or go command.
- env [-r] [key=value...]
With no arguments, print the environment (useful for debugging).
With no arguments, print the environment to stdout
(useful for debugging and for verifying initial state).
Otherwise add the listed key=value pairs to the environment.
The -r flag causes the values to be escaped using regexp.QuoteMeta
before being recorded.
@ -163,7 +166,7 @@ The commands are:
- [!] stdout [-count=N] pattern
Apply the grep command (see above) to the standard output
from the most recent exec, go, or wait command.
from the most recent exec, go, wait, or env command.
- stop [message]
Stop the test early (marking it as passing), including the message if given.

View file

@ -0,0 +1,21 @@
env GO111MODULE=off
# Test that the user can override default code generation flags.
[gccgo] skip # gccgo does not use -gcflags
[!cgo] skip
[!linux] skip # test only works if c-archive implies -shared
[short] skip
go build -x -buildmode=c-archive -gcflags=all=-shared=false ./override.go
stderr '^.*/compile (.* )?-shared (.* )?-shared=false'
-- override.go --
package main
import "C"
//export GoFunc
func GoFunc() {}
func main() {}

41
src/cmd/go/testdata/script/build_i.txt vendored Normal file
View file

@ -0,0 +1,41 @@
env GO111MODULE=off
# Test that 'go build -i' installs dependencies of the requested package.
[short] skip
# Since we are checking installation of dependencies, use a clean cache
# to ensure that multiple runs of the test do not interfere.
env GOCACHE=$WORK/cache
# The initial 'go build -i' for bar should install its dependency foo.
go build -v -i x/y/bar
stderr 'x/y/foo' # should be rebuilt
go build -v -i x/y/bar
! stderr 'x/y/foo' # should already be installed
# After modifying the source files, both packages should be rebuild.
cp x/y/foo/foo.go.next x/y/foo/foo.go
cp x/y/bar/bar.go.next x/y/bar/bar.go
go build -v -i x/y/bar
stderr 'x/y/foo' # should be rebuilt
go build -v -i x/y/bar
! stderr 'x/y/foo' # should already be installed
-- x/y/foo/foo.go --
package foo
func F() {}
-- x/y/bar/bar.go --
package bar
import "x/y/foo"
func F() { foo.F() }
-- x/y/foo/foo.go.next --
package foo
func F() { F() }
-- x/y/bar/bar.go.next --
package main
import "x/y/foo"
func main() { foo.F() }

View file

@ -1,64 +1,92 @@
[short] skip
env GO111MODULE=on
# A binary built without -trimpath should contain the current workspace
# Set up two identical directories that can be used as GOPATH.
env GO111MODULE=on
mkdir $WORK/a/src/paths $WORK/b/src/paths
cp paths.go $WORK/a/src/paths
cp paths.go $WORK/b/src/paths
cp go.mod $WORK/a/src/paths/
cp go.mod $WORK/b/src/paths/
# A binary built without -trimpath should contain the module root dir
# and GOROOT for debugging and stack traces.
cd a
go build -o $WORK/paths-a.exe paths.go
exec $WORK/paths-a.exe $WORK/paths-a.exe
stdout 'binary contains GOPATH: true'
cd $WORK/a/src/paths
go build -o $WORK/paths-dbg.exe .
exec $WORK/paths-dbg.exe $WORK/paths-dbg.exe
stdout 'binary contains module root: true'
stdout 'binary contains GOROOT: true'
# A binary built with -trimpath should not contain the current workspace
# or GOROOT.
go build -trimpath -o $WORK/paths-a.exe paths.go
go build -trimpath -o $WORK/paths-a.exe .
exec $WORK/paths-a.exe $WORK/paths-a.exe
stdout 'binary contains GOPATH: false'
stdout 'binary contains module root: false'
stdout 'binary contains GOROOT: false'
# A binary from an external module built with -trimpath should not contain
# the current workspace or GOROOT.
cd $WORK
go get -trimpath rsc.io/fortune
exec $WORK/paths-a.exe $GOPATH/bin/fortune$GOEXE
stdout 'binary contains GOPATH: false'
stdout 'binary contains module root: false'
stdout 'binary contains GOROOT: false'
go mod edit -droprequire rsc.io/fortune
# Two binaries built from identical packages in different directories
# should be identical.
# TODO(golang.org/issue/35435): at the moment, they are not.
#mkdir $GOPATH/src/b
#cp $GOPATH/src/a/go.mod $GOPATH/src/b/go.mod
#cp $GOPATH/src/a/paths.go $GOPATH/src/b/paths.go
#cd $GOPATH/src/b
#go build -trimpath -o $WORK/paths-b.exe .
#cmp -q $WORK/paths-a.exe $WORK/paths-b.exe
cd $WORK/b/src/paths
go build -trimpath -o $WORK/paths-b.exe
cmp -q $WORK/paths-a.exe $WORK/paths-b.exe
# Same sequence of tests but in GOPATH mode.
# A binary built without -trimpath should contain GOPATH and GOROOT.
env GO111MODULE=off
cd $WORK
env GOPATH=$WORK/a
go build -o paths-dbg.exe paths
exec ./paths-dbg.exe paths-dbg.exe
stdout 'binary contains GOPATH: true'
stdout 'binary contains GOROOT: true'
# A binary built with -trimpath should not contain GOPATH or GOROOT.
go build -trimpath -o paths-a.exe paths
exec ./paths-a.exe paths-a.exe
stdout 'binary contains GOPATH: false'
stdout 'binary contains GOROOT: false'
# Two binaries built from identical packages in different GOPATH roots
# should be identical.
env GOPATH=$WORK/b
go build -trimpath -o paths-b.exe paths
cmp -q paths-a.exe paths-b.exe
# Same sequence of tests but with gccgo.
# gccgo does not support builds in module mode.
[!exec:gccgo] stop
env GOPATH=$WORK/a
# A binary built with gccgo without -trimpath should contain the current
# GOPATH and GOROOT.
env GO111MODULE=off # The current released gccgo does not support builds in module mode.
cd $GOPATH/src/a
go build -compiler=gccgo -o $WORK/gccgo-paths-a.exe .
exec $WORK/gccgo-paths-a.exe $WORK/gccgo-paths-a.exe
go build -compiler=gccgo -o paths-dbg.exe paths
exec ./paths-dbg.exe paths-dbg.exe
stdout 'binary contains GOPATH: true'
stdout 'binary contains GOROOT: false' # gccgo doesn't load std from GOROOT.
# A binary built with gccgo with -trimpath should not contain GOPATH or GOROOT.
go build -compiler=gccgo -trimpath -o $WORK/gccgo-paths-b.exe .
exec $WORK/gccgo-paths-a.exe $WORK/gccgo-paths-b.exe
go build -compiler=gccgo -trimpath -o paths-a.exe paths
exec ./paths-a.exe paths-a.exe
stdout 'binary contains GOPATH: false'
stdout 'binary contains GOROOT: false'
# Two binaries built from identical packages in different directories
# should be identical.
# TODO(golang.org/issue/35435): at the moment, they are not.
#cd ../b
#go build -compiler=gccgo -trimpath -o $WORK/gccgo-paths-b.exe .
#cmp -q $WORK/gccgo-paths-a.exe $WORK/gccgo-paths-b.exe
env GOPATH=$WORK/b
go build -compiler=gccgo -trimpath -o paths-b.exe paths
cmp -q paths-a.exe paths-b.exe
-- $GOPATH/src/a/paths.go --
-- paths.go --
package main
import (
@ -67,7 +95,9 @@ import (
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
)
func main() {
@ -77,17 +107,26 @@ func main() {
log.Fatal(err)
}
gopath := []byte(filepath.ToSlash(os.Getenv("GOPATH")))
if len(gopath) == 0 {
log.Fatal("GOPATH not set")
if os.Getenv("GO111MODULE") == "on" {
out, err := exec.Command("go", "env", "GOMOD").Output()
if err != nil {
log.Fatal(err)
}
modRoot := filepath.Dir(strings.TrimSpace(string(out)))
check(data, "module root", modRoot)
} else {
check(data, "GOPATH", os.Getenv("GOPATH"))
}
fmt.Printf("binary contains GOPATH: %v\n", bytes.Contains(data, gopath))
goroot := []byte(filepath.ToSlash(os.Getenv("GOROOT")))
if len(goroot) == 0 {
log.Fatal("GOROOT not set")
}
fmt.Printf("binary contains GOROOT: %v\n", bytes.Contains(data, goroot))
check(data, "GOROOT", os.Getenv("GOROOT"))
}
-- $GOPATH/src/a/go.mod --
module example.com/a
func check(data []byte, desc, dir string) {
containsDir := bytes.Contains(data, []byte(dir))
containsSlashDir := bytes.Contains(data, []byte(filepath.ToSlash(dir)))
fmt.Printf("binary contains %s: %v\n", desc, containsDir || containsSlashDir)
}
-- go.mod --
module paths
go 1.14

View file

@ -1,7 +1,7 @@
env GO111MODULE=off
[short] skip
[GODEBUG:gocacheverify] skip
[GODEBUG:gocacheverify=1] skip
[gccgo] skip # gccgo has no standard packages
# Start with a clean build cache:

View file

@ -0,0 +1,25 @@
env GO111MODULE=off
# Coverage analysis should use 'set' mode by default,
# and should merge coverage profiles correctly.
[short] skip
[gccgo] skip # gccgo has no cover tool
go test -short -cover encoding/binary errors -coverprofile=$WORK/cover.out
! stderr '[^0-9]0\.0%'
! stdout '[^0-9]0\.0%'
grep -count=1 '^mode: set$' $WORK/cover.out
grep 'errors\.go' $WORK/cover.out
grep 'binary\.go' $WORK/cover.out
[!race] stop
go test -short -race -cover encoding/binary errors -coverprofile=$WORK/cover.out
! stderr '[^0-9]0\.0%'
! stdout '[^0-9]0\.0%'
grep -count=1 '^mode: atomic$' $WORK/cover.out
grep 'errors\.go' $WORK/cover.out
grep 'binary\.go' $WORK/cover.out

26
src/cmd/go/testdata/script/devnull.txt vendored Normal file
View file

@ -0,0 +1,26 @@
env GO111MODULE=off
# Issue 28035: go test -c -o NUL should work.
# Issue 28549: go test -c -o /dev/null should not overwrite /dev/null when run as root.
cd x
cmp $devnull $WORK/empty.txt
go test -o=$devnull -c
! exists x.test$GOEXE
cmp $devnull $WORK/empty.txt
# Issue 12407: go build -o /dev/null should succeed.
cd ..
go build -o $devnull y
cmp $devnull $WORK/empty.txt
-- x/x_test.go --
package x_test
import (
"testing"
)
func TestNUL(t *testing.T) {
}
-- y/y.go --
package y
func main() {}
-- $WORK/empty.txt --

View file

@ -0,0 +1,53 @@
# Regression test for 'go install' locations in GOPATH mode.
env GO111MODULE=off
[short] skip
# Without $GOBIN set, binaries should be installed into the GOPATH bin directory.
env GOBIN=
rm $GOPATH/bin/go-cmd-test$GOEXE
go install go-cmd-test
exists $GOPATH/bin/go-cmd-test$GOEXE
# With $GOBIN set, binaries should be installed to $GOBIN.
env GOBIN=$WORK/bin1
mkdir -p $GOBIN
go install go-cmd-test
exists $GOBIN/go-cmd-test$GOEXE
# Issue 11065: installing to the current directory should create an executable.
cd go-cmd-test
env GOBIN=$PWD
go install
exists ./go-cmd-test$GOEXE
cd ..
# Without $GOBIN set, installing a program outside $GOPATH should fail
# (there is nowhere to install it).
env GOPATH= # reset to default ($HOME/go, which does not exist)
env GOBIN=
! go install go-cmd-test/helloworld.go
stderr '^go install: no install location for \.go files listed on command line \(GOBIN not set\)$'
# With $GOBIN set, should install there.
env GOBIN=$WORK/bin1
go install go-cmd-test/helloworld.go
exists $GOBIN/helloworld$GOEXE
# We can't assume that we can write to GOROOT, because it may not be writable.
# However, we can check its install location using 'go list'.
# cmd/fix should be installed to GOROOT/pkg, not GOPATH/bin.
env GOPATH=$PWD
go list -f '{{.Target}}' cmd/fix
stdout $GOROOT'[/\\]pkg[/\\]tool[/\\]'$GOOS'_'$GOARCH'[/\\]fix'$GOEXE'$'
# GOBIN should not affect toolchain install locations.
env GOBIN=$WORK/bin1
go list -f '{{.Target}}' cmd/fix
stdout $GOROOT'[/\\]pkg[/\\]tool[/\\]'$GOOS'_'$GOARCH'[/\\]fix'$GOEXE'$'
-- go-cmd-test/helloworld.go --
package main
func main() {
println("hello world")
}

View file

@ -0,0 +1,117 @@
env GO111MODULE=off # Relative imports only work in GOPATH mode.
[short] skip
# Imports should be resolved relative to the source file.
go build testdata/local/easy.go
exec ./easy$GOEXE
stdout '^easysub\.Hello'
# Ignored files should be able to import the package built from
# non-ignored files in the same directory.
go build -o easysub$GOEXE testdata/local/easysub/main.go
exec ./easysub$GOEXE
stdout '^easysub\.Hello'
# Files in relative-imported packages should be able to
# use relative imports themselves.
go build testdata/local/hard.go
exec ./hard$GOEXE
stdout '^sub\.Hello'
# Explicit source files listed on the command line should not install without
# GOBIN set, since individual source files aren't part of the containing GOPATH.
! go install testdata/local/easy.go
stderr '^go install: no install location for \.go files listed on command line \(GOBIN not set\)$'
[windows] stop # Windows does not allow the ridiculous directory name we're about to use.
env BAD_DIR_NAME='#$%:, &()*;<=>?\^{}'
mkdir -p testdata/$BAD_DIR_NAME/easysub
mkdir -p testdata/$BAD_DIR_NAME/sub/sub
cp testdata/local/easy.go testdata/$BAD_DIR_NAME/easy.go
cp testdata/local/easysub/easysub.go testdata/$BAD_DIR_NAME/easysub/easysub.go
cp testdata/local/easysub/main.go testdata/$BAD_DIR_NAME/easysub/main.go
cp testdata/local/hard.go testdata/$BAD_DIR_NAME/hard.go
cp testdata/local/sub/sub.go testdata/$BAD_DIR_NAME/sub/sub.go
cp testdata/local/sub/sub/subsub.go testdata/$BAD_DIR_NAME/sub/sub/subsub.go
# Imports should be resolved relative to the source file.
go build testdata/$BAD_DIR_NAME/easy.go
exec ./easy$GOEXE
stdout '^easysub\.Hello'
# Ignored files should be able to import the package built from
# non-ignored files in the same directory.
go build -o easysub$GOEXE testdata/$BAD_DIR_NAME/easysub/main.go
exec ./easysub$GOEXE
stdout '^easysub\.Hello'
# Files in relative-imported packages should be able to
# use relative imports themselves.
go build testdata/$BAD_DIR_NAME/hard.go
exec ./hard$GOEXE
stdout '^sub\.Hello'
# Explicit source files listed on the command line should not install without
# GOBIN set, since individual source files aren't part of the containing GOPATH.
! go install testdata/$BAD_DIR_NAME/easy.go
stderr '^go install: no install location for \.go files listed on command line \(GOBIN not set\)$'
-- testdata/local/easy.go --
package main
import "./easysub"
func main() {
easysub.Hello()
}
-- testdata/local/easysub/easysub.go --
package easysub
import "fmt"
func Hello() {
fmt.Println("easysub.Hello")
}
-- testdata/local/easysub/main.go --
// +build ignore
package main
import "."
func main() {
easysub.Hello()
}
-- testdata/local/hard.go --
package main
import "./sub"
func main() {
sub.Hello()
}
-- testdata/local/sub/sub.go --
package sub
import (
"fmt"
subsub "./sub"
)
func Hello() {
fmt.Println("sub.Hello")
subsub.Hello()
}
-- testdata/local/sub/sub/subsub.go --
package subsub
import "fmt"
func Hello() {
fmt.Println("subsub.Hello")
}

View file

@ -0,0 +1,68 @@
env GO111MODULE=off
# Test that 'go get -u' reports packages whose VCS configurations do not
# match their import paths.
[!net] skip
[short] skip
# We need to execute a custom Go program to break the config files.
#
# git will ask for a username and password when we run 'go get -d -f -u',
# so we also need to set GIT_ASKPASS. Conveniently, a single binary can
# perform both tasks!
go build -o replace.exe replace
env GIT_ASKPASS=$PWD/replace.exe
# Test that 'go get -u' reports moved git packages.
[exec:git] go get -d rsc.io/pdf
[exec:git] go get -d -u rsc.io/pdf
[exec:git] exec ./replace.exe pdf rsc.io/pdf/.git/config
[exec:git] ! go get -d -u rsc.io/pdf
[exec:git] stderr 'is a custom import path for'
[exec:git] ! go get -d -f -u rsc.io/pdf
[exec:git] stderr 'validating server certificate|[nN]ot [fF]ound'
# Test that 'go get -u' reports moved Mercurial packages.
[exec:hg] go get -d vcs-test.golang.org/go/custom-hg-hello
[exec:hg] go get -d -u vcs-test.golang.org/go/custom-hg-hello
[exec:hg] exec ./replace.exe custom-hg-hello vcs-test.golang.org/go/custom-hg-hello/.hg/hgrc
[exec:hg] ! go get -d -u vcs-test.golang.org/go/custom-hg-hello
[exec:hg] stderr 'is a custom import path for'
[exec:hg] ! go get -d -f -u vcs-test.golang.org/go/custom-hg-hello
[exec:hg] stderr 'validating server certificate|[nN]ot [fF]ound'
-- replace/replace.go --
package main
import (
"bytes"
"io/ioutil"
"log"
"os"
)
func main() {
if len(os.Args) < 3 {
return
}
base := []byte(os.Args[1])
path := os.Args[2]
data, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}
err = ioutil.WriteFile(path, bytes.ReplaceAll(data, base, append(base, "XXX"...)), 0644)
if err != nil {
log.Fatal(err)
}
}

View file

@ -0,0 +1,43 @@
# Regression test for GOPATH validation in GOPATH mode.
env GO111MODULE=off
env ORIG_GOPATH=$GOPATH
# The literal path '.' in GOPATH should be rejected.
env GOPATH=.
! go build go-cmd-test/helloworld.go
stderr 'GOPATH entry is relative'
# It should still be rejected if the requested package can be
# found using another entry.
env GOPATH=${:}$ORIG_GOPATH${:}.
! go build go-cmd-test
stderr 'GOPATH entry is relative'
# GOPATH cannot be a relative subdirectory of the working directory.
env ORIG_GOPATH
stdout 'ORIG_GOPATH='$WORK[/\\]gopath
cd $WORK
env GOPATH=gopath
! go build gopath/src/go-cmd-test/helloworld.go
stderr 'GOPATH entry is relative'
# Blank paths in GOPATH should be rejected as relative (issue 21928).
env GOPATH=' '${:}$ORIG_GOPATH
! go build go-cmd-test
stderr 'GOPATH entry is relative'
[short] stop
# Empty paths in GOPATH should be ignored (issue 21928).
env GOPATH=${:}$ORIG_GOPATH
env GOPATH
go install go-cmd-test
exists $ORIG_GOPATH/bin/go-cmd-test$GOEXE
-- go-cmd-test/helloworld.go --
package main
func main() {
println("hello world")
}

View file

@ -0,0 +1,114 @@
env GO111MODULE=off
# Test that you cannot import a main package.
# See golang.org/issue/4210 and golang.org/issue/17475.
[short] skip
cd $WORK
# Importing package main from that package main's test should work.
go build x
go test -c x
# Importing package main from another package should fail.
! go build p1
stderr 'import "x" is a program, not an importable package'
# ... even in that package's test.
go build p2
! go test -c p2
stderr 'import "x" is a program, not an importable package'
# ... even if that package's test is an xtest.
go build p3
! go test p3
stderr 'import "x" is a program, not an importable package'
# ... even if that package is a package main
go build p4
! go test -c p4
stderr 'import "x" is a program, not an importable package'
# ... even if that package is a package main using an xtest.
go build p5
! go test -c p5
stderr 'import "x" is a program, not an importable package'
-- x/main.go --
package main
var X int
func main() {}
-- x/main_test.go --
package main_test
import (
"testing"
xmain "x"
)
var _ = xmain.X
func TestFoo(t *testing.T) {}
-- p1/p.go --
package p1
import xmain "x"
var _ = xmain.X
-- p2/p.go --
package p2
-- p2/p_test.go --
package p2
import (
"testing"
xmain "x"
)
var _ = xmain.X
func TestFoo(t *testing.T) {}
-- p3/p.go --
package p
-- p3/p_test.go --
package p_test
import (
"testing"
xmain "x"
)
var _ = xmain.X
func TestFoo(t *testing.T) {}
-- p4/p.go --
package main
func main() {}
-- p4/p_test.go --
package main
import (
"testing"
xmain "x"
)
var _ = xmain.X
func TestFoo(t *testing.T) {}
-- p5/p.go --
package main
func main() {}
-- p5/p_test.go --
package main_test
import (
"testing"
xmain "x"
)
var _ = xmain.X
func TestFoo(t *testing.T) {}

View file

@ -0,0 +1,16 @@
env GO111MODULE=on
# golang.org/issue/35759: 'go list -linkshared'
# panicked if invoked on a test-only package.
[!buildmode:shared] skip
go list -f '{{.ImportPath}}: {{.Target}} {{.Shlib}}' -linkshared .
stdout '^example.com: $'
-- go.mod --
module example.com
go 1.14
-- x.go --
package x

View file

@ -19,8 +19,8 @@ cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go
# should be able to remove the module cache if the '-rf' flags are set.
[!windows] [exec:rm] exec rm -rf $GOPATH/pkg/mod
[!windows] [!exec:rm] go clean -modcache
[windows] [exec:rmdir] exec rmdir /s /q $GOPATH\pkg\mod
[windows] [!exec:rmdir] go clean -modcache
[windows] [exec:cmd.exe] exec cmd.exe /c rmdir /s /q $GOPATH\pkg\mod
[windows] [!exec:cmd.exe] go clean -modcache
! exists $GOPATH/pkg/mod
# The directories in the module cache should by default be unwritable,

View file

@ -1,5 +1,8 @@
env GO111MODULE=on
[!net] skip
[!exec:git] skip
# secure fetch should report insecure warning
cd $WORK/test
go mod init

View file

@ -4,6 +4,7 @@ env GOPROXY=$GOPROXY/quiet
# download with version should print nothing
go mod download rsc.io/quote@v1.5.0
! stdout .
! stderr .
exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.info
exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.mod
@ -106,5 +107,11 @@ rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.2.1.zip
go mod download rsc.io/quote@v1.2.1
exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.2.1.zip
# download -x with version should print
# the underlying commands such as contacting GOPROXY.
go mod download -x rsc.io/quote@v1.0.0
! stdout .
stderr 'get '$GOPROXY
-- go.mod --
module m

View file

@ -5,4 +5,4 @@ env GO111MODULE=on
[short] skip
go mod init example.com
go get golang.org/x/text@v0.3.0 golang.org/x/internal@v0.1.0
go get golang.org/x/text@v0.3.0 golang.org/x/internal@v0.1.0 golang.org/x/exp@none

View file

@ -56,6 +56,13 @@ stderr 'go: cannot match "all": working directory is not part of a module'
stderr 'go: cannot match "all": working directory is not part of a module'
! stdout 'example.com/version'
# 'go list -m' with wildcards should fail. Wildcards match modules in the
# build list, so they aren't meaningful outside a module.
! go list -m ...
stderr 'go: cannot match "...": working directory is not part of a module'
! go list -m rsc.io/quote/...
stderr 'go: cannot match "rsc.io/quote/...": working directory is not part of a module'
# 'go clean' should skip the current directory if it isn't in a module.
go clean -n

View file

@ -44,6 +44,19 @@ exists vendor
go mod edit -require rsc.io/quote@v1.5.1
! go list .
go list -mod=mod
rm vendor
# 'go generate' should use the alternate file when resolving packages.
# Recursive go commands started with 'go generate' should not get an explicitly
# passed -modfile, but they should see arguments from GOFLAGS.
cp go.alt.mod go.gen.mod
env OLD_GOFLAGS=$GOFLAGS
env GOFLAGS=-modfile=go.gen.mod
go generate -modfile=go.alt.mod .
env GOFLAGS=$OLD_GOFLAGS
grep example.com/exclude go.gen.mod
! grep example.com/exclude go.alt.mod
# The original files should not have been modified.
@ -62,6 +75,10 @@ stderr '-modfile=goaltmod: file does not have .mod extension'
-- go.sum --
ʕ◔ϖ◔ʔ
-- use.go --
package use
package main
import _ "rsc.io/quote"
-- gen.go --
//go:generate go mod edit -exclude example.com/exclude@v1.0.0
package main

View file

@ -0,0 +1,230 @@
env GO111MODULE=off
# Test that cached test results are invalidated in response to
# changes to the external inputs to the test.
[short] skip
[GODEBUG:gocacheverify=1] skip
# We're testing cache behavior, so start with a clean GOCACHE.
env GOCACHE=$WORK/cache
# Build a helper binary to invoke os.Chtimes.
go build -o mkold$GOEXE mkold.go
# Make test input files appear to be a minute old.
exec ./mkold$GOEXE 1m testcache/file.txt
exec ./mkold$GOEXE 1m testcache/script.sh
# If the test reads an environment variable, changes to that variable
# should invalidate cached test results.
env TESTKEY=x
go test testcache -run=TestLookupEnv
go test testcache -run=TestLookupEnv
stdout '\(cached\)'
env TESTKEY=y
go test testcache -run=TestLookupEnv
! stdout '\(cached\)'
go test testcache -run=TestLookupEnv
stdout '\(cached\)'
# If the test stats a file, changes to the file should invalidate the cache.
go test testcache -run=FileSize
go test testcache -run=FileSize
stdout '\(cached\)'
cp 4x.txt testcache/file.txt
go test testcache -run=FileSize
! stdout '\(cached\)'
go test testcache -run=FileSize
stdout '\(cached\)'
# Files should be tracked even if the test changes its working directory.
go test testcache -run=Chdir
go test testcache -run=Chdir
stdout '\(cached\)'
cp 6x.txt testcache/file.txt
go test testcache -run=Chdir
! stdout '\(cached\)'
go test testcache -run=Chdir
stdout '\(cached\)'
# The content of files should affect caching, provided that the mtime also changes.
exec ./mkold$GOEXE 1m testcache/file.txt
go test testcache -run=FileContent
go test testcache -run=FileContent
stdout '\(cached\)'
cp 2y.txt testcache/file.txt
exec ./mkold$GOEXE 50s testcache/file.txt
go test testcache -run=FileContent
! stdout '\(cached\)'
go test testcache -run=FileContent
stdout '\(cached\)'
# Directory contents read via os.ReadDirNames should affect caching.
go test testcache -run=DirList
go test testcache -run=DirList
stdout '\(cached\)'
rm testcache/file.txt
go test testcache -run=DirList
! stdout '\(cached\)'
go test testcache -run=DirList
stdout '\(cached\)'
# Files outside GOROOT and GOPATH should not affect caching.
env TEST_EXTERNAL_FILE=$WORK/external.txt
go test testcache -run=ExternalFile
go test testcache -run=ExternalFile
stdout '\(cached\)'
rm $WORK/external.txt
go test testcache -run=ExternalFile
stdout '\(cached\)'
# Executables within GOROOT and GOPATH should affect caching,
# even if the test does not stat them explicitly.
[!exec:/bin/sh] skip
chmod 0755 ./testcache/script.sh
exec ./mkold$GOEXEC 1m testcache/script.sh
go test testcache -run=Exec
go test testcache -run=Exec
stdout '\(cached\)'
exec ./mkold$GOEXE 50s testcache/script.sh
go test testcache -run=Exec
! stdout '\(cached\)'
go test testcache -run=Exec
stdout '\(cached\)'
-- testcache/file.txt --
xx
-- 4x.txt --
xxxx
-- 6x.txt --
xxxxxx
-- 2y.txt --
yy
-- $WORK/external.txt --
This file is outside of GOPATH.
-- testcache/script.sh --
#!/bin/sh
exit 0
-- testcache/testcache_test.go --
// 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.
package testcache
import (
"io/ioutil"
"os"
"testing"
)
func TestChdir(t *testing.T) {
os.Chdir("..")
defer os.Chdir("testcache")
info, err := os.Stat("testcache/file.txt")
if err != nil {
t.Fatal(err)
}
if info.Size()%2 != 1 {
t.Fatal("even file")
}
}
func TestOddFileContent(t *testing.T) {
f, err := os.Open("file.txt")
if err != nil {
t.Fatal(err)
}
data, err := ioutil.ReadAll(f)
f.Close()
if err != nil {
t.Fatal(err)
}
if len(data)%2 != 1 {
t.Fatal("even file")
}
}
func TestOddFileSize(t *testing.T) {
info, err := os.Stat("file.txt")
if err != nil {
t.Fatal(err)
}
if info.Size()%2 != 1 {
t.Fatal("even file")
}
}
func TestOddGetenv(t *testing.T) {
val := os.Getenv("TESTKEY")
if len(val)%2 != 1 {
t.Fatal("even env value")
}
}
func TestLookupEnv(t *testing.T) {
_, ok := os.LookupEnv("TESTKEY")
if !ok {
t.Fatal("env missing")
}
}
func TestDirList(t *testing.T) {
f, err := os.Open(".")
if err != nil {
t.Fatal(err)
}
f.Readdirnames(-1)
f.Close()
}
func TestExec(t *testing.T) {
// Note: not using os/exec to make sure there is no unexpected stat.
p, err := os.StartProcess("./script.sh", []string{"script"}, new(os.ProcAttr))
if err != nil {
t.Fatal(err)
}
ps, err := p.Wait()
if err != nil {
t.Fatal(err)
}
if !ps.Success() {
t.Fatalf("script failed: %v", err)
}
}
func TestExternalFile(t *testing.T) {
os.Open(os.Getenv("TEST_EXTERNAL_FILE"))
_, err := os.Stat(os.Getenv("TEST_EXTERNAL_FILE"))
if err != nil {
t.Fatal(err)
}
}
-- mkold.go --
package main
import (
"log"
"os"
"time"
)
func main() {
d, err := time.ParseDuration(os.Args[1])
if err != nil {
log.Fatal(err)
}
path := os.Args[2]
old := time.Now().Add(-d)
err = os.Chtimes(path, old, old)
if err != nil {
log.Fatal(err)
}
}

View file

@ -1,15 +0,0 @@
env GO111MODULE=off
# go test -c -o NUL
# should work (see golang.org/issue/28035).
cd x
go test -o=$devnull -c
! exists x.test$GOEXE
-- x/x_test.go --
package x_test
import (
"testing"
)
func TestNUL(t *testing.T) {
}

View file

@ -0,0 +1,32 @@
env GO111MODULE=off
# Test that a main_test of 'package main' imports the package,
# not the installed binary.
[short] skip
env GOBIN=$WORK/bin
go test main_test
go install main_test
go list -f '{{.Stale}}' main_test
stdout false
go test main_test
-- main_test/m.go --
package main
func F() {}
func main() {}
-- main_test/m_test.go --
package main_test
import (
. "main_test"
"testing"
)
func Test1(t *testing.T) {
F()
}

View file

@ -0,0 +1,14 @@
env GO111MODULE=off
# Regression test for golang.org/issue/6844:
# 'go test -a' should force dependencies in the standard library to be rebuilt.
[short] skip
go test -x -a -c testdata/dep_test.go
stderr '^.*[/\\]compile'$GOEXE'["]? (.* )?regexp .*[/\\]regexp\.go'
-- testdata/dep_test.go --
package deps
import _ "testing"

View file

@ -0,0 +1,8 @@
env GO111MODULE=off
# Issue 35837. Verify that "go vet -<analyzer> <std package>" works if 'pwd' is not $GOROOT/src
# we utilize the package runtime/testdata/testprog as the issue is specific to vetting standard package
go vet -n -unreachable=false runtime/testdata/testprog
stderr '-unreachable=false'
stderr '-unsafeptr=false'

View file

@ -1,5 +0,0 @@
package main
func main() {
println("hello world")
}

View file

@ -1,4 +0,0 @@
package main
func F() {}
func main() {}

View file

@ -1,10 +0,0 @@
package main_test
import (
. "main_test"
"testing"
)
func Test1(t *testing.T) {
F()
}

View file

@ -1,91 +0,0 @@
// 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.
package testcache
import (
"io/ioutil"
"os"
"runtime"
"testing"
)
func TestChdir(t *testing.T) {
os.Chdir("..")
defer os.Chdir("testcache")
info, err := os.Stat("testcache/file.txt")
if err != nil {
t.Fatal(err)
}
if info.Size()%2 != 1 {
t.Fatal("even file")
}
}
func TestOddFileContent(t *testing.T) {
f, err := os.Open("file.txt")
if err != nil {
t.Fatal(err)
}
data, err := ioutil.ReadAll(f)
f.Close()
if err != nil {
t.Fatal(err)
}
if len(data)%2 != 1 {
t.Fatal("even file")
}
}
func TestOddFileSize(t *testing.T) {
info, err := os.Stat("file.txt")
if err != nil {
t.Fatal(err)
}
if info.Size()%2 != 1 {
t.Fatal("even file")
}
}
func TestOddGetenv(t *testing.T) {
val := os.Getenv("TESTKEY")
if len(val)%2 != 1 {
t.Fatal("even env value")
}
}
func TestLookupEnv(t *testing.T) {
_, ok := os.LookupEnv("TESTKEY")
if !ok {
t.Fatal("env missing")
}
}
func TestDirList(t *testing.T) {
f, err := os.Open(".")
if err != nil {
t.Fatal(err)
}
f.Readdirnames(-1)
f.Close()
}
func TestExec(t *testing.T) {
if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
t.Skip("non-unix")
}
// Note: not using os/exec to make sure there is no unexpected stat.
p, err := os.StartProcess("./script.sh", []string{"script"}, new(os.ProcAttr))
if err != nil {
t.Fatal(err)
}
ps, err := p.Wait()
if err != nil {
t.Fatal(err)
}
if !ps.Success() {
t.Fatalf("script failed: %v", err)
}
}

View file

@ -7,6 +7,7 @@ package buildid
import (
"bytes"
"crypto/sha256"
"internal/obscuretestdata"
"io/ioutil"
"os"
"reflect"
@ -19,13 +20,6 @@ const (
)
func TestReadFile(t *testing.T) {
var files = []string{
"p.a",
"a.elf",
"a.macho",
"a.pe",
}
f, err := ioutil.TempFile("", "buildid-test-")
if err != nil {
t.Fatal(err)
@ -34,26 +28,43 @@ func TestReadFile(t *testing.T) {
defer os.Remove(tmp)
f.Close()
for _, f := range files {
id, err := ReadFile("testdata/" + f)
// Use obscured files to prevent Apples notarization service from
// mistaking them as candidates for notarization and rejecting the entire
// toolchain.
// See golang.org/issue/34986
var files = []string{
"p.a.base64",
"a.elf.base64",
"a.macho.base64",
"a.pe.base64",
}
for _, name := range files {
f, err := obscuretestdata.DecodeToTempFile("testdata/" + name)
if err != nil {
t.Errorf("obscuretestdata.DecodeToTempFile(testdata/%s): %v", name, err)
continue
}
defer os.Remove(f)
id, err := ReadFile(f)
if id != expectedID || err != nil {
t.Errorf("ReadFile(testdata/%s) = %q, %v, want %q, nil", f, id, err, expectedID)
}
old := readSize
readSize = 2048
id, err = ReadFile("testdata/" + f)
id, err = ReadFile(f)
readSize = old
if id != expectedID || err != nil {
t.Errorf("ReadFile(testdata/%s) [readSize=2k] = %q, %v, want %q, nil", f, id, err, expectedID)
t.Errorf("ReadFile(%s) [readSize=2k] = %q, %v, want %q, nil", f, id, err, expectedID)
}
data, err := ioutil.ReadFile("testdata/" + f)
data, err := ioutil.ReadFile(f)
if err != nil {
t.Fatal(err)
}
m, _, err := FindAndHash(bytes.NewReader(data), expectedID, 1024)
if err != nil {
t.Errorf("FindAndHash(testdata/%s): %v", f, err)
t.Errorf("FindAndHash(%s): %v", f, err)
continue
}
if err := ioutil.WriteFile(tmp, data, 0666); err != nil {
@ -68,7 +79,7 @@ func TestReadFile(t *testing.T) {
err = Rewrite(tf, m, newID)
err2 := tf.Close()
if err != nil {
t.Errorf("Rewrite(testdata/%s): %v", f, err)
t.Errorf("Rewrite(%s): %v", f, err)
continue
}
if err2 != nil {
@ -77,7 +88,7 @@ func TestReadFile(t *testing.T) {
id, err = ReadFile(tmp)
if id != newID || err != nil {
t.Errorf("ReadFile(testdata/%s after Rewrite) = %q, %v, want %q, nil", f, id, err, newID)
t.Errorf("ReadFile(%s after Rewrite) = %q, %v, want %q, nil", f, id, err, newID)
}
}
}

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View file

@ -0,0 +1 @@
TVqQAAMABAAAAAAA//8AAIsAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAABQRQAAZIYEAAAAAAAADAAAAAAAAPAAIwILAgMAAAIAAAACAAAAAAAAcBAAAAAQAAAAAEAAAAAAAAAQAAAAAgAABAAAAAEAAAAEAAAAAAAAAABQAAAABgAAAAAAAAMAAAAAACAAAAAAAADgHwAAAAAAAAAQAAAAAAAAEAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAMAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAudGV4dAAAAMYBAAAAEAAAAAIAAAAGAAAAAAAAAAAAAAAAAABgAABgLmRhdGEAAADgAQAAACAAAAACAAAACAAAAAAAAAAAAAAAAAAAQAAAwC5pZGF0YQAAFAAAAAAwAAAAAgAAAAoAAAAAAAAAAAAAAAAAAEAAAMAuc3ltdGFiAAQAAAAAQAAAAAIAAAAMAAAAAAAAAAAAAAAAAAAAAABCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/yBHbyBidWlsZCBJRDogImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6LjEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQiCiD/zMPMzMzMzMzMzMzMzMzMzMwBAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAEEAAAAAAAAAAAAAAAAAA+////wAAAQgCAAAAAAAAAAAQQAAAAAAAQAAAAAAAAABwEEAAAAAAAHgAAAAAAAAAcRBAAAAAAADIAAAAAAAAAAAQQAAAAAAAaAAAAAAAAABnRSMBAAAAAAAAAAAAAAAAAAAAAAAAAABnby5idWlsZGlkAAAAAAAAcBBAAAAAAACwAAAAAAAAAGdFIwG7AAAAvgAAAMEAAAAAAAAAAgAAAIAQQAAAAAAAgBBAAAAAAABtYWluLm1haW4AAAIBAAQBAAYBAAAAAAACAAAA0AAAAC9Vc2Vycy9yc2MvZ28vc3JjL2NtZC9pbnRlcm5hbC9idWlsZGlkL3Rlc3RkYXRhL3AuZ28AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAQQAAAAAAABgEAAAAAAAAGAQAAAAAAANAQQAAAAAAAAwAAAAAAAAADAAAAAAAAAIgRQAAAAAAAAgAAAAAAAAACAAAAAAAAAIwQQAAAAAAAABBAAAAAAABxEEAAAAAAAAAQQAAAAAAAgBBAAAAAAAAAIEAAAAAAAOAhQAAAAAAA4CFAAAAAAADgIUAAAAAAAOAhQAAAAAAA4CFAAAAAAADgIUAAAAAAAOAhQAAAAAAA4CFAAAAAAACJEEAAAAAAAIgQQAAAAAAAgBBAAAAAAAC4EEAAAAAAAKAQQAAAAAAAAQAAAAAAAAABAAAAAAAAALgQQAAAAAAAAAAAAAAAAAAAAAAAAAAAALgQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=

Binary file not shown.

View file

@ -0,0 +1 @@
ITxhcmNoPgpfXy5QS0dERUYgICAgICAgMCAgICAgICAgICAgMCAgICAgMCAgICAgNjQ0ICAgICAzMzAgICAgICAgYApnbyBvYmplY3QgZGFyd2luIGFtZDY0IGRldmVsICszYjMzYWY1ZDY4IFRodSBPY3QgNSAxNjo1OTowMCAyMDE3IC0wNDAwIFg6ZnJhbWVwb2ludGVyCmJ1aWxkIGlkICJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ei4xMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0IgotLS0tCgpidWlsZCBpZCAiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXouMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNCIKCiQkQgp2ZXJzaW9uIDUKCgACAQFwAAsACwABAAokJApfZ29fLm8gICAgICAgICAgMCAgICAgICAgICAgMCAgICAgMCAgICAgNjQ0ICAgICAyMjMgICAgICAgYApnbyBvYmplY3QgZGFyd2luIGFtZDY0IGRldmVsICszYjMzYWY1ZDY4IFRodSBPY3QgNSAxNjo1OTowMCAyMDE3IC0wNDAwIFg6ZnJhbWVwb2ludGVyCmJ1aWxkIGlkICJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ei4xMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0IgotLS0tCgoKIQoAAGdvMTlsZAEA/wAAAAAAAP//Z28xOWxkAA==

View file

@ -674,6 +674,12 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
// Mark the stack bound check and morestack call async nonpreemptible.
// If we get preempted here, when resumed the preemption request is
// cleared, but we'll still call morestack, which will double the stack
// unnecessarily. See issue #35470.
p = c.ctxt.StartUnsafePoint(p, c.newprog)
if framesize <= objabi.StackSmall {
// small stack: SP < stackguard
// CMP stackguard, SP
@ -757,6 +763,8 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
bls.As = ABLS
bls.To.Type = obj.TYPE_BRANCH
end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
var last *obj.Prog
for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
}
@ -768,7 +776,8 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
spfix.As = obj.ANOP
spfix.Spadj = -framesize
pcdata := c.ctxt.EmitEntryLiveness(c.cursym, spfix, c.newprog)
pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
// MOVW LR, R3
movw := obj.Appendp(pcdata, c.newprog)
@ -793,14 +802,16 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
}
call.To.Sym = c.ctxt.Lookup(morestack)
pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
// B start
b := obj.Appendp(call, c.newprog)
b := obj.Appendp(pcdata, c.newprog)
b.As = obj.AJMP
b.To.Type = obj.TYPE_BRANCH
b.Pcond = c.cursym.Func.Text.Link
b.Spadj = +framesize
return bls
return end
}
var unaryDst = map[obj.As]bool{

View file

@ -53,12 +53,17 @@ Special Cases.
(3) No need to add "W" suffix: LDARB, LDARH, LDAXRB, LDAXRH, LDTRH, LDXRB, LDXRH.
(4) In Go assembly syntax, NOP is a zero-width pseudo-instruction serves generic purpose, nothing
related to real ARM64 instruction. NOOP serves for the hardware nop instruction. NOOP is an alias of
HINT $0.
Examples:
VMOV V13.B[1], R20 <=> mov x20, v13.b[1]
VMOV V13.H[1], R20 <=> mov w20, v13.h[1]
JMP (R3) <=> br x3
CALL (R17) <=> blr x17
LDAXRB (R19), R16 <=> ldaxrb w16, [x19]
NOOP <=> nop
Register mapping rules

View file

@ -62,6 +62,12 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
// Mark the stack bound check and morestack call async nonpreemptible.
// If we get preempted here, when resumed the preemption request is
// cleared, but we'll still call morestack, which will double the stack
// unnecessarily. See issue #35470.
p = c.ctxt.StartUnsafePoint(p, c.newprog)
q := (*obj.Prog)(nil)
if framesize <= objabi.StackSmall {
// small stack: SP < stackguard
@ -156,6 +162,8 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
bls.As = ABLS
bls.To.Type = obj.TYPE_BRANCH
end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
var last *obj.Prog
for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
}
@ -167,7 +175,8 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
spfix.As = obj.ANOP
spfix.Spadj = -framesize
pcdata := c.ctxt.EmitEntryLiveness(c.cursym, spfix, c.newprog)
pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
// MOV LR, R3
movlr := obj.Appendp(pcdata, c.newprog)
@ -204,18 +213,16 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
}
call.To.Sym = c.ctxt.Lookup(morestack)
pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
// B start
jmp := obj.Appendp(call, c.newprog)
jmp := obj.Appendp(pcdata, c.newprog)
jmp.As = AB
jmp.To.Type = obj.TYPE_BRANCH
jmp.Pcond = c.cursym.Func.Text.Link
jmp.Spadj = +framesize
// placeholder for bls's jump target
// p = obj.Appendp(ctxt, p)
// p.As = obj.ANOP
return bls
return end
}
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {

View file

@ -677,6 +677,12 @@ func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
// Mark the stack bound check and morestack call async nonpreemptible.
// If we get preempted here, when resumed the preemption request is
// cleared, but we'll still call morestack, which will double the stack
// unnecessarily. See issue #35470.
p = c.ctxt.StartUnsafePoint(p, c.newprog)
var q *obj.Prog
if framesize <= objabi.StackSmall {
// small stack: SP < stackguard
@ -796,7 +802,7 @@ func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
p.Mark |= LABEL
}
p = c.ctxt.EmitEntryLiveness(c.cursym, p, c.newprog)
p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
// JAL runtime.morestack(SB)
p = obj.Appendp(p, c.newprog)
@ -812,6 +818,8 @@ func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
}
p.Mark |= BRANCH
p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
// JMP start
p = obj.Appendp(p, c.newprog)

View file

@ -187,6 +187,13 @@ func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
// liveness map active at the entry of function s. It returns the last
// Prog generated.
func (ctxt *Link) EmitEntryLiveness(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata := ctxt.EmitEntryStackMap(s, p, newprog)
pcdata = ctxt.EmitEntryRegMap(s, pcdata, newprog)
return pcdata
}
// Similar to EmitEntryLiveness, but just emit stack map.
func (ctxt *Link) EmitEntryStackMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata := Appendp(p, newprog)
pcdata.Pos = s.Func.Text.Pos
pcdata.As = APCDATA
@ -195,8 +202,12 @@ func (ctxt *Link) EmitEntryLiveness(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata.To.Type = TYPE_CONST
pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
// Same, with register map.
pcdata = Appendp(pcdata, newprog)
return pcdata
}
// Similar to EmitEntryLiveness, but just emit register map.
func (ctxt *Link) EmitEntryRegMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata := Appendp(p, newprog)
pcdata.Pos = s.Func.Text.Pos
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
@ -215,12 +226,10 @@ func (ctxt *Link) StartUnsafePoint(p *Prog, newprog ProgAlloc) *Prog {
pcdata := Appendp(p, newprog)
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
pcdata.From.Offset = objabi.PCDATA_StackMapIndex
pcdata.From.Offset = objabi.PCDATA_RegMapIndex
pcdata.To.Type = TYPE_CONST
pcdata.To.Offset = -2 // pcdata -2 marks unsafe point
// TODO: register map?
return pcdata
}
@ -232,7 +241,7 @@ func (ctxt *Link) EndUnsafePoint(p *Prog, newprog ProgAlloc, oldval int64) *Prog
pcdata := Appendp(p, newprog)
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
pcdata.From.Offset = objabi.PCDATA_StackMapIndex
pcdata.From.Offset = objabi.PCDATA_RegMapIndex
pcdata.To.Type = TYPE_CONST
pcdata.To.Offset = oldval
@ -248,7 +257,7 @@ func MarkUnsafePoints(ctxt *Link, p0 *Prog, newprog ProgAlloc, isUnsafePoint fun
prev := p0
oldval := int64(-1) // entry pcdata
for p := prev.Link; p != nil; p, prev = p.Link, p {
if p.As == APCDATA && p.From.Offset == objabi.PCDATA_StackMapIndex {
if p.As == APCDATA && p.From.Offset == objabi.PCDATA_RegMapIndex {
oldval = p.To.Offset
continue
}

View file

@ -1045,6 +1045,12 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
// Mark the stack bound check and morestack call async nonpreemptible.
// If we get preempted here, when resumed the preemption request is
// cleared, but we'll still call morestack, which will double the stack
// unnecessarily. See issue #35470.
p = c.ctxt.StartUnsafePoint(p, c.newprog)
var q *obj.Prog
if framesize <= objabi.StackSmall {
// small stack: SP < stackguard
@ -1153,7 +1159,7 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
q.Pcond = p
}
p = c.ctxt.EmitEntryLiveness(c.cursym, p, c.newprog)
p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
var morestacksym *obj.LSym
if c.cursym.CFunc() {
@ -1239,6 +1245,8 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
p.To.Reg = REG_R2
}
p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
// BR start
p = obj.Appendp(p, c.newprog)
p.As = ABR

View file

@ -324,7 +324,7 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
off := p.From.Offset
to := p.To
low, high, err := split32BitImmediate(off)
low, high, err := Split32BitImmediate(off)
if err != nil {
ctxt.Diag("%v: constant %d too large: %v", p, off, err)
}
@ -486,6 +486,116 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
}
// Split immediates larger than 12-bits.
for p := cursym.Func.Text; p != nil; p = p.Link {
switch p.As {
// <opi> $imm, REG, TO
case AADDI, AANDI, AORI, AXORI:
// LUI $high, TMP
// ADDI $low, TMP, TMP
// <op> TMP, REG, TO
q := *p
low, high, err := Split32BitImmediate(p.From.Offset)
if err != nil {
ctxt.Diag("%v: constant %d too large", p, p.From.Offset, err)
}
if high == 0 {
break // no need to split
}
p.As = ALUI
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high}
p.Reg = 0
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
p.Spadj = 0 // needed if TO is SP
p = obj.Appendp(p, newprog)
p.As = AADDIW
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: low}
p.Reg = REG_TMP
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
p = obj.Appendp(p, newprog)
switch q.As {
case AADDI:
p.As = AADD
case AANDI:
p.As = AAND
case AORI:
p.As = AOR
case AXORI:
p.As = AXOR
default:
ctxt.Diag("progedit: unsupported inst %v for splitting", q)
}
p.Spadj = q.Spadj
p.To = q.To
p.Reg = q.Reg
p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
// <load> $imm, REG, TO (load $imm+(REG), TO)
// <store> $imm, REG, TO (store $imm+(TO), REG)
case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU,
ASD, ASB, ASH, ASW:
// LUI $high, TMP
// ADDI $low, TMP, TMP
q := *p
low, high, err := Split32BitImmediate(p.From.Offset)
if err != nil {
ctxt.Diag("%v: constant %d too large", p, p.From.Offset)
}
if high == 0 {
break // no need to split
}
switch q.As {
case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU:
// LUI $high, TMP
// ADD TMP, REG, TMP
// <load> $low, TMP, TO
p.As = ALUI
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high}
p.Reg = 0
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
p.Spadj = 0 // needed if TO is SP
p = obj.Appendp(p, newprog)
p.As = AADD
p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
p.Reg = q.Reg
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
p = obj.Appendp(p, newprog)
p.As = q.As
p.To = q.To
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: low}
p.Reg = REG_TMP
case ASD, ASB, ASH, ASW:
// LUI $high, TMP
// ADD TMP, TO, TMP
// <store> $low, REG, TMP
p.As = ALUI
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high}
p.Reg = 0
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
p.Spadj = 0 // needed if TO is SP
p = obj.Appendp(p, newprog)
p.As = AADD
p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
p.Reg = q.To.Reg
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
p = obj.Appendp(p, newprog)
p.As = q.As
p.Reg = q.Reg
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: low}
}
}
}
setPCs(cursym.Func.Text, 0)
// Resolve branch and jump targets.
@ -512,11 +622,11 @@ func signExtend(val int64, bit uint) int64 {
return val << (64 - bit) >> (64 - bit)
}
// split32BitImmediate splits a signed 32-bit immediate into a signed 20-bit
// Split32BitImmediate splits a signed 32-bit immediate into a signed 20-bit
// upper immediate and a signed 12-bit lower immediate to be added to the upper
// result. For example, high may be used in LUI and low in a following ADDI to
// generate a full 32-bit constant.
func split32BitImmediate(imm int64) (low, high int64, err error) {
func Split32BitImmediate(imm int64) (low, high int64, err error) {
if !immIFits(imm, 32) {
return 0, 0, fmt.Errorf("immediate does not fit in 32-bits: %d", imm)
}
@ -909,6 +1019,27 @@ func encodeRaw(p *obj.Prog) uint32 {
return uint32(a.Offset)
}
func EncodeIImmediate(imm int64) (int64, error) {
if !immIFits(imm, 12) {
return 0, fmt.Errorf("immediate %#x does not fit in 12 bits", imm)
}
return imm << 20, nil
}
func EncodeSImmediate(imm int64) (int64, error) {
if !immIFits(imm, 12) {
return 0, fmt.Errorf("immediate %#x does not fit in 12 bits", imm)
}
return ((imm >> 5) << 25) | ((imm & 0x1f) << 7), nil
}
func EncodeUImmediate(imm int64) (int64, error) {
if !immUFits(imm, 20) {
return 0, fmt.Errorf("immediate %#x does not fit in 20 bits", imm)
}
return imm << 12, nil
}
type encoding struct {
encode func(*obj.Prog) uint32 // encode returns the machine code for an *obj.Prog
validate func(*obj.Prog) // validate validates an *obj.Prog, calling ctxt.Diag for any issues

View file

@ -335,6 +335,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
if !p.From.Sym.NoSplit() {
p, pPreempt = c.stacksplitPre(p, autosize) // emit pre part of split check
pPre = p
p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
wasSplit = true //need post part of split
}
@ -575,15 +576,16 @@ func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Pro
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
// Mark the stack bound check and morestack call async nonpreemptible.
// If we get preempted here, when resumed the preemption request is
// cleared, but we'll still call morestack, which will double the stack
// unnecessarily. See issue #35470.
p = c.ctxt.StartUnsafePoint(p, c.newprog)
q = nil
if framesize <= objabi.StackSmall {
// small stack: SP < stackguard
// CMP stackguard, SP
//p.To.Type = obj.TYPE_REG
//p.To.Reg = REGSP
// q1: BLT done
// CMPUBGE stackguard, SP, label-of-call-to-morestack
p = obj.Appendp(p, c.newprog)
//q1 = p
@ -592,22 +594,11 @@ func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Pro
p.Reg = REGSP
p.As = ACMPUBGE
p.To.Type = obj.TYPE_BRANCH
//p = obj.Appendp(ctxt, p)
//p.As = ACMPU
//p.From.Type = obj.TYPE_REG
//p.From.Reg = REG_R3
//p.To.Type = obj.TYPE_REG
//p.To.Reg = REGSP
//p = obj.Appendp(ctxt, p)
//p.As = ABGE
//p.To.Type = obj.TYPE_BRANCH
} else if framesize <= objabi.StackBig {
// large stack: SP-framesize < stackguard-StackSmall
// ADD $-(framesize-StackSmall), SP, R4
// CMP stackguard, R4
// CMPUBGE stackguard, R4, label-of-call-to-morestack
p = obj.Appendp(p, c.newprog)
p.As = AADD
@ -639,7 +630,7 @@ func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Pro
// ADD $StackGuard, SP, R4
// SUB R3, R4
// MOVD $(framesize+(StackGuard-StackSmall)), TEMP
// CMPUBGE TEMP, R4
// CMPUBGE TEMP, R4, label-of-call-to-morestack
p = obj.Appendp(p, c.newprog)
p.As = ACMP
@ -694,7 +685,8 @@ func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog,
spfix.As = obj.ANOP
spfix.Spadj = -framesize
pcdata := c.ctxt.EmitEntryLiveness(c.cursym, spfix, c.newprog)
pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
// MOVD LR, R5
p = obj.Appendp(pcdata, c.newprog)
@ -721,6 +713,8 @@ func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog,
p.To.Sym = c.ctxt.Lookup("runtime.morestack")
}
p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
// BR start
p = obj.Appendp(p, c.newprog)

View file

@ -998,6 +998,12 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
if cursym.CFunc() {
p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
// Mark the stack bound check and morestack call async nonpreemptible.
// If we get preempted here, when resumed the preemption request is
// cleared, but we'll still call morestack, which will double the stack
// unnecessarily. See issue #35470.
p = ctxt.StartUnsafePoint(p, newprog)
} else if framesize <= objabi.StackBig {
// large stack: SP-framesize <= stackguard-StackSmall
// LEAQ -xxx(SP), AX
@ -1020,6 +1026,8 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
if cursym.CFunc() {
p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p = ctxt.StartUnsafePoint(p, newprog) // see the comment above
} else {
// Such a large stack we need to protect against wraparound.
// If SP is close to zero:
@ -1029,11 +1037,11 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
//
// Preemption sets stackguard to StackPreempt, a very large value.
// That breaks the math above, so we have to check for that explicitly.
// MOVQ stackguard, CX
// CMPQ CX, $StackPreempt
// MOVQ stackguard, SI
// CMPQ SI, $StackPreempt
// JEQ label-of-call-to-morestack
// LEAQ StackGuard(SP), AX
// SUBQ CX, AX
// SUBQ SI, AX
// CMPQ AX, $(framesize+(StackGuard-StackSmall))
p = obj.Appendp(p, newprog)
@ -1047,6 +1055,8 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_SI
p = ctxt.StartUnsafePoint(p, newprog) // see the comment above
p = obj.Appendp(p, newprog)
p.As = cmp
p.From.Type = obj.TYPE_REG
@ -1090,6 +1100,8 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
jls.As = AJLS
jls.To.Type = obj.TYPE_BRANCH
end := ctxt.EndUnsafePoint(jls, newprog, -1)
var last *obj.Prog
for last = cursym.Func.Text; last.Link != nil; last = last.Link {
}
@ -1101,7 +1113,8 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
spfix.As = obj.ANOP
spfix.Spadj = -framesize
pcdata := ctxt.EmitEntryLiveness(cursym, spfix, newprog)
pcdata := ctxt.EmitEntryStackMap(cursym, spfix, newprog)
pcdata = ctxt.StartUnsafePoint(pcdata, newprog)
call := obj.Appendp(pcdata, newprog)
call.Pos = cursym.Func.Text.Pos
@ -1126,7 +1139,9 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
progedit(ctxt, callend.Link, newprog)
}
jmp := obj.Appendp(callend, newprog)
pcdata = ctxt.EndUnsafePoint(callend, newprog, -1)
jmp := obj.Appendp(pcdata, newprog)
jmp.As = obj.AJMP
jmp.To.Type = obj.TYPE_BRANCH
jmp.Pcond = cursym.Func.Text.Link
@ -1137,7 +1152,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
q1.Pcond = call
}
return jls
return end
}
var unaryDst = map[obj.As]bool{

View file

@ -71,6 +71,10 @@ func (p XPos) WithIsStmt() XPos {
// gdb chooses not to display the bogus line; delve shows it with a complaint, but the
// alternative behavior is to hang.
func (p XPos) WithBogusLine() XPos {
if p.index == 0 {
// See #35652
panic("Assigning a bogus line to XPos with no file will cause mysterious downstream failures.")
}
p.lico = makeBogusLico()
return p
}

View file

@ -43,3 +43,71 @@ func MustLinkExternal(goos, goarch string) bool {
}
return false
}
// BuildModeSupported reports whether goos/goarch supports the given build mode
// using the given compiler.
func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
if compiler == "gccgo" {
return true
}
platform := goos + "/" + goarch
switch buildmode {
case "archive":
return true
case "c-archive":
// TODO(bcmills): This seems dubious.
// Do we really support c-archive mode on js/wasm‽
return platform != "linux/ppc64"
case "c-shared":
switch platform {
case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/s390x",
"android/amd64", "android/arm", "android/arm64", "android/386",
"freebsd/amd64",
"darwin/amd64", "darwin/386",
"windows/amd64", "windows/386":
return true
}
return false
case "default":
return true
case "exe":
return true
case "pie":
switch platform {
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
"android/amd64", "android/arm", "android/arm64", "android/386",
"freebsd/amd64",
"darwin/amd64",
"aix/ppc64":
return true
}
return false
case "shared":
switch platform {
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
return true
}
return false
case "plugin":
switch platform {
case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/s390x", "linux/ppc64le",
"android/amd64", "android/arm", "android/arm64", "android/386",
"darwin/amd64",
"freebsd/amd64":
return true
}
return false
default:
return false
}
}

View file

@ -7,15 +7,38 @@
package main
import (
"fmt"
"internal/testenv"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
)
func getCCAndCCFLAGS(t *testing.T, env []string) (string, []string) {
goTool := testenv.GoToolPath(t)
cmd := exec.Command(goTool, "env", "CC")
cmd.Env = env
ccb, err := cmd.Output()
if err != nil {
t.Fatal(err)
}
cc := strings.TrimSpace(string(ccb))
cmd = exec.Command(goTool, "env", "GOGCCFLAGS")
cmd.Env = env
cflagsb, err := cmd.Output()
if err != nil {
t.Fatal(err)
}
cflags := strings.Fields(string(cflagsb))
return cc, cflags
}
var asmSource = `
.section .text1,"ax"
s1:
@ -61,21 +84,7 @@ func TestSectionsWithSameName(t *testing.T) {
}
goTool := testenv.GoToolPath(t)
cmd := exec.Command(goTool, "env", "CC")
cmd.Env = env
ccb, err := cmd.Output()
if err != nil {
t.Fatal(err)
}
cc := strings.TrimSpace(string(ccb))
cmd = exec.Command(goTool, "env", "GOGCCFLAGS")
cmd.Env = env
cflagsb, err := cmd.Output()
if err != nil {
t.Fatal(err)
}
cflags := strings.Fields(string(cflagsb))
cc, cflags := getCCAndCCFLAGS(t, env)
asmObj := filepath.Join(dir, "x.o")
t.Logf("%s %v -c -o %s %s", cc, cflags, asmObj, asmFile)
@ -102,7 +111,7 @@ func TestSectionsWithSameName(t *testing.T) {
t.Fatal(err)
}
cmd = exec.Command(goTool, "build")
cmd := exec.Command(goTool, "build")
cmd.Dir = dir
cmd.Env = env
t.Logf("%s build", goTool)
@ -111,3 +120,92 @@ func TestSectionsWithSameName(t *testing.T) {
t.Fatal(err)
}
}
var cSources35779 = []string{`
static int blah() { return 42; }
int Cfunc1() { return blah(); }
`, `
static int blah() { return 42; }
int Cfunc2() { return blah(); }
`,
}
// TestMinusRSymsWithSameName tests a corner case in the new
// loader. Prior to the fix this failed with the error 'loadelf:
// $WORK/b001/_pkg_.a(ldr.syso): duplicate symbol reference: blah in
// both main(.text) and main(.text)'. See issue #35779.
func TestMinusRSymsWithSameName(t *testing.T) {
testenv.MustHaveGoBuild(t)
testenv.MustHaveCGO(t)
t.Parallel()
// Skip this test on MIPS for the time being since it seems to trigger
// problems with unknown relocations.
if strings.Contains(runtime.GOARCH, "mips") {
testenv.SkipFlaky(t, 35779)
}
dir, err := ioutil.TempDir("", "go-link-TestMinusRSymsWithSameName")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
gopath := filepath.Join(dir, "GOPATH")
env := append(os.Environ(), "GOPATH="+gopath)
if err := ioutil.WriteFile(filepath.Join(dir, "go.mod"), []byte("module elf_test\n"), 0666); err != nil {
t.Fatal(err)
}
goTool := testenv.GoToolPath(t)
cc, cflags := getCCAndCCFLAGS(t, env)
objs := []string{}
csrcs := []string{}
for i, content := range cSources35779 {
csrcFile := filepath.Join(dir, fmt.Sprintf("x%d.c", i))
csrcs = append(csrcs, csrcFile)
if err := ioutil.WriteFile(csrcFile, []byte(content), 0444); err != nil {
t.Fatal(err)
}
obj := filepath.Join(dir, fmt.Sprintf("x%d.o", i))
objs = append(objs, obj)
t.Logf("%s %v -c -o %s %s", cc, cflags, obj, csrcFile)
if out, err := exec.Command(cc, append(cflags, "-c", "-o", obj, csrcFile)...).CombinedOutput(); err != nil {
t.Logf("%s", out)
t.Fatal(err)
}
}
sysoObj := filepath.Join(dir, "ldr.syso")
t.Logf("%s %v -nostdlib -r -o %s %v", cc, cflags, sysoObj, objs)
if out, err := exec.Command(cc, append(cflags, "-nostdlib", "-r", "-o", sysoObj, objs[0], objs[1])...).CombinedOutput(); err != nil {
t.Logf("%s", out)
t.Fatal(err)
}
cruft := [][]string{objs, csrcs}
for _, sl := range cruft {
for _, s := range sl {
if err := os.Remove(s); err != nil {
t.Fatal(err)
}
}
}
goFile := filepath.Join(dir, "main.go")
if err := ioutil.WriteFile(goFile, []byte(goSource), 0444); err != nil {
t.Fatal(err)
}
t.Logf("%s build", goTool)
cmd := exec.Command(goTool, "build")
cmd.Dir = dir
cmd.Env = env
if out, err := cmd.CombinedOutput(); err != nil {
t.Logf("%s", out)
t.Fatal(err)
}
}

View file

@ -462,6 +462,9 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) (found bool, ehdrFlags
// TODO: find a better place for this logic.
func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string, initEhdrFlags uint32) (textp []*sym.Symbol, ehdrFlags uint32, err error) {
localSymVersion := syms.IncVersion()
newSym := func(name string, version int) *sym.Symbol {
return l.Create(name, syms)
}
lookup := func(name string, version int) *sym.Symbol {
return l.LookupOrCreate(name, version, syms)
}
@ -758,7 +761,7 @@ func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pk
for i := 1; i < elfobj.nsymtab; i++ {
var elfsym ElfSym
if err := readelfsym(lookup, arch, elfobj, i, &elfsym, 1, localSymVersion); err != nil {
if err := readelfsym(newSym, lookup, arch, elfobj, i, &elfsym, 1, localSymVersion); err != nil {
return errorf("%s: malformed elf file: %v", pn, err)
}
symbols[i] = elfsym.sym
@ -929,7 +932,7 @@ func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pk
rp.Sym = nil
} else {
var elfsym ElfSym
if err := readelfsym(lookup, arch, elfobj, int(info>>32), &elfsym, 0, 0); err != nil {
if err := readelfsym(newSym, lookup, arch, elfobj, int(info>>32), &elfsym, 0, 0); err != nil {
return errorf("malformed elf file: %v", err)
}
elfsym.sym = symbols[info>>32]
@ -1006,7 +1009,7 @@ func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) {
return nil
}
func readelfsym(lookup func(string, int) *sym.Symbol, arch *sys.Arch, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int, localSymVersion int) (err error) {
func readelfsym(newSym, lookup func(string, int) *sym.Symbol, arch *sys.Arch, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int, localSymVersion int) (err error) {
if i >= elfobj.nsymtab || i < 0 {
err = fmt.Errorf("invalid elf symbol index")
return err
@ -1092,7 +1095,10 @@ func readelfsym(lookup func(string, int) *sym.Symbol, arch *sys.Arch, elfobj *El
// local names and hidden global names are unique
// and should only be referenced by their index, not name, so we
// don't bother to add them into the hash table
s = lookup(elfsym.name, localSymVersion)
// FIXME: pass empty string here for name? This would
// reduce mem use, but also (possibly) make it harder
// to debug problems.
s = newSym(elfsym.name, localSymVersion)
s.Attr |= sym.AttrVisibilityHidden
}

Some files were not shown because too many files have changed in this diff Show more