Merge pull request #385 from elezar/migrate-github-go-nvlib

Use github.com/NVIDIA/go-nvlib
This commit is contained in:
Evan Lezar 2024-02-29 10:33:38 +02:00 committed by GitHub
commit 37b1e37c8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
57 changed files with 2373 additions and 652 deletions

View File

@ -20,10 +20,11 @@ import (
"fmt"
"path/filepath"
"github.com/NVIDIA/go-nvlib/pkg/nvpci"
"github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/devices"
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
"github.com/NVIDIA/nvidia-container-toolkit/internal/nvcaps"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvpci"
)
type allPossible struct {

2
go.mod
View File

@ -3,6 +3,7 @@ module github.com/NVIDIA/nvidia-container-toolkit
go 1.20
require (
github.com/NVIDIA/go-nvlib v0.0.0-20231115170030-b21432a353e1
github.com/NVIDIA/go-nvml v0.12.0-2
github.com/fsnotify/fsnotify v1.7.0
github.com/opencontainers/runtime-spec v1.2.0
@ -10,7 +11,6 @@ require (
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.8.4
github.com/urfave/cli/v2 v2.27.1
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20230818092907-09424fdc8884
golang.org/x/mod v0.15.0
golang.org/x/sys v0.17.0
tags.cncf.io/container-device-interface v0.6.2

4
go.sum
View File

@ -1,3 +1,5 @@
github.com/NVIDIA/go-nvlib v0.0.0-20231115170030-b21432a353e1 h1:A+2GAIeZkdID7Jc/aSJ1dq42eippP5uHvRMgO8eN3aM=
github.com/NVIDIA/go-nvlib v0.0.0-20231115170030-b21432a353e1/go.mod h1:HPFNPAYqQeoos58MKUboWsdZMu71EzSQrbmd+QBRD40=
github.com/NVIDIA/go-nvml v0.12.0-2 h1:Sg239yy7jmopu/cuvYauoMj9fOpcGMngxVxxS1EBXeY=
github.com/NVIDIA/go-nvml v0.12.0-2/go.mod h1:7ruy85eOM73muOc/I37euONSwEyFqZsv5ED9AogD4G0=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
@ -69,8 +71,6 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20230818092907-09424fdc8884 h1:V0LUbfm4kVA1CPG8FgG9AGZqa3ykE5U12Gd3PZgoItA=
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20230818092907-09424fdc8884/go.mod h1:/x5Ky1ZJNyCjDkgSL1atII0EFKQF5WaIHKeP5nkaQfk=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View File

@ -20,9 +20,9 @@ import (
"fmt"
"strings"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/info"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/device"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/info"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
)
// additionalInfo allows for the info.Interface to be extened to implement the infoInterface.

View File

@ -19,9 +19,9 @@ package info
import (
"testing"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/device"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
"github.com/stretchr/testify/require"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
)
func TestUsesNVGPUModule(t *testing.T) {

View File

@ -17,9 +17,9 @@
package info
import (
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/info"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/device"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/info"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
cdi "tags.cncf.io/container-device-interface/pkg/parser"
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"

View File

@ -17,7 +17,7 @@
package nvcdi
import (
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/device"
"tags.cncf.io/container-device-interface/pkg/cdi"
"tags.cncf.io/container-device-interface/specs-go"

View File

@ -23,7 +23,7 @@ import (
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
)
// newCommonNVMLDiscoverer returns a discoverer for entities that are not associated with a specific CDI device.

View File

@ -22,12 +22,13 @@ import (
"path/filepath"
"strings"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
"golang.org/x/sys/unix"
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/cuda"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
"golang.org/x/sys/unix"
)
// NewDriverDiscoverer creates a discoverer for the libraries and binaries associated with a driver installation.

View File

@ -22,8 +22,8 @@ import (
"path/filepath"
"strings"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/device"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
"tags.cncf.io/container-device-interface/pkg/cdi"
"tags.cncf.io/container-device-interface/specs-go"

View File

@ -19,7 +19,7 @@ package nvcdi
import (
"fmt"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/device"
"tags.cncf.io/container-device-interface/pkg/cdi"
"tags.cncf.io/container-device-interface/specs-go"

View File

@ -19,7 +19,7 @@ package nvcdi
import (
"fmt"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/device"
"tags.cncf.io/container-device-interface/pkg/cdi"
"tags.cncf.io/container-device-interface/specs-go"

View File

@ -19,8 +19,8 @@ package nvcdi
import (
"fmt"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/device"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
"tags.cncf.io/container-device-interface/pkg/cdi"
"tags.cncf.io/container-device-interface/specs-go"

View File

@ -19,7 +19,7 @@ package nvcdi
import (
"fmt"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/device"
"tags.cncf.io/container-device-interface/pkg/cdi"
"tags.cncf.io/container-device-interface/specs-go"

View File

@ -19,13 +19,14 @@ package nvcdi
import (
"fmt"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/device"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/info"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
"github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv"
"github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec"
"github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/info"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
)
type wrapper struct {

View File

@ -21,7 +21,7 @@ import (
"path/filepath"
"strings"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/device"
"tags.cncf.io/container-device-interface/pkg/cdi"
"tags.cncf.io/container-device-interface/specs-go"

View File

@ -19,8 +19,8 @@ package nvcdi
import (
"fmt"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/device"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
"tags.cncf.io/container-device-interface/pkg/cdi"
"tags.cncf.io/container-device-interface/specs-go"

View File

@ -19,7 +19,7 @@ package nvcdi
import (
"fmt"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
"github.com/NVIDIA/go-nvlib/pkg/nvlib/device"
"tags.cncf.io/container-device-interface/pkg/cdi"
"tags.cncf.io/container-device-interface/specs-go"

View File

@ -20,7 +20,7 @@ import (
"errors"
"fmt"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
)
// UUIDer is an interface for getting UUIDs.

View File

@ -4,7 +4,7 @@
package nvcdi
import (
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
"sync"
)

View File

@ -19,8 +19,8 @@ package nvcdi
import (
"testing"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
"github.com/stretchr/testify/require"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
)
func TestConvert(t *testing.T) {

View File

@ -17,10 +17,11 @@
package nvcdi
import (
"github.com/NVIDIA/go-nvlib/pkg/nvlib/device"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
"github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
)
// Option is a function that configures the nvcdilib

View File

@ -17,7 +17,7 @@
package device
import (
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
)
// Interface provides the API to the 'device' package

View File

@ -19,8 +19,7 @@ package device
import (
"fmt"
"github.com/NVIDIA/go-nvml/pkg/dl"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
)
// Device defines the set of extended functions associated with a device.Device
@ -152,8 +151,7 @@ func (d *device) GetCudaComputeCapabilityAsString() (string, error) {
// IsMigCapable checks if a device is capable of having MIG paprtitions created on it
func (d *device) IsMigCapable() (bool, error) {
err := d.lib.nvmlLookupSymbol("nvmlDeviceGetMigMode")
if err != nil {
if !d.lib.hasSymbol("nvmlDeviceGetMigMode") {
return false, nil
}
@ -170,8 +168,7 @@ func (d *device) IsMigCapable() (bool, error) {
// IsMigEnabled checks if a device has MIG mode currently enabled on it
func (d *device) IsMigEnabled() (bool, error) {
err := d.lib.nvmlLookupSymbol("nvmlDeviceGetMigMode")
if err != nil {
if !d.lib.hasSymbol("nvmlDeviceGetMigMode") {
return false, nil
}
@ -465,22 +462,12 @@ func (d *devicelib) GetMigProfiles() ([]MigProfile, error) {
return profiles, nil
}
// nvmlLookupSymbol checks to see if the given symbol is present in the NVML library
func (d *devicelib) nvmlLookupSymbol(symbol string) error {
// If devicelib is configured to not verify symbols, then we short-circuit here
// hasSymbol checks to see if the given symbol is present in the NVML library.
// If devicelib is configured to not verify symbols, then all symbols are assumed to exist.
func (d *devicelib) hasSymbol(symbol string) bool {
if !*d.verifySymbols {
return nil
return true
}
// Otherwise we lookup the provided symbol and verify it is available
lib := dl.New("libnvidia-ml.so.1", dl.RTLD_LAZY|dl.RTLD_GLOBAL)
if lib == nil {
return fmt.Errorf("error instantiating DynamicLibrary for NVML")
}
err := lib.Open()
if err != nil {
return fmt.Errorf("error opening DynamicLibrary for NVML: %v", err)
}
defer lib.Close()
return lib.Lookup(symbol)
return d.nvml.Lookup(symbol) == nil
}

View File

@ -19,7 +19,7 @@ package device
import (
"fmt"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
)
// MigDevice defines the set of extended functions associated with a MIG device

View File

@ -23,7 +23,7 @@ import (
"strconv"
"strings"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
"github.com/NVIDIA/go-nvlib/pkg/nvml"
)
const (

View File

@ -30,10 +30,27 @@ type nvmlLib struct {
var _ Interface = (*nvmlLib)(nil)
// New creates a new instance of the NVML Interface
func New() Interface {
func New(opts ...Option) Interface {
o := &options{}
for _, opt := range opts {
opt(o)
}
var nvmlOptions []nvml.LibraryOption
if o.libraryPath != "" {
nvmlOptions = append(nvmlOptions, nvml.WithLibraryPath(o.libraryPath))
}
nvml.SetLibraryOptions(nvmlOptions...)
return &nvmlLib{}
}
// Lookup checks whether the specified symbol exists in the configured NVML library.
func (n *nvmlLib) Lookup(name string) error {
// TODO: For now we rely on the default NVML library and perform the lookups against this.
return nvml.GetLibrary().Lookup(name)
}
// Init initializes an NVML Interface
func (n *nvmlLib) Init() Return {
ret := nvml.Init()

View File

@ -35,6 +35,9 @@ var _ Interface = &InterfaceMock{}
// InitFunc: func() Return {
// panic("mock out the Init method")
// },
// LookupFunc: func(s string) error {
// panic("mock out the Lookup method")
// },
// ShutdownFunc: func() Return {
// panic("mock out the Shutdown method")
// },
@ -69,6 +72,9 @@ type InterfaceMock struct {
// InitFunc mocks the Init method.
InitFunc func() Return
// LookupFunc mocks the Lookup method.
LookupFunc func(s string) error
// ShutdownFunc mocks the Shutdown method.
ShutdownFunc func() Return
@ -104,6 +110,11 @@ type InterfaceMock struct {
// Init holds details about calls to the Init method.
Init []struct {
}
// Lookup holds details about calls to the Lookup method.
Lookup []struct {
// S is the s argument value.
S string
}
// Shutdown holds details about calls to the Shutdown method.
Shutdown []struct {
}
@ -120,6 +131,7 @@ type InterfaceMock struct {
lockErrorString sync.RWMutex
lockEventSetCreate sync.RWMutex
lockInit sync.RWMutex
lockLookup sync.RWMutex
lockShutdown sync.RWMutex
lockSystemGetCudaDriverVersion sync.RWMutex
lockSystemGetDriverVersion sync.RWMutex
@ -302,6 +314,38 @@ func (mock *InterfaceMock) InitCalls() []struct {
return calls
}
// Lookup calls LookupFunc.
func (mock *InterfaceMock) Lookup(s string) error {
if mock.LookupFunc == nil {
panic("InterfaceMock.LookupFunc: method is nil but Interface.Lookup was just called")
}
callInfo := struct {
S string
}{
S: s,
}
mock.lockLookup.Lock()
mock.calls.Lookup = append(mock.calls.Lookup, callInfo)
mock.lockLookup.Unlock()
return mock.LookupFunc(s)
}
// LookupCalls gets all the calls that were made to Lookup.
// Check the length with:
//
// len(mockedInterface.LookupCalls())
func (mock *InterfaceMock) LookupCalls() []struct {
S string
} {
var calls []struct {
S string
}
mock.lockLookup.RLock()
calls = mock.calls.Lookup
mock.lockLookup.RUnlock()
return calls
}
// Shutdown calls ShutdownFunc.
func (mock *InterfaceMock) Shutdown() Return {
if mock.ShutdownFunc == nil {

32
vendor/github.com/NVIDIA/go-nvlib/pkg/nvml/options.go generated vendored Normal file
View File

@ -0,0 +1,32 @@
/**
# Copyright 2023 NVIDIA CORPORATION
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
**/
package nvml
// options represents the options that could be passed to the nvml contructor.
type options struct {
libraryPath string
}
// Option represents a functional option to control behaviour.
type Option func(*options)
// WithLibraryPath sets the NVML library name to use.
func WithLibraryPath(libraryPath string) Option {
return func(o *options) {
o.libraryPath = libraryPath
}
}

View File

@ -30,6 +30,7 @@ type Interface interface {
ErrorString(r Return) string
EventSetCreate() (EventSet, Return)
Init() Return
Lookup(string) error
Shutdown() Return
SystemGetCudaDriverVersion() (int, Return)
SystemGetDriverVersion() (string, Return)

View File

@ -20,7 +20,7 @@ import (
"fmt"
"os"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvpci/bytes"
"github.com/NVIDIA/go-nvlib/pkg/nvpci/bytes"
)
const (

View File

@ -22,7 +22,7 @@ import (
"syscall"
"unsafe"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvpci/bytes"
"github.com/NVIDIA/go-nvlib/pkg/nvpci/bytes"
)
// Mmio memory map a region

View File

@ -19,7 +19,7 @@ package mmio
import (
"fmt"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvpci/bytes"
"github.com/NVIDIA/go-nvlib/pkg/nvpci/bytes"
)
type mockMmio struct {

View File

@ -21,7 +21,7 @@ import (
"os"
"path/filepath"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvpci/bytes"
"github.com/NVIDIA/go-nvlib/pkg/nvpci/bytes"
)
// MockNvpci mock pci device

View File

@ -25,7 +25,7 @@ import (
"strconv"
"strings"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/pciids"
"github.com/NVIDIA/go-nvlib/pkg/pciids"
)
const (

View File

@ -20,7 +20,7 @@ import (
"fmt"
"sort"
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvpci/mmio"
"github.com/NVIDIA/go-nvlib/pkg/nvpci/mmio"
)
const (

View File

@ -182,6 +182,7 @@ var defaultPCIdbPaths = []string{
}
// This is a fallback if all of the locations fail
//
//go:embed default_pci.ids
var defaultPCIdb []byte

18
vendor/modules.txt vendored
View File

@ -1,3 +1,12 @@
# github.com/NVIDIA/go-nvlib v0.0.0-20231115170030-b21432a353e1
## explicit; go 1.20
github.com/NVIDIA/go-nvlib/pkg/nvlib/device
github.com/NVIDIA/go-nvlib/pkg/nvlib/info
github.com/NVIDIA/go-nvlib/pkg/nvml
github.com/NVIDIA/go-nvlib/pkg/nvpci
github.com/NVIDIA/go-nvlib/pkg/nvpci/bytes
github.com/NVIDIA/go-nvlib/pkg/nvpci/mmio
github.com/NVIDIA/go-nvlib/pkg/pciids
# github.com/NVIDIA/go-nvml v0.12.0-2
## explicit; go 1.15
github.com/NVIDIA/go-nvml/pkg/dl
@ -53,15 +62,6 @@ github.com/urfave/cli/v2
# github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673
## explicit
github.com/xrash/smetrics
# gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20230818092907-09424fdc8884
## explicit; go 1.20
gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device
gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/info
gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml
gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvpci
gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvpci/bytes
gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvpci/mmio
gitlab.com/nvidia/cloud-native/go-nvlib/pkg/pciids
# golang.org/x/mod v0.15.0
## explicit; go 1.18
golang.org/x/mod/semver