Go 编译构建的一些细节

发布于:2024-04-20 ⋅ 阅读:(26) ⋅ 点赞:(0)

Go 编译构建的一些细节

发现自己竟然没有怎么认真研究过 go 的编译构建命令。

结论前置

  • go run 专门用来运行命令源码文件的命令,一般用来运行单个文件
  • go build 主要是用于测试编译。编译某个包或者项目,在当前目录下生成可执行文件
  • go install 编译并安装代码包或者源码文件的。
  • go get 用于从远程代码仓库(比如 Github )上下载代码包并更新 mod
  • go 1.17 之后 go get 只下载源码,并将依赖添加到 go.mod。get install 用来下载和安装三方库

go 命令常用选项

在这里插入图片描述

下面是细节。

go run

专门用来运行命令源码文件的命令,不是用来运行所有 go 源码文件的

go run 命令只能接受一个命令源码文件以及若干个库源码文件(必须同属于 main 包)作为文件参数,且不能接受测试源码文件。它在执行时会检查源码文件的类型。如果参数中有多个或者没有命令源码文件,那么 go run 命令就只会打印错误提示信息并退出,而不会继续执行。

go run -ngo run 命令的一个选项,用于执行编译和运行 Go 源文件,但不实际运行。它会打印出编译时将要执行的命令,而不会真正运行该命令。这对于调试构建脚本或查看编译命令是否正确非常有用。

  1. 临时文件生成: 在使用 go run 命令时,会生成临时工作目录(通常在系统的临时目录下),其中包含编译过程中产生的临时文件和中间文件。
  2. 导入文件(importcfg 文件): importcfg 文件用于指定程序在编译时所需的导入包。这个文件在编译过程中被使用,而不是在运行时。
  3. compile 命令和生成 link 文件: 在编译过程中,compile 命令用于将源码文件编译成归档文件(archive)。生成的 link 文件记录了编译过程中用到的依赖信息。
  4. 生成可执行文件: 最后,exe 文件是通过连接编译生成的归档文件和 link 文件,并将其与源码文件一起打包成可执行文件。
  5. go run 命令生成的文件: go run 命令会在执行过程中生成两个文件,一个是编译生成的归档文件(通常具有 .a 扩展名),另一个是最终的可执行文件。

举例:

