golang学习手册之build子命令(下)

build多个导入路径

前面介绍build命令时,对象都是单个的,接下来看看如果同时build多个对象会怎样,要分为三种情况:多个目录,多个文件,以及目录和文件共存。

目录和文件共存

如果同时build目录和文件

1
2
➜  examples go build ./test.go temp/
named files must be .go files: temp/

完全不可行,只要编译对象中出现了以“.go”为名字后缀的源代码文件,其他对象就不能是目录。

多个文件

  1. 文件列表必须全部都是go源代码文件,不能包含其他类型的文件。

    1
    2
    ➜  example7 go build test.txt example7.go 
    named files must be .go files: test.txt

    同时.go文件和.txt文件直接报错了:要求所有文件只能是go文件。

  2. 所有文件必须来自同个目录。

    1
    2
    ➜  example7 go build example7.go dir0/tmp.go 
    named files must all be in one directory; have . and dir0

​ 同时编译当前目录下的examle7.go和子目录dir0下的tmp.go,就会报错:要求所有文件位于同一目录。

  1. 所有文件还必须属于同一个包。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ➜  example7 cat example7.go
    package example7

    func test() {
    }
    ➜ example7 cat main.go
    package main

    func main() {
    }
    ➜ example7 go build .
    found packages example7 (example7.go) and main (main.go) in /home/Admin/projects/examples/example7

    main.go和examle7.go都位于当前目录,但是在代码中声明了不同的包,所以报错:在目录中发现了两个不同的包。
    换言之,同一个目录下的源代码文件属于不同的包时,无法同时编译,只能分开编译,无论是以目录形式还是以文件列表形式。

  2. 当多个go文件来自同个目录,都属于非main包,那么编译这些文件跟直接编译他们所在的目录是一样的效果。

  3. 当多个go文件来自同个目录,都属于属于main包。

    区别在于默认生成的可执行文件的名字:直接编译目录默认以目录命名,编译文件列表默认以第一个文件的名字命名。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    ➜  example7 cat example7.go
    package example7

    func test() {
    }
    ➜ example7 cat main.go
    package main

    func main() {
    }
    ➜ example7 go build example7.go main.go
    ➜ example7 ls
    dir0 example7 example7.go main.go
    ➜ example7 go build main.go example7.go
    ➜ example7 ls
    dir0 example7 example7.go main main.go

​ main.go和example7.go只是换了一下位置,生成的可执行文件名就不一样了。

多个目录

  1. 若某个目录不存在go文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ➜  example8 tree .
    .
    ├── tmp1
    │   └── tmp.go
    └── tmp2

    2 directories, 1 file
    ➜ example8 go build ./tmp1 ./tmp2
    package ./tmp2: no Go files in /home/Admin/projects/examples/example8/tmp2

    直接报错了。

  2. 所有目录都包含了go文件,不过由于来自不同目录,是否属于同一个包已经没有意义了,即使所属的包名相同,也不会被视为同一个包。此时进行编译,也就是进行个语法检查而已,除非还要使用-o参数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ➜  example8 cat tmp1/tmp.go 
    package main

    func main() {
    }
    ➜ example8 cat tmp2/tmp.go
    package main

    func main() {
    }
    ➜ example8 go build ./tmp1 ./tmp2
    ➜ example8 ls
    tmp1 tmp2

    即使tmp1和tmp2目录中的代码都声明了自己属于main包,一起进行编译时,也不会生成可执行文件,仅仅做语法检查。可以知道对于部分目录是非main包,甚至所有目录全是非main包的情况了。

  3. 当使用-o参数时,又分为以下几种情况

    • 所有目录都包含main包

      1
      2
      ➜  example8 go build -o main ./tmp1 ./tmp2
      go: cannot write multiple packages to non-directory main

      继续使用上面的代码,-o的参数值是文件,报错了,无法将两个包的可执行文件结果写入到一份文件中,所以此时-o的参数值只能是目录:

      1
      2
      3
      ➜  example8 go build -o tmp/ ./tmp1 ./tmp2
      ➜ example8 ls tmp
      tmp1 tmp2

      在新建的目录tmp中,分别为两个目录的代码生产了各自的可执行文件,这也印证了上面的说法,即两个目录的代码即使声明为同一个包,也会被build命令分开处理,而不是当做同一个包。

    • 所有目录都不包含main包

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      ➜  example8 cat tmp3/tmp3.go 
      package example8

      func tmp() {
      }
      ➜ example8 cat tmp4/tmp4.go
      package example8

      func tmp() {
      }
      ➜ example8 go build -o pkg ./tmp3 ./tmp4
      go: cannot write multiple packages to non-directory main
      ➜ example8 go build -o tmp ./tmp3 ./tmp4
      go: no main packages to build

      无论-o参数值是文件还是目录,都报错了,这意味着此时只能做语法检查。

    • 部分目录包含main包

      1
      2
      3
      4
      5
      ➜  example8 go build -o main ./tmp1 ./tmp3
      go: cannot write multiple packages to non-directory main
      ➜ example8 go build -o temp/ ./tmp1 ./tmp3
      ➜ example8 ls temp
      tmp1

      继续使用前面的代码,可以发现,即使某个目录中存在main包,也无法将编译结果保存到文件中;但是却可以将main包的编译结果保存到指定目录中,当然非main包的那些代码生成的库文件会被丢弃。

(全文完)