本文章从 go build/install 命令开始说起,提炼出 golang 目录结构与编译规则。
0.go build 与 go install 命令对于文件,目录的规则是一样的。
1.go build 后面可以接文件,此时,从当前目录出发找到指定的文件编译。
2.go build 后面可以接目录(看起来像是包名,但其实是目录). 从 GoPath 开始找到这个目录,然后编译下面所有的 go 文件.再强调一次: go build 后面的目录并 非是相对当前目录的,它是相对 GoPath 的。
3.go build 后面接目录,只会编译此目录下的 go 文件,并不会递归处理子目录下的 go 文件。
4.go build 后面可以不接参数,表示编译当前目录下的所有 go 文件. 当前目录下若没有 go 文件则会编译报错。
5.当一个目录下存在引入不同包的 go 文件,使用 go build 会报错。
6.GOPATH 下的目录下的 src 目录可以被自动忽略,这是因为, go 语言假设所有工程的源码都放于 src 文件夹下。看后面的举例即可明白。
-----------------------------------------------------------------------------------------------------------------------------------
举例说明,有一个 go 工程目录结构如下.
bubblesort.go 和bubblesort_test.go都 package 到 bubblesort 包.
qsort.go 和 qsort_test.go 都 package 到 qsort 包.
sorter.go 则 package 到 main 包.
我们将 sorter 设置为 GOPATH.
<sorter> |--<src> |--<algorithm> |--<bubblesort> |--bubblesort.go |--bubblesort_test.go |--<qsort> |--qsort.go |--qsort_test.go |--<main> |--sorter.go1.go build 单个文件的情况。
如下所示,sorter.go 文件是一个包名为 main ,且有 main 函数的 go 文件。可以直接在 GOPATH 下使用相对目录编译某个文件,或者到那个目录,直接使用 go build 编译那个文件,或者直接 go build,都是可以的。抑或是在非 GOPATH 下使用相对目录编译那个文件,这一点说明了编译单个文件时,查找文件的方式是基于当前目录的,与 GOPATH 无关。
需要注意还有两点:
-----------------------------------------------------------------------------------------------------------------------------------
当我们要编译的 go 文件的包名不含 main 函数,会是怎样的呢?继续试验。qsort.go 没有 main 函数,编译成功后它没有在任何地方生成任何文件。而 bubblesort.go 中有 main 函数,它在当前目录下生成了 exe 文件。
另外有一点需要注意,sorter.go 和 bubblesort.go 都是 package 到 main 包且都有 main 函数,它们同时存在于
-----------------------------------------------------------------------------------------------------------------------------------
还有一点需要验证,如果一个 go 文件 package 的是 main 包,但没有 main 函数,会有怎样的编译结果?我们更改 qsort.go 文件,将包名改为 main 但不增加 main 函数,编译结果如下:
以上结果说明,当被打包到 main 包时,一定要有一个 main 函数。
-----------------------------------------------------------------------------------------------------------------------------------
我们再更改 qsort.go 文件,将包名改回为 qsort,但增加一个 main 函数,编译结果如下:
啥也没有,目前猜测是,当 main 函数不在 main 包里会被掩盖,只会被作为成员函数去调用,不被当成是程序的启动点。
2.我们将所有文件都恢复如初,考察编译某个包.
-----------------------------------------------------------------------------------------------------------------------------------
上面编译过程说明了两点:
1.go build 后面的目录若不直接含有 go 文件,则 build 失败
2.最后两次编译,是在 E 盘根目录完成的,编译成功了,说明 go build 后面的目录不是相对于当前目录的路径,而是相对于 GOPATH 的
3.回到最开始给出的第 6 条规则,我们看到,在第二次/第三次编译时,处于 GOPATH E:\Go\src\sorter 目录下,go build 参数是 algorithm/qsort,并不是 src/algorithm/qsort 。编译成功了,说明了 src 是 GOPATH 默认的一个目录,省去不写。
-----------------------------------------------------------------------------------------------------------------------------------
加上 src 编译则失败,如下:
编译失败!仔细看最后一行,要找的目录是:E:\Go\src\sorter\src\src\algorithm\qsort, 显然是多加了一个 src。再次证实了第 6 个规则。
-----------------------------------------------------------------------------------------------------------------------------------
最后我们再看如何编译整个工程呢?根本上,我们要解决一个问题:如何递归地编译子目录 go 文件。目前暂时没有找到解决方案,后续找到了会更新此文。
有一个弱一点的解决方法:我们编译 main 目录即可。所有 main 目录下 go 文件依赖的其它源文件,模块都会被编译。
对,直接这样就行。只要 sorter 目录被加到了 GOPATH 中,那么 sorter 的 src/main 目录可以被找到,所以可以编译成功。后面的 go install main 执行完成后,我们会看到 sorter 目录下会生成 bin 和 pkg 两个目录。如下: