Skip to content

Commit fa093af

Browse files
author
Bryan C. Mills
committed
_content/ref/mod: document Go 1.17 lazy loading and module graph pruning
For golang/go#36460 Change-Id: I36b3657103f069412b225356d011a19c1a10109e Reviewed-on: https://go-review.googlesource.com/c/website/+/333629 Trust: Bryan C. Mills <[email protected]> Run-TryBot: Bryan C. Mills <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Jay Conrod <[email protected]> Reviewed-by: Michael Matloob <[email protected]>
1 parent 11adafe commit fa093af

File tree

1 file changed

+153
-22
lines changed

1 file changed

+153
-22
lines changed

_content/ref/mod.md

+153-22
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,13 @@ specified by the `go` directive. This has the following effects:
564564
[`go mod vendor`](#go-mod-vendor) since modules were introduced. In lower
565565
versions, `all` also includes tests of packages imported by packages in
566566
the main module, tests of those packages, and so on.
567+
* At `go 1.17` or higher, the `go.mod` file includes an explicit [`require`
568+
directive](#go-mod-file-require) for each module that provides any package
569+
transitively imported by a package or test in the main module. (At `go 1.16`
570+
and lower, an [indirect dependency](#glos-direct-dependency) is included only
571+
if [minimal version selection](#minimal-version-selection) would otherwise
572+
select a different version.) This extra information enables [lazy
573+
loading](#lazy-loading) and [module graph pruning](#graph-pruning).
567574

568575
A `go.mod` file may contain at most one `go` directive. Most commands will add a
569576
`go` directive with the current Go version if one is not present.
@@ -590,14 +597,22 @@ the [build list](#glos-build-list).
590597

591598
The `go` command automatically adds `// indirect` comments for some
592599
requirements. An `// indirect` comment indicates that no package from the
593-
required module is directly imported by any package in the main module.
594-
The `go` command adds an indirect requirement when the selected version of a
595-
module is higher than what is already implied (transitively) by the main
596-
module's other dependencies. That may occur because of an explicit upgrade
597-
(`go get -u`), removal of some other dependency that previously imposed the
598-
requirement (`go mod tidy`), or a dependency that imports a package without
599-
a corresponding requirement in its own `go.mod` file (such as a dependency
600-
that lacks a `go.mod` file altogether).
600+
required module is directly imported by any package in the [main
601+
module](#glos-main-module).
602+
603+
If the [`go` directive](#go-mod-file-go) specifies `go 1.16` or lower, the `go`
604+
command adds an indirect requirement when the selected version of a module is
605+
higher than what is already implied (transitively) by the main module's other
606+
dependencies. That may occur because of an explicit upgrade (`go get -u ./...`),
607+
removal of some other dependency that previously imposed the requirement (`go
608+
mod tidy`), or a dependency that imports a package without a corresponding
609+
requirement in its own `go.mod` file (such as a dependency that lacks a `go.mod`
610+
file altogether).
611+
612+
At `go 1.17` and above, the `go` command adds an indirect requirement for each
613+
module that provides a package transitively imported by any package or test in
614+
the main module. These extra requirements enable [lazy loading](#lazy-loading)
615+
and [module graph pruning](#graph-pruning).
601616

602617
```
603618
RequireDirective = "require" ( RequireSpec | "(" newline { RequireSpec } ")" newline ) .
@@ -964,6 +979,89 @@ is changed to 1.1.
964979
suffix after an argument. This works similarly to a downgrade. All versions
965980
of the named module are removed from the module graph.
966981

982+
## Module graph redundancy {#graph-redundancy}
983+
984+
In a module with a [`go` directive](#go-mod-file-go) at `go 1.17` or higher, the
985+
`go.mod` file is expected to include an explicit [`require`
986+
directive](#go-mod-file-require) to the `go.mod` file for the [selected
987+
version](#glos-selected-version) of every module that provides any package
988+
imported (even [indirectly](#glos-indirect-dependency)) by a package or test in
989+
the [main module](#glos-main-module).
990+
991+
When the `go` command loads packages it makes a best effort to check and
992+
maintain this property: [`go mod tidy`](#go-mod-tidy) adds indirect requirements
993+
for all packages imported by the main module, and [`go get`](#go-get) adds
994+
indirect requirements for the packages imported by those named on the command
995+
line.
996+
997+
A module that _does not_ provide any imported package cannot affect the compiled
998+
artifacts produced by `go build` and `go test`, so this added redundancy allows
999+
packages in the main module to be built and tested using only the requirements
1000+
listed in the its own `go.mod` file. The `go` command takes advantage of that
1001+
property to substantially reduce the size of the overall module graph.
1002+
1003+
(At `go 1.16` and below, the `go.mod` file includes only [direct
1004+
dependencies](#glos-direct-dependency), so a much larger graph must be loaded to
1005+
ensure that all indirect dependencies are included.)
1006+
1007+
See [the design document](/design/36460-lazy-module-loading) for more detail.
1008+
1009+
### Lazy loading {#lazy-loading}
1010+
1011+
If the main module is at `go 1.17` or higher, the `go` command avoids loading
1012+
the complete module graph until (and unless) it is needed. Instead, it loads
1013+
only the main module's `go.mod` file, then attempts to load the packages to be
1014+
built using only those requirements. If a package to be imported (for example, a
1015+
dependency of a test for a package outside the main module) is not found among
1016+
those requirements, then the rest of the module graph is loaded on demand.
1017+
1018+
If all packages can be found without loading the full module graph, the `go`
1019+
command then loads the `go.mod` files for _only_ the modules containing those
1020+
packages, and their requirements are checked against the requirements of the
1021+
main module to ensure that they are locally consistent. (Inconsistencies can
1022+
arise due to version-control merges, hand-edits, and changes in modules that
1023+
have been [replaced](#go-mod-file-replace) using local filesystem paths.)
1024+
1025+
### Module graph pruning {#graph-pruning}
1026+
1027+
If the main module is at `go 1.17` or higher, the [module
1028+
graph](#glos-module-graph) used for [minimal version
1029+
selection](#minimal-version-selection) includes only the _immediate_ (not
1030+
transitive) requirements for each module dependency that specifies `go 1.17` or
1031+
higher in its own `go.mod` file, unless that version of the module is also
1032+
(transitively) required by some _other_ dependency at `go 1.16` or below.
1033+
1034+
Since a `go 1.17` `go.mod` file includes every dependency needed to build any
1035+
package or test in that module, the pruned module graph includes every
1036+
dependency needed to `go build` or `go test` the packages in every dependency
1037+
explicitly [required](#go-mod-file-require) by the main module.
1038+
1039+
Modules whose requirements have been pruned out still appear in the module graph
1040+
and are still reported by `go list -m all`: their [selected
1041+
versions](#glos-selected-version) are known and well-defined, and packages can
1042+
be loaded from those modules (for example, as transitive dependencies of tests
1043+
loaded from other modules). However, since the `go` command cannot easily
1044+
identify which dependencies of these modules are satisfied, the arguments to `go
1045+
build` and `go test` cannot include packages from modules whose requirements
1046+
have been pruned out. [`go get`](#go-get) promotes the module containing each
1047+
named package to an explicit dependency, allowing `go build` or `go test` to be
1048+
invoked on that package.
1049+
1050+
Because Go 1.16 and earlier did not support module graph pruning, the full
1051+
transitive closure of dependencies — including transitive `go 1.17` dependencies
1052+
— is still included for each module that specifies `go 1.16` or lower. (The
1053+
`go.mod` file for a `go 1.16` or lower module does not necessarily include the
1054+
requirements needed to build the packages and tests in that module.)
1055+
1056+
The [`go.sum` file](#go-sum-files) recorded by [`go mod tidy`](#go-mod-tidy) for
1057+
a module by default includes checksums needed by the Go version _one below_ the
1058+
version specified in its [`go` directive](#go-mod-file-go). So a `go 1.17`
1059+
module includes checksums needed for the full module graph loaded by Go 1.16,
1060+
but a `go 1.18` module will include only the checksums needed for the pruned
1061+
module graph loaded by Go 1.17. The `-compat` flag can be used to override the
1062+
default version (for example, to prune the `go.sum` file more aggressively in a
1063+
`go 1.17` module).
1064+
9671065
## Compatibility with non-module repositories {#non-module-compat}
9681066

9691067
To ensure a smooth transition from `GOPATH` to modules, the `go` command can
@@ -1704,7 +1802,7 @@ to parse, edit, and format `go.mod` files.
17041802
Usage:
17051803

17061804
```
1707-
go mod graph
1805+
go mod graph [-go=version]
17081806
```
17091807

17101808
The `go mod graph` command prints the [module requirement
@@ -1729,6 +1827,10 @@ space-separated fields: a module version and one of its dependencies. Each
17291827
module version is identified as a string of the form `path@version`. The main
17301828
module has no `@version` suffix, since it has no version.
17311829

1830+
The `-go` flag causes `go mod graph` to report the module graph as
1831+
loaded by the given Go version, instead of the version indicated by
1832+
the [`go` directive](#go-mod-file-go) in the `go.mod` file.
1833+
17321834
See [Minimal version selection (MVS)](#minimal-version-selection) for more
17331835
information on how versions are chosen. See also [`go list -m`](#go-list-m) for
17341836
printing selected versions and [`go mod why`](#go-mod-why) for understanding
@@ -1786,7 +1888,7 @@ requirements and to drop unused requirements.
17861888
Usage:
17871889

17881890
```
1789-
go mod tidy [-e] [-v]
1891+
go mod tidy [-e] [-v] [-go=version] [-compat=version]
17901892
```
17911893

17921894
`go mod tidy` ensures that the `go.mod` file matches the source code in the
@@ -1814,20 +1916,30 @@ with names that start with `.` or `_` unless those packages are explicitly
18141916
imported by other packages.
18151917

18161918
Once `go mod tidy` has loaded this set of packages, it ensures that each module
1817-
that provides one or more packages either has a `require` directive in the main
1818-
module's `go.mod` file or is required by another required module. `go mod tidy`
1819-
will add a requirement on the latest version on each missing module (see
1820-
[Version queries](#version-queries) for the definition of the `latest`
1821-
version). `go mod tidy` will remove `require` directives for modules that don't
1822-
provide any packages in the set described above.
1919+
that provides one or more packages has a `require` directive in the main
1920+
module's `go.mod` file or, if the main module is at `go 1.16` or below (see
1921+
[Module graph redundancy](#graph-redundancy)), is required by another required
1922+
module. `go mod tidy` will add a requirement on the latest version on each
1923+
missing module (see [Version queries](#version-queries) for the definition of
1924+
the `latest` version). `go mod tidy` will remove `require` directives for
1925+
modules that don't provide any packages in the set described above.
18231926

18241927
`go mod tidy` may also add or remove `// indirect` comments on `require`
1825-
directives. An `// indirect` comment denotes a module that does not provide
1826-
packages imported by packages in the main module. These requirements will be
1827-
present if the module that imports packages in the indirect dependency has
1828-
no `go.mod` file. They may also be present if the indirect dependency is
1829-
required at a higher version than is implied by the module graph; this usually
1830-
happens after running a command like `go get -u ./...`.
1928+
directives. An `// indirect` comment denotes a module that does not provide a
1929+
package imported by a package in the main module. (See the [`require`
1930+
directive](#go-mod-file-require) for more detail on when `// indirect`
1931+
dependencies and comments are added.)
1932+
1933+
If the `-go` flag is set, `go mod tidy` will update the [`go`
1934+
directive](#go-mod-file-go) to the indicated version, enabling or disabling
1935+
[lazy loading](#lazy-loading) and [module graph pruning](#graph-pruning) (and
1936+
adding or removing indirect requirements as needed) according to that version.
1937+
1938+
By default, `go mod tidy` will check that the [selected
1939+
versions](#glos-selected-version) of modules do not change when the module graph
1940+
is loaded by the Go version immediately preceding the version indicated in the
1941+
`go` directive. The versioned checked for compatibility can also be specified
1942+
explicitly via the `-compat` flag.
18311943

18321944
### `go mod vendor` {#go-mod-vendor}
18331945

@@ -3887,6 +3999,12 @@ A deprecated module is marked with a [deprecation
38873999
comment](#go-mod-file-module-deprecation) in the latest version of its
38884000
[`go.mod` file](#glos-go-mod-file).
38894001

4002+
<a id="glos-direct-dependency"></a>
4003+
**direct dependency:** A package whose path appears in an [`import`
4004+
declaration](/ref/spec#import_declarations) in a `.go` source file for a package
4005+
or test in the [main module](#glos-main-module), or the module containing such a
4006+
package. (Compare [indirect dependency](#glos-indirect-dependency).)
4007+
38904008
<a id="glos-direct-mode"></a>
38914009
**direct mode:** A setting of [environment variables](#environment-variables)
38924010
that causes the `go` command to download a module directly from a [version
@@ -3904,6 +4022,14 @@ files](#go-mod-file).
39044022
**import path:** A string used to import a package in a Go source file.
39054023
Synonymous with [package path](#glos-package-path).
39064024

4025+
<a id="glos-indirect-dependency"></a>
4026+
**indirect dependency:** A package transitively imported by a package or test in
4027+
the [main module](#glos-main-module), but whose path does not appear in any
4028+
[`import` declaration](/ref/spec#import_declarations) in the main module;
4029+
or a module that appears in the [module graph](#glos-module-graph) but does not
4030+
provide any package directly imported by the main module.
4031+
(Compare [direct dependency](#glos-direct-dependency).)
4032+
39074033
<a id="glos-main-module"></a>
39084034
**main module:** The module in which the `go` command is invoked. The main
39094035
module is defined by a [`go.mod` file](#glos-go-mod-file) in the current
@@ -4030,6 +4156,11 @@ after it was published. See [`retract` directive](#go-mod-file-retract).
40304156
[version](#glos-version) to a specific revision. See [Mapping versions to
40314157
commits](#vcs-version).
40324158

4159+
<a id="glos-selected-version"></a>
4160+
**selected version:** The version of a given module chosen by [minimal version
4161+
selection](#minimal-version-selection). The selected version is the highest
4162+
version for the module's path found in the [module graph](#glos-module-graph).
4163+
40334164
<a id="glos-vendor-directory"></a>
40344165
**vendor directory:** A directory named `vendor` that contains packages from
40354166
other modules needed to build packages in the main module. Maintained with

0 commit comments

Comments
 (0)