Hey guys, I've been using (and loving) Go for a week or two, and one thing is perplexing me:
What's the deal with Gopath? Are you meant to maintain one monolithic Gopath for your entire system, or have a Gopath for each individual project? Because I thought it was the former: I figured the $GOPATH constant aliased to where you wanted to drop your global libraries, and then you would use relative imports for your project-specific files. In other words, $GOPATH would be like using C's
#import <global library>
While relative imports with java-like directory structure (directory must match package name) would be like C's
#import "local file"
It all makes a lot of sense and while the forced directory-naming is irritating, it makes sense and is good for organization so I went with it.
But everything and I mean EVERYTHING out there rants and raves about how awful relative imports are! Some even made noise that they're deprecated and only still supported because there are old libraries that haven't been updated yet. They make it sound like $GOROOT is for global and $GOPATH is for projects... but $GOPATH is an environment variable. Switching it every time you want to work on a different project would be so cumbersome that, if that was the only way to import local files, I would personally drive to California and slap Ken Thompson. You would have to switch: putting every package you ever write into the same namespace is insane.
So what's going on here? What's the "proper" way to manage local vs global imports?
评论:
010a:
om0tho:Go does not have a concept of "local imports" and you'd be going against recommended usage by trying to implement something like that.
I don't set $GOROOT. If you need to set it, it has everything to do with pointing to the
go
binary, not the binaries or source code of your projects.The typical way of setting up your $GOPATH is to have a single directory (we'll say
$GOPATH=~/go
) which stores all of your go related code.Every import in Go is global. If I start a new project which will have the package
github.com/user/project
, the source code for this goes in~/go/src/github.com/user/project
. I would writepackage main
in all of my .go files inside this directory (unless it is a pure library project, in which case it would havepackage project
).If my project relies on, say, Echo, I would write
import "github.com/labstack/echo
in my go files.go get github.com/labstack/echo
would download the source code for Echo to~/go/src/github.com/labstack/echo
compile it, and store the.a
library for it in~/go/pkg/{arch}/github.com/labstack/echo
. This would resemble a typical "global import" from C.If I want to write my own library package which my project depends on, this might resemble a local import in C, but in Go its just another global import. I can write a new package
github.com/user/project/mylib
. This would go in folder~/go/src/github.com/user/project/mylib
. In C, you would#import "mylib/file.c"
. In Go, you justimport github.com/user/project/mylib
, just like every other package. You can even do that outside of your project. Go has no local imports.In fact, the logical extension of this is that Go has no concept of files. You can organize your source code however you wish inside of a package. You could give each function its own .go file. Go doesn't care. This is very different from C because you import entire packages, not individual files. Quite nice.
And as another point: You don't have to create package names and organize your go code in your $GOPATH. If I have a
~/src/main.go
and~/src/other.go
, I can certainly just rungo build main.go other.go
and it will compile, even if it imports other global libraries installed on $GOPATH. The only thing the $GOPATH is used for is imports, so you only have to keep your projects on the $GOPATH if you're going to be importing them in other packages.
dchapes:Don't mess with $GOROOT, unless you're installing to some non-standard location. In fact, forget about that $GOROOT exists. The vast majority of people probably don't need to mess with that.
The suggested way of doing things is having only 1 $GOPATH. It's what Google does. Otherwise, you'll be going against the grain (have fun with that).
You can install third-party code globally. OR you can vendor it in your project, which basically means you copy the package you want to install in your own project. You can even fork it, if you wish. That'll allow you to use different versions of the package in different projects and also gives you control over updating it.
This will be the "official" way of doing things in August, when 1.5 comes out.
https://groups.google.com/forum/#!topic/golang-dev/nMWoEAG55v8%5B1-25%5D
GoldDog:putting every package you ever write into the same namespace is insane
No. Not making sure every package you write has a globally unique import path is insane because it's the right thing to do and it's also so trivial to do so.
LordButtersI:You know, GOPATH doesn't have to be a single path...
natefinch:I know, but unless there's a way to restrict which paths are available for a given project, every project in the list is available to every other: you could never use a generic package name; you'd have to use some kind of hungarian
package projectname_packagename
abomination. I don't want to do that, and I doubt anyone else does either.
SupersonicSpitfire:You need a hierarchy. So for example, on disk:
$GOPATH/src/project1/pkg1 $GOPATH/src/project1/pkg2 $GOPATH/src/project2/pkg1 $GOPATH/src/project2/pkg2
you would then import those as
import "project1/pkg1"
or
import "project2/pkg1"
The import statement directly translates to a path on disk rooted at your $GOPATH/src
If you use an online source control system like github, with a url like https://github.com/yourname/project1/pkg1
this would be put on disk by
go get
at$GOPATH/src/github.com/yourname/project1/pkg1
which you would import as
import "github.com/yourname/project1/pkg1
bertold:One way is to first start developing a project in, say, $GOPATH/src/github.com/username/myproject, where GOPATH might be ~/go. Then first start developing in one relatively large source file. Then refactor it into several source files, based on which types and functions fit where. Then create new packages for where functionality seems to be separate, for instance $GOPATH/src/github.com/username/myfileformat, with "package myfileformat" at the top of every source file. Then import that package in "myproject". It can be useful to have a script for testing and building code if source code in either package you are developing are changing, perhaps using inotifywait. There are also tools that help with building and developing, but the above worked for me. YMMV.
ddoreto:Are you meant to maintain one monolithic Gopath for your entire system
Yes.
or have a Gopath for each individual project?
Barring some very esoteric exceptions, no.
What's the "proper" way to manage local vs global imports?
There is no distinction between "local" or "global" imports.
Currently I have one $GOPATH for each project and the entire $GOPATH is commited on git repo. That way I don't depend on a 3rd party lib be always available and if some repo have an update that breaks my app, I can plan the upgrade when I have time. So I know that what's on my repo is tested and working.
Changing the $GOPATH per project is not a pain when you make it automatic. I have a script that changes it for me, open a terminal and my editor on the correct directory.
