Go项目源代码组织

引言

我们在管理项目源代码结构的时候,最终总是要落实到具体文件和文件夹,还有文件和文件夹得之间关系的描述。比如我们传统的C项目,我们使用文件来存储源代码和头文件,用文件夹来存储不同的模块,最后用Makefile来描述这些文件和文件夹的关系。而我们在Visual Studio中新建项目的时候使用文件和文件夹来存储源代码,用*.sln项目文件来描述文件间的关系。Visual Studio正是使用了这个项目文件最终编译和链接。像这样的情况还有很多,比如Python中使用文件夹来描述包。

总结起来,我们通常都是使用文件来存储源代码,使用文件夹来作为模块的划分,最终使用描述文件来描述文件和文件夹的关系。

Go语言比较强调工程性,所以Go使用了约定的方式来组织文件和文件夹,这样可以省去了Makefile。只要你符合Go项目的约定放置源代码文件和文件夹,Go自动去约定的目录寻找和编译代码。

要编译连接一个Go的项目说,你至少需要按Go得约定设定:

Go语言工作空间

Go使用它自己的工作空间来组织它所有的代码,即所有代码都必须放到某一个Go的工作空间(Workspace)中才能编译链接。这个工作空间使用环境变量GOPATH来指定,我们可以使用下面的命令来查看当前的设定。

➜  src  go env | grep GOPATH
GOPATH=""

上面病没有设置Go的工作空间,我们可以使用下面的命令来将当前目前设为Go的工作空间:

➜  gowks  export GOPATH=`pwd`
➜  gowks  go env | grep GOPATH
GOPATH="/Users/zjy/work/gowks"

GOPATH相当于所有Go项目的根目录,我们再看一下具体的目录组成:

➜  gowks  tree -L 3 .
.
├── bin
│   └── s3cl
├── pkg
│   └── darwin_amd64
│       └── github.com
└── src
    └── github.com
        ├── goamz
        ├── imzjy
        ├── jessevdk
        └── vaughan0

再Go工作空间主要有三个目录组成:

src/ 源代码目录

我们的项目源代码放在src/目录下,通过不同的目录来组织不同的项目。通过类似github.com/imzjy/s3cl这样的结构来定义项目。在项目定义完成后,我们便可以import github.com/imzjy/s3cl来引用这个项目导出的类型,方法等。

我们再来看看src/github.com/imzjy/s3cl目录下具体的源代码是怎么组织的:

 gowks  tree src/github.com/imzjy/s3cl 
src/github.com/imzjy/s3cl
├── LICENSE
├── README.md
├── build.sh
├── config.go
└── main.go

这个目录是s3cl这个Go项目的源代码目录,你还可以在这个目录下创建新的目录来组织模块,但无论怎么样,只是针对于s3cl这个项目,如果你想写一个库,那么最好是新建一个目录类似github.com/imzjy/apkg来单独将库作为一个Go项目。

当我们设置好GOPATH后,我们可以从任意目录,加上项目路径(github.com/imzjy/s3cl)来编译项目或者针对项目执行相关命令:

➜  work  go build github.com/imzjy/s3cl
➜  work  go fmt github.com/imzjy/s3cl
gowks/src/github.com/imzjy/s3cl/config.go
gowks/src/github.com/imzjy/s3cl/main.go

这样组织的Go项目,可以直接使用go get来直接下载编译,链接Go项目。比如这里的s3cl是Go得一个命令行工具,别人想使用这个工具的话只需要执行:

➜  work  go get github.com/imzjy/s3cl

Go会自动下载s3cl源代码到src/目录下,并且会自动下载依赖,编译和链接。这样你s3cl这个可执行文件就放在bin/目录下。你可以直接使用这个可执行文件。

总结

你在GitHub上新建项目,这个项目只放项目相关的源代码。然后你再自己的电脑上设置好自己的Go工作空间,这样你就可以使用go get,在Go工作空间目录来统一管理所有的Go项目。对于实际的项目,这个Go Workspace可以单独新建一个项目,其中包含一些项目相关的脚本,文档等常用目录,放到GitHub上,需要加入到项目的人员直接先clone这个项目,跑个脚本设置GOPATH,这样所有设置都完成了。类似:

$ git clone https://github.com/imzjy/gowks
$ cd gowks && ./source env.sh
$ go get github.com/imzjy/s3cl

s3cl已经下载编译好,可以直接使用或者修改调试了。

后记

真实的项目中,如果都使用一个GOPATH还是有很多不方便的地方,我得解决办法是使用Makefile来构建项目,在Makefile中使用env来定义一次性环境变量。

项目结构

.
├── Makefile
├── README.md
├── bin
│   ├── apihelp.txt
│   ├── apiserver
│   └── conf
│       └── app.conf
├── gowks
│   └── src
│       ├── apiserver
│       ├── github.com
│       ├── go-carrot
│       ├── go.net
├── scripts
│   ├── redis.conf
│   └── supervisord.conf
└── ubuntu_extras.sh

Makefile定义:

GOPATH  := ${CURDIR}/gowks
GO      := env GOPATH="${GOPATH}" go
apiserver: pre
        ${GO} build apiserver
@ 2015-04-08 08:00

Comments:

Sharing your thoughts: