Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Go中的目录结构 #5

Open
zhouhaibing089 opened this issue Dec 1, 2015 · 6 comments
Open

Go中的目录结构 #5

zhouhaibing089 opened this issue Dec 1, 2015 · 6 comments
Labels

Comments

@zhouhaibing089
Copy link
Owner

在学习go语言的过程当中, 你也许问过自己一个问题, GOPATH到底是做什么的? 或许在写过一些代码之后, 很快你就会在网上找到一些资料, 它告诉我们GOPATH这个环境变量它指定了一个目录, 这个目录包含了我们所有的源码, 比如这里的介绍, 但是我觉得光是理解这一点是不够的, 因为你会发现让人为难的是, 看起来似乎我们每新建一个项目, 都要往GOPATH再补充一条路径, 这实在是反人类的做法啊.

我自己曾经也有过那样的顾虑, 为了巩固自己的理解, 同时也为了让其他读者更清楚GOPATH的作用, 我希望这篇小文希望能够起到一定的作用.

基本探索

让我们先从目录结构开始说起, 在写registry-watch这个项目的时候, 编辑器经常提示我结构不正确, 于是在网上搜了搜, 找到了这个.

按照文档的说法, 作为一个workspace, 它需要包含三个目录:

workspace
  |-- src
  |-- pkg
  |-- bin

src表示我们的源码目录, 在不考虑另外两个目录的情况下, 假设我写了一个demo项目, 并新建了一个hello.go, 它是main模块, 同时它依赖于另外一个函数, 该函数位于library/world.go:

hello.go

package main

import "fmt"
import "demo/library"

func main() {
    fmt.Println("Hello, " + library.World())
}

world.go

package library

// World return "World"
func World() string {
    return "World"
}

于是目录结构变成了现在这个样子:

workspace
  |-- src
  |     |-- demo
  |     |     |-- hello.go
  |     |     |-- library
  |     |     |     |-- world.go
  |-- pkg
  |-- bin

现在我cd src目录并运行go install demo后, 我们发现以下变化:

workspace
  |-- src
  |     |-- demo
  |     |     |-- hello.go
  |     |     |-- library
  |     |     |     |-- world.go
  |-- pkg
  |     |-- darwin_amd64
  |     |     |-- demo
  |     |     |     |-- library.a
  |-- bin
  |     |-- demo

这个例子基本说明了问题, 当我们写的模块是main时, 它会对应到一个可执行文件, 并且编译后的文件会被复制到bin目录, 如果是其他模块, 它会被编译成一个库文件, 并且被复制到pkg目录. 这就是我们必须提供三个目录的原因, 一个放源代码, 一个放编译后的可执行文件, 另外一个放编译后的库文件.

协作

一个项目总是会由多个成员进行协作开发, 在观察我们的项目结构之后, 很自然的, 我们会发现应该被提交的代码只有hello.golibrary/world.go, 也就是说我们的.git目录应该位于src/demo之下.

workspace
  |-- src
  |     |-- demo
  |     |     |-- .git
  |     |     |-- hello.go
  |     |     |-- library
  |     |     |     |-- world.go
  |-- pkg
  |-- bin

再考虑另外一个问题, 我们经常会运行go get xxx去安装一些包, 这些包会被下载到$GOPATH/src目录下, 当另外一个团队成员拉下我们的代码时, 如果还需要逐个去运行go get xxx那就太不方便了, 于是我们需要借助一个依赖管理的工具, 这就是godep. 当我们运行过go get xxxx安装过依赖之后, 只要再到项目目录下, 运行godep save, 便会将所有的依赖记录在一个文件当中, 并且这个时候我们的目录结构再次发生了一些小小的变化.

workspace
  |-- src
  |     |-- demo
  |     |     |-- .git
  |     |     |-- Godeps
  |     |     |     |-- _workspace
  |     |     |     |-- Godeps.json
  |     |     |-- hello.go
  |     |     |-- library
  |     |     |     |-- world.go
  |-- pkg
  |-- bin

现在来到需要拉代码的这一方, 对于像上面这样一个仓库. 我们需要多考虑一些事情. 我们不如以kubernetes为例来做示例:

cd workspace/src
git clone https://github.com/kubernetes/kubernetes.git k8s.io/kubernetes
godep restore

初看可能会奇怪, 为什么需要指定目的目录呢, 尤其是k8s.io看起来好生奇怪, 其实只要大概找一个源码文件看看就知道了, 比如这个文件

pkg/api/context.go

package api

import (
    stderrs "errors"
    "time"

    "golang.org/x/net/context"
    "k8s.io/kubernetes/pkg/auth/user"
)

我们知道import路径都是针对$GOPATH/src的, 所以很自然的我们要有k8s.io这个目录.

总结

这个时候, 我们回到一开始提到的顾虑, 我们真的需要对每一个项目都添加一条GOPATH路径吗? 不然, 我们所说的项目不过是以一个文件夹的形式存在于$GOPATH/src中, 我们只需要配置一个GOPATH, 并把项目都建在src目录下就可以了.

@jianzhangbjz
Copy link

以kubernetes为例,clone k8s下来之后, 它并未包含src目录,那如果需要新添加自己封装的包到k8s中,该如何做呢?

@zhouhaibing089
Copy link
Owner Author

kubernetes应该clone至$GOPATH/src/k8s.io.

@jianzhangbjz
Copy link

jianzhangbjz commented Aug 1, 2016

是的,但是如何添加自己的package文件呢?按照文档development.md所述,我需要执行下面的操作,但是DEP设置为包的本地路径后,出现无法识别错误unrecognized import path "vendor/github.com/xxx" (import path does not begin with hostname)。这个DEP该如何设置呢?
To add a new dependency is simple (if a bit slow):

cd $KPATH/src/k8s.io/kubernetes
DEP=example.com/path/to/dependency
godep get $DEP/...
# Now change code in Kubernetes to use the dependency.
./hack/godep-save.sh

@zhouhaibing089
Copy link
Owner Author

比如需要添加github.com/golang/groupcache/lru这个依赖:

$ go get github.com/golang/groupcache/lru
$ DEP=github.com/golang/groupcache/lru
$ godep go get $DEP
$ ./hack/godep-save.sh

@jianzhangbjz
Copy link

jianzhangbjz commented Aug 2, 2016

当执行go get vendor/github.com/xxx/, 出现如下错误:

package vendor/github.com/xxx: unrecognized import path "vendor/github.com/xxx" (import path does not begin with hostname)

这个依赖应该是个本地路径吧,是否需要其它设置?我是需要添加自己在本地封装的包文件,并不是去网络上下载。

@jianzhangbjz
Copy link

对go的import理解错误,已解决,多谢:)

@zhouhaibing089 zhouhaibing089 added blog and removed blog labels Dec 11, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants