gobuildgo-build

go build not working when used with workspaces


Below is the structure of my golang code,

├── go.work
├── moda
│   ├── go.mod
│   └── main.go
├── go.mod
└── modb
    └── main.go

The problem is I'm only able to build binary only for a single module. For building other modules it is only working after i comment out the other modules in go.work

my go.work is as below,

go 1.19
use (
    ./moda
    .
)

so when i do build as below with the above go.work it works fine,

go build -o test-binary -modfile ./moda/go.mod ./moda

but when i try to build for my other module (which is modb/) like below,

go build -o test-binary1 -modfile ./go.mod ./modb

i'm getting below error,

directory modb is contained in a module that is not one of the workspace modules listed in go.work. You can add the module to the workspace using go work use .

i tried using go work use but im still facing the same issue. Can someone help me solve this ?

edit 1:

I have a project that needs multiple go.mod files to separate the dependencies of main and submodules and thats when i got to know about go workspaces which worked perfectly for my use case.

The structure of my project is same as mentioned above,

├── go.work
├── submodule
│   ├── go.mod
│   ├── go.sum
│   └── main.go
└── mainmodule
    └── main.go
├── go.mod
├── go.sum

now when building executable for submodule go build works fine but when building executable for mainmodule the imports that are present in submodules/go.mod are also getting added to mainmodule executable. I have verified this with go build -n too.

To avoid the submodule imports getting added to mainmodule executable i used -modfile but using it i'm only able to build the executable for the submodule but not for mainmodule.

github source

PS: though i have added the example code in github it is not able to reproduce the same issue (submodule imports getting added to mainmodule) not sure if it is because of the imports i used though


Solution

  • After a discussion with @ArigatoManga, we found that the confusion is caused by the behavior of minimal version selection (MVS) in workspace. A workspace is a collection of modules on disk that are used as the main modules when running minimal version selection (MVS) (reference). Because of the MVS, a module built with the workspace mode enabled could use different dependent modules from the one built with the workspace mode disabled.

    This is a documented behavior of the workspace, and there is not issue about it now.


    Update: Below is the original answer focusing on the -modfile flag. This flag will be rejected in workspace mode in go1.21.

    You have run into a bug in the go tools. I just reported this issue here.

    The error message in Go1.20 is different and still misleading:

    go: module example.com/m1 appears multiple times in workspace
    

    The difference was introduced by the commit cmd/go/internal/modload: return error when duplicate module paths among modules in go.work, but the root cause is the same: in workspace mode, the -modfile flag is not handled correctly.


    Update: The part below is not relevant now. It's a failed try to suppress MVS with the -modfile flag before understanding what MVC is.

    In the issue report, I suggested to prevent the -modfile flag in workspace mode. But you said that you need this flag in the comment.

    the reason for using -modfile is without that if i build binary for ./src the modules present even in ./moda are also getting downloaded and loaded as part of ./src binary though they should not be included

    But according to the cmd/go doc:

    -modfile file

    in module aware mode, read (and possibly write) an alternate go.mod file instead of the one in the module root directory. A file named "go.mod" must still be present in order to determine the module root directory, but it is not accessed. When -modfile is specified, an alternate go.sum file is also used: its path is derived from the -modfile flag by trimming the ".mod" extension and appending ".sum".

    The -modfile flag is used to replace the go.mod file in the module root. But in your example, you specify the same file as the one in the module root. So I don't quite understand it. Can you update your question to elaborate this part? A demo is appropriated!