Reputation: 14884
I am new to go and working on an example code that I want to localize.
In the original main.go
import statement it was:
import (
"log"
"net/http"
"github.com/foo/bar/myapp/common"
"github.com/foo/bar/myapp/routers"
)
Now I have common
and routers
package in /home/me/go/src/myapp
So I converted the import statement to:
import (
"log"
"net/http"
"./common"
"./routers"
)
But when I run go install myapp
I get these errors:
can't load package: /home/me/go/src/myapp/main.go:7:3: local import "./common" in non-local package
Also, when I use common
and routers
instead of ./common
and ./routers
in the import statement, I get:
myapp/main.go:7:3: cannot find package "common" in any of:
/usr/local/go/src/common (from $GOROOT)
/home/me/go/src/common (from $GOPATH)
myapp/main.go:8:2: cannot find package "routers" in any of:
/usr/local/go/src/routers (from $GOROOT)
/home/me/go/src/routers (from $GOPATH)
How can I fix this?
Upvotes: 255
Views: 434170
Reputation: 53
If you are using GOMODULE111=on, then
Suppose, your local module is located at "/Users/me/dir_mod"
Then the go.mod within it should declare the module path as: "module abc.def/xyz"
Suppose the module has a package at a "/Users/me/dir_mod/dir_package".
This package folder has file somefile.go declaring its package as "package random"
Note: The module path as well as the package name are not required to be the same as their respective actual directory names.
Let's say, you want to now import "random" package in another module.
The go.mod of calling project requires 2 lines (without the quotes):
The version number can be any random vX.Y.Z format string where X, Y, and Z have characters only between 0-9 (e.g. v1.2.3, v0.100.2, v00.1.345).
Now any file in a package inside the calling module can do:
"import another_random abc.def/xyz/dir_package" => using aliasing of packages to rename "package random" contained in ""/Users/me/dir_mod/dir_package"" as "another_random"
The above is just to illustrate that except for module path naming convention of abc.def/xyz and including a pseudo-version number, everything else is flexible. You wouldn't be having mixed names of packages and directories in real projects, but is helpful to know what is absolutely essential vs not.
Upvotes: 2
Reputation: 66475
You should have created your package with go mod init
e.g. go mod init github.com/my-org/my-package
Now in my-package
you have a sub module called utils
for example.
main.go
utils
|- randstr.go
And your randstr.go
looks like this:
package utils
func RandStr(n int) string {
// TODO: Generate random string....
return "I am a random string"
}
And then anywhere in your project you would use exported (capitalized) functions from the utils
package like this, for example in main.go
:
package main
import (
"fmt"
// "github.com/my-org/my-package" is the
// module name at the top of your `go.mod`
"github.com/my-org/my-package/utils"
)
func main() {
fmt.Printf("Random string: %s\n", utils.RandStr(20))
}
Upvotes: 102
Reputation: 1512
Another approach, available since go1.18
, is to use a go.work
file.
First, the local common
package has to be a module, so provide a go.mod
file inside the common
folder:
module common
go 1.18
You can now create a go.work
file in the root of your directory manually or call go work init
, then go work use .
and finally go work use ./common
. It will look like this:
go 1.18
use (
.
./common
)
Finally you can import the package in your code by name
package main
import "common"
Just remember to not commit your go.work
files :)
Upvotes: 8
Reputation: 17171
Follow instructions here https://go.dev/doc/tutorial/call-module-code
Mainly you need the replace call in your go.mod file.
module example.com/hello
go 1.16
replace example.com/greetings => ../greetings
Upvotes: 28
Reputation: 21
Try to change the package name with the go mod init command.
So, I have go 1.17, and I have the same import problem. My project directory is $GOPATH/src/myswagger/app-swagger-test. I ran this command into app-swagger-test dir:
go mod init app-swagger-test
go mod tidy
In my new go.mod file the package name is app-swagger-test. For example, this import was wrong:
import (
...
"myswagger/app-swagger-test/internal/generated/restapi"
"myswagger/app-swagger-test/internal/generated/restapi/operations"
)
So I removed go.mod and go.sum. And I ran next commands into app-swagger-test dir:
go mod init myswagger/app-swagger-test
go mod tidy
After that all imports in the project were imported successfully. In the new go.mod file the first line is:
module myswagger/app-swagger-test
Maybe this information is common, but I did not find it. Thanks!
Upvotes: 2
Reputation: 407
As in the question, the folder structure is:
/home/me/go/src/myapp
└─ common
└─ routers
So go to myapp dir
cd /home/me/go/src/myapp
Do
go mod init myapp
This will create a go.mod file which lets Go know the name of the module myapp so that when it’s looking at import paths in any package, it knows not to look elsewhere for myapp
Then you can do the following in the code:
import (
"log"
"net/http"
"myapp/common"
"myapp/routers"
)
Now package common and routers gets imported.
Upvotes: 6
Reputation: 2444
The key is how you name your module in the following command
go mod init <TheNameGiven>
Then refer the modules in the inner folder with,
TheNameGiven/folder
I have found the best solution here... Read More
Upvotes: 4
Reputation: 382
an example:
in ./greetings
, do go mod init example.com/greetings
from another module, do go mod edit -replace=example.com/greetings=../greetings
go get example.com/greetings
from the go tutorial
Upvotes: 16
Reputation: 1520
Local package is a annoying problem in go.
For some projects in our company we decide not use sub packages at all.
$ glide install
$ go get
$ go install
All work.
For some projects we use sub packages, and import local packages with full path:
import "xxxx.gitlab.xx/xxgroup/xxproject/xxsubpackage
But if we fork this project, then the subpackages still refer the original one.
Upvotes: 8
Reputation: 1061
If you are using Go 1.5 above, you can try to use vendoring feature. It allows you to put your local package under vendor folder and import it with shorter path. In your case, you can put your common and routers folder inside vendor folder so it would be like
myapp/
--vendor/
----common/
----routers/
------middleware/
--main.go
and import it like this
import (
"common"
"routers"
"routers/middleware"
)
This will work because Go will try to lookup your package starting at your project’s vendor directory (if it has at least one .go file) instead of $GOPATH/src.
FYI: You can do more with vendor, because this feature allows you to put "all your dependency’s code" for a package inside your own project's directory so it will be able to always get the same dependencies versions for all builds. It's like npm or pip in python, but you need to manually copy your dependencies to you project, or if you want to make it easy, try to look govendor by Daniel Theophanes
For more learning about this feature, try to look up here
Understanding and Using Vendor Folder by Daniel Theophanes
Understanding Go Dependency Management by Lucas Fernandes da Costa
I hope you or someone else find it helpfully
Upvotes: 68
Reputation: 14884
Well, I figured out the problem.
Basically Go starting path for import is $HOME/go/src
So I just needed to add myapp
in front of the package names, that is, the import should be:
import (
"log"
"net/http"
"myapp/common"
"myapp/routers"
)
Upvotes: 157
Reputation: 1014
Import paths are relative to your $GOPATH
and $GOROOT
environment variables. For example, with the following $GOPATH
:
GOPATH=/home/me/go
Packages located in /home/me/go/src/lib/common
and /home/me/go/src/lib/routers
are imported respectively as:
import (
"lib/common"
"lib/routers"
)
Upvotes: 25