1

If I run a command similar to the following:

go build -mod=mod -o xyz.exe github.com/some/go/tool

And I'm in a directory with a go.mod, I noticed that the go.mod will be updated with a reference to github.com/some/go/tool, and xyz.exe will be built. So the go.mod being used is the one in the current directory.

However, if I change to some empty tmp folder with no go.mod, the build still succeeds and no go.mod is generated or updated.

My question is: in the latter case, what go.mod is used? Does go use the one from github.com/some/go/tool? And, is this documented somewhere?

craig65535
  • 3,439
  • 1
  • 23
  • 49
  • 1
    If there’s no go.mod to update, then nothing is updated. Building the binary is not using your go.mod, it is using the one from the main package’s module. The behavior for `-mod` with `build` is documented here https://go.dev/ref/mod#build-commands – JimB Jan 12 '23 at 00:57
  • @JimB thanks for the reply. Is it documented that `go build` will use the go.mod from the main package's module? All I can see in your link is "-mod=mod tells the go command to ignore the vendor directory and to automatically update go.mod, for example, when an imported package is not provided by any known module." and, earlier in the page, "The -mod=mod flag instructs the go command to attempt to find new modules providing missing packages and to update go.mod and go.sum." – craig65535 Jan 12 '23 at 01:18
  • It's at least implied that `go build` would use the `go.mod` from the main package if you're not working within another module, because that's the purpose of the `go.mod` file. The fact that `-mod=mod` is concerned with updating a `go.mod` file at all, means there's really no reason to consider it if you're only installing a binary from outside of a module. It's kind of a "why would you even do that?" sort of situation (not to mention `-mod=mod` would hardly ever be used in the first place) – JimB Jan 12 '23 at 13:42
  • I need `-mod=mod` here or it wouldn't even attempt to find the module: `no required module provides package github.com/some/go/tool: go.mod file not found in current directory or any parent directory; see 'go help modules'`. This is the "instructs the go command to attempt to find new modules providing missing packages" part of the behaviour documented for `-mod=mod`. – craig65535 Jan 12 '23 at 18:20
  • That's because you don't use `build` to compile a binary outside of a module, you use `install`. The only way to compile an external binary with any special flags or module directives is to checkout the source and run the `go` tool from within _that_ module. – JimB Jan 12 '23 at 20:55
  • Are you saying this isn't a supported use case? Because it does work, and it does use all of the `GO*` environment variables and all of the `go build` flags I pass to it. I don't want the extra installation side-effects of `go install`. – craig65535 Jan 12 '23 at 21:17
  • To be clear, I'm happy with how well this works. I just want to reconcile this with what the documentation says (or doesn't say, in this case). – craig65535 Jan 12 '23 at 21:19
  • 1
    I was surprised that adding `-mod=mod` makes it work at all, you may have found a bug which tricks the cli into thinking it's in a module when it's not. The `build` tool documentation has never shown any use case like this, and `install` is the documented way to download and build a binary directly. – JimB Jan 12 '23 at 21:21

2 Answers2

3

When you run the command go build -mod=mod -o xyz.exe github.com/some/go/tool in a directory with an existing go.mod file, Go will use the go.mod in the current directory, and any new dependencies added as a result of building the github.com/some/go/tool package will be added to that go.mod file.

However, when you run the command in a directory without a go.mod file, Go will still be able to build the package, but it will not create or update a go.mod file in the current directory.

When Go is building a package that is not in the current module (the module defined by the current directory's go.mod), it will use the go.mod file of the package that you are building if present. In this case github.com/some/go/tool should have it's own go.mod file and it will be used when building and resolving the dependencies.

This behavior of Go is specified in the go help build documentation, under the section "Modules" specifically.

https://golang.org/cmd/go/#hdr-Modules__module_versions__and_more

Lab210
  • 66
  • 3
1

let's take a look at what go.mod does:

Take windows-os as an example:

go mod file like:

module xxx

go 1.19

require github.com/mitchellh/mapstructure v1.5.0

if you run

go build -mod=mod  xxx

it will be download mapstructure in C:\Users\{username}\go\pkg\mod\github.com\mitchellh\mapstructure@v1.5.0

Next, if you delete the go.mod, \go\pkg\...\mapstructure still exists.

go will look up \go\pkg\ and go Root, when go run/build.

so it can build/run even there is no go.mod

if delete \go\pkg\...\mapstructure in local, it will can't run/build

go mod can build consistently in different environments(different pc/os).and deal different version and package dependencies

Para
  • 1,299
  • 4
  • 11