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,

  1. go get, just as you had it. (I ignored the error messages.)
  2. setting the import line in main.go back to "../../../meme", as you wanted to do.
  3. (commenting out a little bit of code containing an unused variable.)
  4. then in the meme/cmd/meme directory, either go run main.go or go 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).