Go 编译构建的一些细节

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 复制代码
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

相关推荐
2401_857439692 分钟前
SpringBoot框架在资产管理中的应用
java·spring boot·后端
怀旧6664 分钟前
spring boot 项目配置https服务
java·spring boot·后端·学习·个人开发·1024程序员节
阿华的代码王国24 分钟前
【SpringMVC】——Cookie和Session机制
java·后端·spring·cookie·session·会话
德育处主任Pro1 小时前
『Django』APIView基于类的用法
后端·python·django
哎呦没3 小时前
SpringBoot框架下的资产管理自动化
java·spring boot·后端
2401_857600953 小时前
SpringBoot框架的企业资产管理自动化
spring boot·后端·自动化
NiNg_1_2347 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
Chrikk9 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*9 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue9 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang