go项目部署详解


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目录的一个子目录下面。

  1.  
    package myfunc
  2.  
     
  3.  
    import "fmt"
  4.  
     
  5.  
    func Afunc(str string) {
  6.  
    fmt.Println( "a.go is package mufunc.")
  7.  
    fmt.Println(str)
  8.  
    }

这时候目录结构如下:

  1.  
    <dirtest>
  2.  
    |-- <src>
  3.  
    |-- <mufunc>
  4.  
    |--a.go

2. 创建main

注意,如果用LITEIDE创建go项目,要编译的主函数必须放在main包下面,否则既不提示出错原因,也不会生成可执行文件,比较操蛋,还好最后发现了。

关于main包的位置,可以参照参考资料2,个人建议放在scr/main下面,毕竟官方推荐包名和文件存放的文件夹名称最好相同(虽然包名和文件夹名可以不相同,也就是说一个文件夹下可以包含多个包的.go文件)。

  1.  
    package main
  2.  
     
  3.  
    import "myfunc"
  4.  
     
  5.  
    func main() {
  6.  
    myfunc.Afunc( "b.go is package main.")
  7.  
    }

这时候目录结构如下:

  1.  
    <dirtest>
  2.  
    |-- <src>
  3.  
    |-- <mufunc>
  4.  
    |--a.go
  5.  
    |-- <main>
  6.  
    |--b.go

3. 使用go build

如果这时候使用go build,你会发现下面的输出:

  1.  
    E:\dirtest> go build src\main\b.go
  2.  
     
  3.  
    src\main\b. go:3:8: cannot find package "myfunc" in any of:
  4.  
    C:\Program Files\ go\src\pkg\myfunc (from $GOROOT)
  5.  
    D:\GoLang\src\myfunc (from $GOPATH)

从输出中我们可以看到,Go先是从$GOROOT中查找包myfunc,如果没找到就从$GOPATH中查找,结果都没有找到,我们可以使用go env输出Go的环境变量设置:

  1.  
    E:\dirtest>go env
  2.  
     
  3.  
    set GOARCH=amd64
  4.  
    set GOBIN=
  5.  
    set GOCHAR=6
  6.  
    set GOEXE=.exe
  7.  
    set GOHOSTARCH=amd64
  8.  
    set GOHOSTOS=windows
  9.  
    set GOOS=windows
  10.  
    set GOPATH=D:\GoLang
  11.  
    set GORACE=
  12.  
    set GOROOT=C:\Program Files\go
  13.  
    set GOTOOLDIR=C:\Program Files\go\pkg\tool\windows_amd64
  14.  
    set CC=gcc
  15.  
    set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0
  16.  
    set CXX=g++
  17.  
    set CGO_ENABLED=1

显然E:\dirtest这个目录没有加到$GOPATH中,在环境变量中添加该目录:

GOPATH

保存后,重新执行(可能需要重新打开控制台,让环境变量生效)go build,就在当前目录生成了一个可执行文件b.exe

  1.  
    E:\dirtest\src\main>go env
  2.  
    set GOARCH=amd64
  3.  
    set GOBIN=
  4.  
    set GOCHAR=6
  5.  
    set GOEXE=.exe
  6.  
    set GOHOSTARCH=amd64
  7.  
    set GOHOSTOS=windows
  8.  
    set GOOS=windows
  9.  
    set GOPATH=D:\GoLang;E:\dirtest
  10.  
    set GORACE=
  11.  
    set GOROOT=C:\Program Files\go
  12.  
    set GOTOOLDIR=C:\Program Files\go\pkg\tool\windows_amd64
  13.  
    set CC=gcc
  14.  
    set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0
  15.  
    set CXX=g++
  16.  
    set CGO_ENABLED=1
  17.  
     
  18.  
    E:\dirtest>go build src\main\b.go
  19.  
    E:\dirtest>dir
  20.  
     
  21.  
    E:\dirtest 的目录
  22.  
     
  23.  
    2015/01/13 23:11 <DIR> .
  24.  
    2015/01/13 23:11 <DIR> ..
  25.  
    2015/01/13 23:11 1,958,912 b.exe
  26.  
    2015/01/13 22:52 <DIR> src
  27.  
     
  28.  
    E:\dirtest>b.exe
  29.  
    a.go is package mufunc.
  30.  
    b.go is package main.

虽然成功运行,但是没有按照期待的那样生成在bin目录下面。为了达到这样的效果,你需要go install。注意go install是针对package,而不是针对单个.go文件。

但是如果是当前状态执行go install,虽然可以成功,但你会发现,并没有在项目根目录E:\dirtest中创建bin\main.exe,反而是在D:\GoLang中创建了。

如果对main包执行go install呢?

  1.  
    E:\dirtest\src\main> go install
  2.  
    go install: no install location for E:\dirtest\src\main: hidden by D:\GoLang\src
  3.  
    \main

可以看到,输出提示当前目录被隐藏。显然这个顺序是对应$GOPATH的设置的,把$GOPATH中的路径顺序改一下:

