https://blog.csdn.net/u010003835/article/details/51896018
在Go
的官网文档How to Write Go Code中,已经介绍了Go
的项目目录一般包含以下几个:
- src 包含项目的源代码文件;
- pkg 包含编译后生成的包/库文件;
- bin 包含编译后生成的可执行文件。
可以通过下面的例子来说明工程目录的组织管理。(Windows 7 64位,go version go1.3.3 windows/amd64)
1. 创建一个库文件
创建一个库文件a.go
并保存在src目录的一个子目录下面。
-
package myfunc
-
-
import "fmt"
-
-
func Afunc(str string) {
-
fmt.Println( "a.go is package mufunc.")
-
fmt.Println(str)
-
}
这时候目录结构如下:
-
<dirtest>
-
|-- <src>
-
|-- <mufunc>
-
|--a.go
2. 创建main
关于main包的位置,可以参照参考资料2,个人建议放在scr/main
下面,毕竟官方推荐包名和文件存放的文件夹名称最好相同(虽然包名和文件夹名可以不相同,也就是说一个文件夹下可以包含多个包的.go
文件)。
-
package main
-
-
import "myfunc"
-
-
func main() {
-
myfunc.Afunc( "b.go is package main.")
-
}
这时候目录结构如下:
-
<dirtest>
-
|-- <src>
-
|-- <mufunc>
-
|--a.go
-
|-- <main>
-
|--b.go
3. 使用go build
如果这时候使用go build
,你会发现下面的输出:
-
E:\dirtest> go build src\main\b.go
-
-
src\main\b. go:3:8: cannot find package "myfunc" in any of:
-
C:\Program Files\ go\src\pkg\myfunc (from $GOROOT)
-
D:\GoLang\src\myfunc (from $GOPATH)
从输出中我们可以看到,Go
先是从$GOROOT
中查找包myfunc
,如果没找到就从$GOPATH
中查找,结果都没有找到,我们可以使用go env
输出Go
的环境变量设置:
-
E:\dirtest>go env
-
-
set GOARCH=amd64
-
set GOBIN=
-
set GOCHAR=6
-
set GOEXE=.exe
-
set GOHOSTARCH=amd64
-
set GOHOSTOS=windows
-
set GOOS=windows
-
set GOPATH=D:\GoLang
-
set GORACE=
-
set GOROOT=C:\Program Files\go
-
set GOTOOLDIR=C:\Program Files\go\pkg\tool\windows_amd64
-
set CC=gcc
-
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0
-
set CXX=g++
-
set CGO_ENABLED=1
显然E:\dirtest
这个目录没有加到$GOPATH
中,在环境变量中添加该目录:
保存后,重新执行(可能需要重新打开控制台,让环境变量生效)go build
,就在当前目录生成了一个可执行文件b.exe
。
-
E:\dirtest\src\main>go env
-
set GOARCH=amd64
-
set GOBIN=
-
set GOCHAR=6
-
set GOEXE=.exe
-
set GOHOSTARCH=amd64
-
set GOHOSTOS=windows
-
set GOOS=windows
-
set GOPATH=D:\GoLang;E:\dirtest
-
set GORACE=
-
set GOROOT=C:\Program Files\go
-
set GOTOOLDIR=C:\Program Files\go\pkg\tool\windows_amd64
-
set CC=gcc
-
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0
-
set CXX=g++
-
set CGO_ENABLED=1
-
-
E:\dirtest>go build src\main\b.go
-
E:\dirtest>dir
-
-
E:\dirtest 的目录
-
-
2015/01/13 23:11 <DIR> .
-
2015/01/13 23:11 <DIR> ..
-
2015/01/13 23:11 1,958,912 b.exe
-
2015/01/13 22:52 <DIR> src
-
-
E:\dirtest>b.exe
-
a.go is package mufunc.
-
b.go is package main.
虽然成功运行,但是没有按照期待的那样生成在bin目录下面。为了达到这样的效果,你需要go install
。注意go install
是针对package,而不是针对单个.go
文件。
但是如果是当前状态执行go install
,虽然可以成功,但你会发现,并没有在项目根目录E:\dirtest
中创建bin\main.exe
,反而是在D:\GoLang
中创建了。
如果对main包执行go install
呢?
-
E:\dirtest\src\main> go install
-
go install: no install location for E:\dirtest\src\main: hidden by D:\GoLang\src
-
\main
可以看到,输出提示当前目录被隐藏。显然这个顺序是对应$GOPATH
的设置的,把$GOPATH
中的路径顺序改一下:
然后在执行go install myfunc
,发现成功地在pkg目录下面生成了myfunc.a
。同样执行go install main
,也成功的在bin目录下生成了main.exe
。此时的目录结构如下:
-
<dirtest>
-
|-- <src>
-
|-- <mufunc>
-
|--a.go
-
|-- <main>
-
|--b.go
-
|-- <pkg>
-
|-- <windows_amd64>
-
|--myfunc.a
-
|-- <bin>
-
|--main.exe
现在就算是成功完成了一个示例“项目”吧...
4. 常见错误
除了上面的步骤中出现的错误,其实工程目录管理稍有不慎,就会出现其他问题,例如:
1. 一个文件夹下面包含多个不同包的源文件。也就是把a.go
和b.go
都放到myfunc
目录下面会是什么情况呢?
这时候的目录结构如下:
-
<dirtest>
-
|-- <src>
-
|-- <mufunc>
-
|--a.go
-
|--b.go
那么执行go install
和go build
,甚至go run
都会是相同的错误:
-
E:\dirtest\src\myfunc> go install
-
can 't load package: package myfunc: found packages myfunc (a.go) and main (b.go)
-
in E:\dirtest\src\myfunc
-
-
E:\dirtest\src\myfunc>go build
-
can't load package: package myfunc: found packages myfunc (a.go) and main (b.go)
-
in E:\dirtest\src\myfunc
-
-
E:\dirtest\src\myfunc> go run b.go
-
b. go:3:8: found packages myfunc (a.go) and main (b.go) in E:\dirtest\src\myfunc
从参考资料3中可以看到,每个子目录中只能存在一个package,否则编译时会报错,所以一个子目录下面不能包含多个不同包的源文件。
2. 一个项目能包含多个main()吗?
简单测试下,创建一个c.go
,并使用myfunc
包(没有导入其他包的情况类似):
-
package main
-
import "fmt"
-
import "myfunc"
-
-
func main() {
-
fmt.Println( "This is single c.go")
-
myfunc.Afunc( "c.go is also package main.")
-
}
执行相应的命令,结果如下:
-
E:\dirtest\src\main> go build
-
# main
-
.\c. go:4: main redeclared in this block
-
previous declaration at .\b. go:5
-
-
E:\dirtest\src\main> go build c.go
-
# 成功,当前目录下生成了c.exe
-
-
E:\dirtest\src\main> go install
-
# main
-
.\c. go:4: main redeclared in this block
-
previous declaration at .\b. go:5
-
-
E:\dirtest\src\main> go install c.go
-
go install: no install location for .go files listed on command line (GOBIN not
-
set)
-
-
E:\dirtest\src\main> go run c.go
-
This is single c. go
-
a. go is package mufunc.
-
c. go is also package main.
显然只能是go run
和go build c.go
可行。如果把c.go
移到单独的目录下面呢:
-
E:\dirtest\src\cmain>dir
-
-
E:\dirtest\src\cmain 的目录
-
-
2015/01/14 11:27 <DIR> .
-
2015/01/14 11:27 <DIR> ..
-
2015/01/14 11:24 147 c.go
-
-
E:\dirtest\src\cmain> go build
-
-
E:\dirtest\src\cmain> go install
均可以执行成功。go install
在bin目录下面生成了对应的exe
文件。看来还是目录管理的问题。
3. go install: no install location for .go files listed on command line (GOBIN not set)
从上面的示例输出中就能看到,使用go install
针对单个文件时,就会出现这个错误。默认情况下如果设置了$GOROOT
和$GOPATH
,就会依次寻找$GOROOT/bin
和$GOPATH/bin
。那么我们如果自定义设置了$GOBIN=E:\dirtest\bin
之后会怎样?
-
E:\dirtest\src\cmain>go env
-
set GOARCH=amd64
-
set GOBIN=E:\dirtest\bin
-
set GOCHAR=6
-
set GOEXE=.exe
-
set GOHOSTARCH=amd64
-
set GOHOSTOS=windows
-
set GOOS=windows
-
set GOPATH=E:\dirtest;D:\GoLang
-
set GORACE=
-
set GOROOT=C:\Program Files\go
-
set GOTOOLDIR=C:\Program Files\go\pkg\tool\windows_amd64
-
set CC=gcc
-
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0
-
set CXX=g++
-
set CGO_ENABLED=1
-
-
E:\dirtest\src\cmain>go install c.go
-
# 成功在 E:\dirtest\bin 下面生成 c.exe
虽然成功了,但是go install
应该是作用于包级别,而非单个文件。
4. go build、go install 和 go run 的区别
详细的可以查看参考资料4,这里简单说一下:
go build (相当于编译)
编译包,如果是main
包则在当前目录生成可执行文件,其他包不会生成.a
文件;go instal (要设置GOBIN)
编译包,同时复制结果到$GOPATH/bin
,$GOPATH/pkg
等对应目录下;go run gofiles...(相当于编译并运行)
编译列出的文件,并生成可执行文件然后执行。注意只能用于main
包,否则会出现go run: cannot run non-main package
的错误。
此外,go run
是不需要设置$GOPATH
的,但go build
和go install
必须设置。go run
常用来测试一些功能,这些代码一般不包含在最终的项目中。
5. 总结
- 一定要管理好目录
- 多个项目最好都在一个
$GOPATH
下面,即src/proj1
,src/proj2
,etc - 尽量使用
go install
,这样能够规范项目整体结构