golang / vscode-go

Go extension for Visual Studio Code
https://marketplace.visualstudio.com/items?itemName=golang.Go
Other
3.87k stars 751 forks source link

document (unfortunate) relationship between [go,gopls].buildFlags and go.lintFlags (was ["-mod=mod"] doesn't seem to work) #2932

Open aathan opened 1 year ago

aathan commented 1 year ago

What version of Go, VS Code & VS Code Go extension are you using?

Version Information
* Run `go version` to get version of Go from _the VS Code integrated terminal_. - go version go1.19.3 linux/amd64 * Run `gopls -v version` to get version of Gopls from _the VS Code integrated terminal_. - golang.org/x/tools/gopls@v0.13.1 h1:Q0cfPbEG1WVfgxcRZ9uKTA6/ckIRNXx6Ym7KgT/VFE4= * Run `code -v` or `code-insiders -v` to get version of VS Code or VS Code Insiders. - 1.80.2 2ccd690cbff1569e4a83d7c43d45101f817401dc x64 * Check your installed extensions to get the version of the VS Code Go extension - v0.39.1

Share the Go related settings you have added/edited

"gopls.buildFlags": [
    "-mod=mod"
],
"go.buildFlags": [
    "-mod=mod"
]

Describe the bug

"undefined: xyz (compile)" shows up for symbols that are defined but only if you need to compile with -mod=mod, despite having properly set the flag in buildFlags

Steps to reproduce the behavior:

in go.mod, use a module from github (e.g. gopkg.in/yaml.v3). go mod vendor (not sure if vendoring is the problem) Also, set a replace => for that module, to a local git clone. Add a public function in your local git clone Use/reference that function in the project that has the replace for that module... Observe that if you leave out the gopls.buildFlags, you get red warnings about unknown functions etc. Set the gopls.buildFlags and reload the window Observe that after reloading the window, no red warnings exist about the unknown function (i.e., the -mod=mod took effect) Now, Command-S (save) the file. Observe that "undefined: yaml.Xyz() (compile)" warning in yellow appears, despite having the go.buildFlags="-mod=mod"

EDIT: I should mention, compiling on the command line with -mod=mod works. I.e., the code and go.mod etc is in fact correct, and correctly compiles vs the local git repo clone. The vscode warning seems to be based on a compile that does not reference the right version of the foreign mod.

Screenshots or recordings

If applicable, add screenshots or recordings to help explain your problem.

aathan commented 1 year ago

It looks like this is solved by:

    "go.lintFlags": [
        "-mod=mod"
    ]

I'm leaving this open because well, it seems like there should be some link between these settings and/or at least some mention of the lintFlags where the relationship between the other buildFlags are described?

Also, maybe instead of (compile) it should say (linter) ?

jamalc commented 1 year ago

What problem do you want to solve by setting this flag?

aathan commented 1 year ago

As described, the problem I'm trying to solve is to get correct editor error/lint/etc messages when a project requires the -mod=mod flag to build. If you're unfamiliar: There are cases when you are working in a mod vendor'ed project, but need to debug an external module. In that case, you may use the go.mod "replace xyz => xyzfeature to point a given module to your local git clone of that project, that you're fixing bugs in. Since the main project is vendor'ed, you need to supply-mod=modflag togo buildetc in order to have it *in fact* use your local copy, even though thereplace ...` exists in that project go.mod.

What I've found is that there are at least three places (as described above) where the same flags have to be provided, and I may just have found a fourth: Namely, here when I'm using the vscode debugger, I think it's using the vendor'ed module again instead of the -mod=mod one, so there must be yet another place I have to go search for to set this flag.

Shouldn't there be a single setting for these flags, with these individual breakout settings used only if they're specified, so that users don't have to set 3-4 things to the same value? The current situation makes it a pain to switch back and forth between -mod=mod and normal mode...

aathan commented 1 year ago

EDIT: I'm leaving this open in case others run into this problem, but i looks like the supported launch.json flags for the dlv-dap adapter are in fact documented (here) and buildFlags is a supported key in launch.json.

Please also see: https://github.com/go-delve/delve/issues/3462

I'm not sure how/if the go vscode extension is involved in what is allowed or how to specify launch.json entries relevant to the debuggering, but it seems that I cannot successfully pas dlvFlags to the remote dlv dap instance so as to build/launch using -mod=mod

hyangah commented 1 year ago

Different lint tools have different flags. So, we cannot plumb all go.buildFlags mechanically to lint tools. Alternative I think is setting GOFLAGS env var.

However, the -mod flag is one of the flags gopls controls internally to avoid extraneous network access (gopls runs go commands so frequently), so I wouldn't be surprised if gopls doesn't handle the case.

Have you tried to remove the vendor directory instead of trying to set -mod=mod? Once go mod tidy runs after updating go.mod, -mod=readonly (the default when no vendor directory is present) and the replace rules will apply as you expect and most of the tools will work as expected. You can also regenerate the vendor easily by running go mod vendor.

aathan commented 1 year ago

I understand. Please consider the following points:

aathan commented 1 year ago

For anyone arriving here searching for how to make -mod=mod work well in vscode, also note:

https://github.com/golang/vscode-go/wiki/debugging#launchjson-attributes

If you use the go debugger in vscode, you'll want to set -mod=mod in your buildFlags in launch.json.

findleyr commented 1 year ago

Let's use this issue to track improving our documentation.

hyangah commented 10 months ago

The current documentation already mention the relationship between go.buildFlags and gopls.build.buildFalgs

Flags to go build/go test used during build-on-save or running tests. (e.g. ["-ldflags='-s'"]) This is propagated to the language server if gopls.build.buildFlags is not specified.

buildFlags is the set of flags passed on to the build system when invoked. It is applied to queries like go list, which is used when discovering files. The most common use is to set -tags.

I verified the flags set with "go.buildFlags" are copied to gopls. However, gopls selectively applies flags and "-mod" flag is one of those dropped (in my case, I see the "inconsistent vendoring" errors coming from go command during package loading). @findleyr shouldn't gopls respect the user-specified mod flag?

@aathan what linter are you using? Neither staticcheck nor golangci-lint accepts -mod=mod flag (so, basically setting such value in "go.lintFlags" basically makes lint functionality stop).

p.s. BTW, the use case (hacking dependencies locally) is served better with go.work.