GOPATH

然后在执行go install myfunc,发现成功地在pkg目录下面生成了myfunc.a。同样执行go install main,也成功的在bin目录下生成了main.exe。此时的目录结构如下:

  1.  
    <dirtest>
  2.  
    |-- <src>
  3.  
    |-- <mufunc>
  4.  
    |--a.go
  5.  
    |-- <main>
  6.  
    |--b.go
  7.  
    |-- <pkg>
  8.  
    |-- <windows_amd64>
  9.  
    |--myfunc.a
  10.  
    |-- <bin>
  11.  
    |--main.exe

现在就算是成功完成了一个示例“项目”吧...

4. 常见错误

除了上面的步骤中出现的错误,其实工程目录管理稍有不慎,就会出现其他问题,例如:

1. 一个文件夹下面包含多个不同包的源文件。也就是把a.gob.go都放到myfunc目录下面会是什么情况呢?

这时候的目录结构如下:

  1.  
    <dirtest>
  2.  
    |-- <src>
  3.  
    |-- <mufunc>
  4.  
    |--a.go
  5.  
    |--b.go

那么执行go installgo build,甚至go run都会是相同的错误:

  1.  
    E:\dirtest\src\myfunc> go install
  2.  
    can 't load package: package myfunc: found packages myfunc (a.go) and main (b.go)
  3.  
    in E:\dirtest\src\myfunc
  4.  
     
  5.  
    E:\dirtest\src\myfunc>go build
  6.  
    can't load package: package myfunc: found packages myfunc (a.go) and main (b.go)
  7.  
    in E:\dirtest\src\myfunc
  8.  
     
  9.  
    E:\dirtest\src\myfunc> go run b.go
  10.  
    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包(没有导入其他包的情况类似):

  1.  
    package main
  2.  
    import "fmt"
  3.  
    import "myfunc"
  4.  
     
  5.  
    func main() {
  6.  
    fmt.Println( "This is single c.go")
  7.  
    myfunc.Afunc( "c.go is also package main.")
  8.  
    }

执行相应的命令,结果如下:

  1.  
    E:\dirtest\src\main> go build
  2.  
    # main
  3.  
    .\c. go:4: main redeclared in this block
  4.  
    previous declaration at .\b. go:5
  5.  
     
  6.  
    E:\dirtest\src\main> go build c.go
  7.  
    # 成功,当前目录下生成了c.exe
  8.  
     
  9.  
    E:\dirtest\src\main> go install
  10.  
    # main
  11.  
    .\c. go:4: main redeclared in this block
  12.  
    previous declaration at .\b. go:5
  13.  
     
  14.  
    E:\dirtest\src\main> go install c.go
  15.  
    go install: no install location for .go files listed on command line (GOBIN not
  16.  
    set)
  17.  
     
  18.  
    E:\dirtest\src\main> go run c.go
  19.  
    This is single c. go
  20.  
    a. go is package mufunc.
  21.  
    c. go is also package main.

显然只能是go rungo build c.go可行。如果把c.go移到单独的目录下面呢:

  1.  
    E:\dirtest\src\cmain>dir
  2.  
     
  3.  
    E:\dirtest\src\cmain 的目录
  4.  
     
  5.  
    2015/01/14 11:27 <DIR> .
  6.  
    2015/01/14 11:27 <DIR> ..
  7.  
    2015/01/14 11:24 147 c.go
  8.  
     
  9.  
    E:\dirtest\src\cmain> go build
  10.  
     
  11.  
    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之后会怎样?

GOPATH

  1.  
    E:\dirtest\src\cmain>go env
  2.  
    set GOARCH=amd64
  3.  
    set GOBIN=E:\dirtest\bin
  4.  
    set GOCHAR=6
  5.  
    set GOEXE=.exe
  6.  
    set GOHOSTARCH=amd64
  7.  
    set GOHOSTOS=windows
  8.  
    set GOOS=windows
  9.  
    set GOPATH=E:\dirtest;D:\GoLang
  10.  
    set GORACE=
  11.  
    set GOROOT=C:\Program Files\go
  12.  
    set GOTOOLDIR=C:\Program Files\go\pkg\tool\windows_amd64
  13.  
    set CC=gcc
  14.  
    set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0
  15.  
    set CXX=g++
  16.  
    set CGO_ENABLED=1
  17.  
     
  18.  
    E:\dirtest\src\cmain>go install c.go
  19.  
    # 成功在 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 buildgo install必须设置。go run常用来测试一些功能,这些代码一般不包含在最终的项目中。

5. 总结

  1. 一定要管理好目录
  2. 多个项目最好都在一个$GOPATH下面,即src/proj1src/proj2,etc
  3. 尽量使用go install,这样能够规范项目整体结构

6. 参考资料

  1. Golang项目目录结构组织
  2. 关于main包放在哪的问题
  3. 关于golang中包(package)的二三事儿
  4. Running multi-file main package


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM