godocが無いと言われたあと、godocインストールに権限が無いと言われた話
前提
$ go version go version go1.6.2 darwin/amd64
はじめに
そもそも go doc
と godoc
が別ものだということに気づいていなかった。2つは別物。
そもそも取得する引数なども異なる。
go doc
$ go doc -h Usage of [go] doc: .. snip Flags: -c symbol matching honors case (paths not affected) -cmd show symbols with package docs even if package is a command -u show unexported symbols as well as exported exit status 2
godoc
$ godoc -h usage: godoc package [name ...] godoc -http=:6060 -analysis string comma-separated list of analyses to perform (supported: type, pointer). See http://golang.org/lib/godoc/analysis/help.html .. snip -zip string zip file providing the file system to serve; disabled if empty
godoc
をインストールした時にエラーが出る
godoc
が無いということで go get
を使ってインストールしようとしたところ以下のようなエラー。
$ go get golang.org/x/tools/cmd/godoc go install golang.org/x/tools/cmd/godoc: open /opt/local/lib/go/bin/godoc: permission de
暫定的な解決策
多くのブログや記事では、godocは $GOROOT
にインストールされるものだから仕方がないという風潮。
以下のような形でインストールを薦める感じだった(幾つかある回答の中では個人的にはこれが一番無難だと思った)。
$ sudo -E go get golang.org/x/tools/cmd/godoc
もちろん、この場合ではインストールは正常に終了する。 $GOROOT/bin/godoc
が存在するようになる。ただ、このようにしてしまうとPATHの管理がだるい(なるべくPATHに追加する場所は少なくしておきたいという気持ち)。
# 存在はする $ go tool dist env CC="/usr/bin/clang" CC_FOR_TARGET="/usr/bin/clang" GOROOT="/opt/local/lib/go" GOBIN="/opt/local/lib/go/bin" GOARCH="amd64" GOOS="darwin" GOHOSTARCH="amd64" GOHOSTOS="darwin" GOTOOLDIR="/opt/local/lib/go/pkg/tool/darwin_amd64" $ GOROOTBIN=`go tool dist env | ruby -ne '$_ =~ /GOROOT="(\S+)"/ && $1.display'`/bin $ ls $GOROOTBIN go godoc gofmt
$GOROOT
以下にインストールしたくない。
Why does go get work for some packages and report permission denied in $GOROOT for some others (with GOPATH set properly)?
If you at any point installed the package in GOROOT (either by having no GOPATH set or by including GOROOT itself in GOPATH) then there might still be a directory in $GOROOT (which is always checked first) that is overriding your GOPATH. To verify, run go list -f {{.Dir}} importpath and if it reports a directory under $GOPATH try deleting that first.
これとは直接関係ないかもだったけれど。とりあえずコードを読んでみることにした。すると幾つかのパッケージに関しては独自に処理が行われているようだった。
$GOROOT/src/cmd/go/pkg.go
// goTools is a map of Go program import path to install target directory. var goTools = map[string]targetDir{ "cmd/addr2line": toTool, "cmd/api": toTool, // snip... "golang.org/x/tools/cmd/godoc": toBin, "code.google.com/p/go.tools/cmd/cover": stalePath, "code.google.com/p/go.tools/cmd/godoc": stalePath, "code.google.com/p/go.tools/cmd/vet": stalePath, } func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package { // 諸々条件分岐が存在 ... if p.build.BinDir != gobin && goTools[p.ImportPath] == toBin { // Override BinDir. // This is from a subrepo but installs to $GOROOT/bin // by default anyway (like godoc). p.target = filepath.Join(gorootBin, elem)
わりとびっくりしたけれど、特定のパッケージに対しての特別な処理が色々直書きされている(例えばgodocやgovetに対して古いpackageの場所が指定された時には警告を出すなど)。
とりあえず以下の様にすると $GOPATH/bin
以下にインストールできる。
$ GOBIN=$GOPATH/bin go install golang.org/x/tools/cmd/godoc
そもそも1.7では
上の内容は1.6で試した場合の話。試していないけれど。コードを読んだ限り、そもそも1.7では上のgodocの特別扱いした処理自体消えている模様。
if文での特別扱い(1.6) -> 1.7ではなくなる。
goToolsの定義(1.6)とgoToolsの定義(1.7) -> "golang.org/x/tools/cmd/godoc" に対する設定が無くなる。
memo
この辺りで色々あった(tweet)https://twitter.com/podhmo/status/771003702102466561