I can not find a way to factor out some code from main.go
into a local package when using Go modules (go version >= 1.11) outside of $GOPATH
.
I am not importing any external dependencies that need to be included into go.mod
, I am just trying to organize locally the source code of this Go module.
The file main.go
:
package main
// this import does not work
import "./stuff"
func main() {
stuff.PrintBaz()
}
The file ./stuff/bar.go
(pretending to be a local package):
package stuff
import "log"
type Bar struct {
Baz int
}
func PrintBaz() {
baz := Bar{42}
log.Printf("Bar struct: %v", baz)
}
The file go.mod
(command go mod init foo
):
module foo
go 1.12
When executing go run main.go
:
import "./stuff"
, then I see build command-line-arguments: cannot find module for path _/home/<PATH_TO>/fooprj/stuff
.import "stuff"
, then I see build command-line-arguments: cannot load stuff: cannot find module providing package stuff
.import stuff "./stuff"
with a package alias, then I see again: build command-line-arguments: cannot find module for path _/home/<PATH_TO>/fooprj/stuff
.I can not find a way to make local packages work with go modules.
go.mod
)?The most common and easiest approach is:
go.mod
per repository, andgo.mod
file in the repository root, andmodule
line in the go.mod
me.io/mymod
rather than using a VCS host based import path, then you would use the custom import path instead of the repository name in your go.mod
).For example, if your repo is github.com/my/repo
, then you would place a single go.mod
in the repo root, with the first line reading module github.com/my/repo
. That can be created by cd
'ing to the repo root and running go mod init github.com/my/repo
.
Following this helps you stay on the happy path with modules, and it avoids multiple subtleties.
Russ Cox commented in #26664:
For all but power users, you probably want to adopt the usual convention that one repo = one module. It's important for long-term evolution of code storage options that a repo can contain multiple modules, but it's almost certainly not something you want to do by default.
There is much more about multi-module repositories in the "Multi-module Repositories" FAQ section on the modules wiki. Those 6 or so FAQs in that section should be read in their entirety by anyone considering veering off the recommendation above.
Once you have set up your go.mod
, you can arrange your packages in directories however you see fit in directories underneath the directory containing the go.mod
, as well as in the directory with the go.mod
. Three good articles about how to arrange your code in packages:
Those articles are classics that pre-date the introduction of modules, but the philosophies in them still apply to how to arrange your packages within a module.
When importing another package with modules, you always use the full path including the module path. This is true even when importing another package in the same module. For example, if a module declared its identity in its go.mod
as module github.com/my/repo
, and you had this organization:
repo/
├── go.mod <<<<< Note go.mod is located in repo root
├── pkg1
│ └── pkg1.go
└── pkg2
└── pkg1.go
Then pkg1
would import its peer package as import "github.com/my/repo/pkg2"
. Note that you cannot use relative import paths like import "../pkg2"
or import "./subpkg"
. (This is part of what OP hit above with import "./stuff"
).
A Go module is a collection of related Go packages that are versioned together as a single unit. Modules record precise dependency requirements and create reproducible builds.
Summarizing the relationship between repositories, modules, and packages:
package foo
statement.import "github.com/my/repo/pkg1"
. The import path always starts with the module path of that package, regardless of whether that package is in the same module or a different module.