• Go项目目录管理


    Go的官网文档How to Write Go Code中,已经介绍了Go的项目目录一般包含以下几个:

    • src 包含项目的源代码文件;
    • pkg 包含编译后生成的包/库文件;
    • bin 包含编译后生成的可执行文件。

    可以通过下面的例子来说明工程目录的组织管理。(Windows 7 64位,go version go1.3.3 windows/amd64)

    1. 创建一个库文件

    创建一个库文件a.go并保存在scr目录的一个子目录下面。

    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 srcmain.go
    
    srcmain.go:3:8: cannot find package "myfunc" in any of:
            C:Program Filesgosrcpkgmyfunc (from $GOROOT)
            D:GoLangsrcmyfunc (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 Filesgo
    set GOTOOLDIR=C:Program Filesgopkg	oolwindows_amd64
    set CC=gcc
    set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0
    set CXX=g++
    set CGO_ENABLED=1

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

    GOPATH

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

    E:dirtestsrcmain>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 Filesgo
    set GOTOOLDIR=C:Program Filesgopkg	oolwindows_amd64
    set CC=gcc
    set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0
    set CXX=g++
    set CGO_ENABLED=1
    
    E:dirtest>go build srcmain.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中创建binmain.exe,反而是在D:GoLang中创建了。

    如果对main包执行go install呢?

    E:dirtestsrcmain>go install
    go install: no install location for E:dirtestsrcmain: hidden by D:GoLangsrc
    main

    可以看到,输出提示当前目录被隐藏。显然这个顺序是对应$GOPATH的设置的,把$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.gob.go都放到myfunc目录下面会是什么情况呢?

    这时候的目录结构如下:

    <dirtest>
         |--<src>
              |--<mufunc>
                     |--a.go
                     |--b.go

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

    E:dirtestsrcmyfunc>go install
    can't load package: package myfunc: found packages myfunc (a.go) and main (b.go)
     in E:dirtestsrcmyfunc
    
    E:dirtestsrcmyfunc>go build
    can't load package: package myfunc: found packages myfunc (a.go) and main (b.go)
     in E:dirtestsrcmyfunc
    
    E:dirtestsrcmyfunc>go run b.go
    b.go:3:8: found packages myfunc (a.go) and main (b.go) in E:dirtestsrcmyfunc

    从参考资料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:dirtestsrcmain>go build
    # main
    .c.go:4: main redeclared in this block
            previous declaration at ..go:5
    
    E:dirtestsrcmain>go build c.go 
    # 成功,当前目录下生成了c.exe
    
    E:dirtestsrcmain>go install
    # main
    .c.go:4: main redeclared in this block
            previous declaration at ..go:5
    
    E:dirtestsrcmain>go install c.go
    go install: no install location for .go files listed on command line (GOBIN not
    set)
    
    E:dirtestsrcmain>go run c.go
    This is single c.go
    a.go is package mufunc.
    c.go is also package main.

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

    E:dirtestsrccmain>dir
    
     E:dirtestsrccmain 的目录
    
    2015/01/14  11:27    <DIR>          .
    2015/01/14  11:27    <DIR>          ..
    2015/01/14  11:24               147 c.go
    
    E:dirtestsrccmain>go build
    
    E:dirtestsrccmain>go install

    均可以执行成功。go installbin目录下面生成了对应的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:dirtestin之后会怎样?

    GOPATH

    E:dirtestsrccmain>go env
    set GOARCH=amd64
    set GOBIN=E:dirtestin
    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 Filesgo
    set GOTOOLDIR=C:Program Filesgopkg	oolwindows_amd64
    set CC=gcc
    set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0
    set CXX=g++
    set CGO_ENABLED=1
    
    E:dirtestsrccmain>go install c.go
    # 成功在 E:dirtestin 下面生成 c.exe

    虽然成功了,但是go install应该是作用于包级别,而非单个文件。

    4. go build、go install 和 go run 的区别

    详细的可以查看参考资料4,这里简单说一下:

    • go build 编译包,如果是main包则在当前目录生成可执行文件,其他包不会生成.a文件;
    • go install 编译包,同时复制结果到$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
  • 相关阅读:
    Spring Cloud Eureka(七):DiscoveryClient 源码分析
    Spring Cloud Eureka(六):Eureka Client 如何注册到Eureka Server
    Centos 查看CPU个数、核心数等信息
    Spring Cloud Eureka(五):Eureka Server 启动流程分析
    GlusterFS常用命令
    修改内核参数ip_local_reserved_ports避免tomcat端口占用
    TTM模块安装
    查看磁盘raid信息
    Kubernetes中的PodIP、ClusterIP和外部IP
    ubuntu 14.04.5 kern numa bug
  • 原文地址:https://www.cnblogs.com/shaoyu19900421/p/6067486.html
Copyright © 2020-2023  润新知