go run app/user/*.go

等价于什么呢?

go run app/user/*.go 命令用于直接运行指定目录下的所有 Go 源代码文件。它的等价操作包括:

  1. 编译并运行每个 .go 文件中的代码。
  2. 如果代码中有 main 函数,则执行该函数;如果没有,则不执行。
  3. 该命令只在开发阶段使用,不会生成可执行文件,而是临时编译和执行代码。

因此,go run app/user/*.go 与手动编译并执行每个文件的操作等价。

问题:会递归查找所有目录吗?

不会。go run app/user/*.go 只会在 app/user/ 目录下查找直接位于该目录下的 .go 文件,而不会递归查找其子目录中的文件。如果需要递归查找所有子目录中的 .go 文件,可以使用 ./... 来代替 *,例如 go run ./...go run ./... 是一个 Go 语言的命令,用于编译并运行当前目录(以及子目录)中的所有 Go 源码文件。这个命令会查找当前目录下的所有 .go 文件,并且假定它们属于同一个包,然后尝试编译它们。

这里的 ./... 是一个模式匹配表达式,用于匹配当前目录及其所有子目录中的所有文件和目录。在 Go 命令中,这种模式匹配通常用于指定源码文件的路径。

具体来说:

  • . 表示当前目录。
  • ...(三个点)是一个通配符,表示递归地匹配当前目录下的所有子目录。

因此,go run ./... 命令会执行以下操作:

  1. 编译当前目录及其所有子目录中的所有 .go 文件。
  2. 将编译后的代码链接成一个可执行文件。
  3. 运行这个可执行文件。

这个命令在处理包含多个源码文件的包时非常有用,尤其是当你想要快速运行和测试整个包中的代码时。然而,需要注意的是,这个命令不会递归地编译子目录中的子目录,它只编译当前目录及其直接文件和子目录中的 .go 文件。

如果你的 Go 项目结构中,每个功能或模块位于不同的包中,那么使用 go run ./... 可能不会按预期工作,因为它会尝试编译所有匹配到的源码文件,而不管它们是否属于同一个包。在这种情况下,你可能需要更精细地指定要编译的文件或目录。

再看 go build

另外,使用 dlv 进行远程调试的话,必须 build 出可执行文件 main 之后,才可以。

所以这个时候需要执行

go build -o main

然后运行就可以开始监听了。

在这里插入图片描述

区别于 go build main.go

区分 Go 编译单个文件和目录下所有文件

go build main.gogo build -o main 都是用于构建 Go 应用程序的命令,但它们之间有一些区别:

  1. go build main.go:这个命令告诉 Go 编译器要编译名为 main.go 的文件,并生成一个默认的可执行文件,文件名与包名相同(如果 main.go 中的包名是 main,则生成的可执行文件为 main)。
  2. go build -o main:这个命令告诉 Go 编译器要编译当前目录下的所有文件,并将生成的可执行文件命名为 main。使用 -o 标志可以指定生成的可执行文件的名称,而不是使用默认的包名。

总的来说,go build main.go 适用于单个文件的构建,而 go build -o main 适用于多个文件的构建,并且可以指定生成的可执行文件的名称。

  1. 用途: go build 命令主要用于编译测试。它会编译指定的源码文件或代码包及其依赖。

  2. 普通包 vs. main 包:

    • 对于普通包:执行 go build 后不会生成任何文件。
      举例:
      在这里插入图片描述
    • 对于 main 包:只执行 go build 会在当前目录下生成一个可执行文件。要在 $GOPATH/bin 目录下生成相应的可执行文件,需要执行 go install 或者使用 go build -o 路径/可执行文件
  3. 单文件 vs. 多文件:

    • 如果某个文件夹下有多个文件,而只想编译其中的某一个文件,可以在 go build 之后加上文件名,例如 go build a.go
    • 默认情况下,go build 会编译当前目录下的所有 go 文件。
  4. 指定输出文件名: 可以使用 -o 标志指定编译输出的文件名。默认情况下,输出文件名为包名(对于非 main 包)或第一个源文件的文件名(对于 main 包)。

  5. 忽略文件: go build 会忽略目录下以"_“或”."开头的 go 文件。

  6. 跨平台编译: 如果源代码需要针对不同的操作系统进行处理,可以根据不同的操作系统后缀来命名文件。

  7. 库源码文件编译: 对于库源码文件,go build 只会进行检查性的编译,而不会生成任何结果文件。

  8. 示例: 执行 go build 编译命令源码文件时,会在该命令的执行目录中生成一个可执行文件。如果跟了代码包导入路径作为参数,则该代码包及其依赖都会被编译。

  9. 执行过程: 类似于 go rungo build 在编译后会将生成的可执行文件重命名并移动到当前目录下。

参考:

https://zhuanlan.zhihu.com/p/619500945

go install 和 go get

go getgo install 是 Go 语言中两个常用的命令,它们虽然有一些相似之处,但在功能上有一些不同。

  1. go get:

    • go get 命令用于从远程仓库中获取并安装指定的包或模块。它通常用于获取项目的依赖项。
    • 如果执行 go get 命令时指定了包或模块的路径,它将尝试从远程仓库中下载该包或模块,并将其放置在 $GOPATH/src 目录下的相应位置。
    • go get 还会安装该包或模块所依赖的其他包或模块。
  2. go install:

    • go install 命令用于编译并安装指定的包或可执行文件。
    • 如果执行 go install 命令时指定了包的路径,它将编译该包并将生成的二进制文件安装到 $GOPATH/bin 目录(或 $GOBIN 目录)下。
    • 如果执行 go install 命令时指定了可执行文件的路径,它将编译该可执行文件并将生成的二进制文件安装到 $GOPATH/bin 目录(或 $GOBIN 目录)下。

在实践中,通常情况下,我们使用 go get 来获取项目的依赖项,而使用 go install 来构建并安装我们自己的代码或可执行文件。

go install 命令

  • 用途: 编译并安装代码包或者源码文件。

  • 流程: 分为两步:

    1. 第一步是生成结果文件(可执行文件或者.a 包)。
    2. 第二步是将编译好的结果移到 $GOPATH/pkg 或者 $GOPATH/bin
  • 可执行文件: 一般由带有 main 函数的 Go 文件产生,具有函数入口,可以直接运行。

  • .a 应用包: 一般由不包含 main 函数的 Go 文件产生,没有函数入口,只能被调用。

go get 命令

  • 用途: 从远程代码仓库(如 GitHub)下载并安装代码包。

  • 注意:

    • go get 命令将当前代码包下载到 $GOPATH 中的第一个工作区的 src 目录,并进行安装。
    • 从 Go 1.17 版本开始,go get 仅用于下载库和更新 mod 文件,并不会执行安装操作。

其他命令

go clean 命令是用来移除当前源码包里面编译生成的文件,这些文件包括

_obj/ 旧的 object 目录,由 Makefiles 遗留

_test/ 旧的 test 目录,由 Makefiles 遗留

_testmain.go 旧的 gotest 文件,由 Makefiles 遗留

test.out 旧的 test 记录,由 Makefiles 遗留

build.out 旧的 test 记录,由 Makefiles 遗留

*.[568ao] object 文件,由 Makefiles 遗留

DIR(.exe) 由 go build 产生

DIR.test(.exe) 由 go test -c 产生

MAINFILE(.exe) 由 go build MAINFILE.go 产生

go fmt 命令主要是用来帮你格式化所写好的代码文件。

go test 命令,会自动读取源码目录下面名为*_test.go 的文件,生成并运行测试用的可执行文件。默认的情况下,不需要任何的参数,它会自动把你源码包下面所有 test 文件测试完毕,当然你也可以带上参数,详情请参考 go help testflag

go doc 命令其实就是一个很强大的文档工具。

go fix 用来修复以前老版本的代码到新版本,例如 go1 之前老版本的代码转化到 go1

go version 查看 go 当前的版本

go env 查看当前 go 的环境变量

go list 列出当前全部安装的 package