Relative import from parent directory
How does one do a relative import from a parent directory?
From meme/cmd/meme
:
import "../../../meme"
This gives an ambiguous error:
matt@stanley:~/gopath/src/bitbucket.org/anacrolix/meme/cmd/meme$ go get bitbucket.org/anacrolix/meme/cmd/meme
can't load package: /home/matt/gopath/src/bitbucket.org/anacrolix/meme/cmd/meme/main.go:8:2: local import "../../../meme" in non-local package
matt@stanley:~/gopath/src/bitbucket.org/anacrolix/meme/cmd/meme$ echo $GOPATH
/home/matt/gopath
How do I import locally from a parent directory?
Solution 1:
Edit: Relative import paths are not the way to go in Go. Lack of documentation shows something about popularity of relative paths, and I don't see a reason for using them. Go's recommended code organization works pretty well. Every package should have a unique import path and be imported everywhere using that same import path.
See how a package like github.com/ha/doozerd/peer
imports its neighbors. This is a common practice among Go projects and I've seen it a lot of times. Package camlistore.org/pkg/auth
(also on GitHub; written by one of the main authors of Go) imports camlistore.org/pkg/netutil
by full path.
Even if you are having both commands and libraries in the same project this approach works. In your original questions you wisely asked for best practices. I did my best in explaining best practices on this matter.
Import paths can't be relative in Go. I recommend reading How to Write Go Code, the essential reading on organizing Go projects. Here's a short overview:
Make a directory like ~/go
for your Go development. Then say:
$ export GOPATH=~/go
$ mkdir $GOPATH/{src,bin,pkg}
$GOPATH/src
holds source code for all your Go packages, even the ones your download with go get
. bin
and pkg
keep output of compilations. Packages with package name main
are commands and yield to executable binaries which go to $GOPATH/bin
. Other packages are libraries and their compiled object files are put in $GOPATH/pkg
.
Now if you put your code in $GOPATH/src/matt/meme
, you can import it by import "matt/meme"
. It's recommended to use a prefix for your package names and leave short package names for standard libraries. That's why I used $GOPATH/src/matt/meme
instead of $GOPATH/src/meme
.
Organize your code around this idea.
Solution 2:
Thanks for adding to your question. First, an answer, then some explanation. I built your code by,
- go get, just as you had it. (I ignored the error messages.)
- setting the import line in
main.go
back to "../../../meme", as you wanted to do. - (commenting out a little bit of code containing an unused variable.)
- then in the meme/cmd/meme directory, either
go run main.go
orgo build main.go
worked.
I was wrong in my comment earlier when I said go install works; I should have said go build.
The key however is that go build
alone does not work; you must type go build main.go
. This is because the go command does not allow "local imports in non-local packages." You are right that spec is of little help here. It weasels out saying, "The interpretation of the ImportPath is implementation-dependent." The current implementation behavior was set with CL 5787055, which was subsequently debated at length on Go-nuts.
"Local" means indicated with a file system relative path. Obviously a relative path starting with .. is local, so the trick is just getting the go
command to treat main as a local package as well. It apparently doesn't do this when you type go build
, but does when you type go build main.go
.
Solution 3:
Relarive imports are supported when manually using the compiler, linker, ... directly. The 'go' (build) tool doesn't support the same (somehow comparable to eg Java).