go 命令谈起

Go 程序的生命周期要从执行 go 命令开始谈起。

2.1.1 Go Run 与 Go Build 命令

  • 设置具体的指令
  • go run –> run.CmdRun
  • go build –> work.CmdBuild
// src/cmd/go/main.go
func init() {
    base.Go.Commands = []*base.Command{
        work.CmdBuild,
        run.CmdRun,
        ...
    }
}
func main() {
    flag.Usage = base.Usage
    flag.Parse()
    log.SetFlags(0)

    args := flag.Args()
    if len(args) < 1 {
        base.Usage()
    }

    ...

    // 从左至右依次解析 go 指令
BigCmdLoop:
    for bigCmd := base.Go; ; {
        for _, cmd := range bigCmd.Commands {
            // 匹配具体的指令,args[0] 是 go 指令后紧跟的第一个参数,如 run、build。
            if cmd.Name() != args[0] {
                continue
            }
            ...
            // 根据指令和参数执行编译或运行
            cmd.Run(cmd, args)
            base.Exit()
            return
        }
        ...
    }
}

TODO:

// src/cmd/go/internal/work/build.go
var CmdBuild = &base.Command{
    UsageLine: "go build [-o output] [-i] [build flags] [packages]",
    Short:     "compile packages and dependencies",
    Long: `...`,
}
func init() {
    CmdBuild.Run = runBuild
    // -o 参数解析
    CmdBuild.Flag.StringVar(&cfg.BuildO, "o", "", "output file or directory")
    ...

    switch build.Default.Compiler {
    case "gc", "gccgo":
        buildCompiler{}.Set(build.Default.Compiler) // gc
    }
}
type buildCompiler struct{}

func (c buildCompiler) Set(value string) error {
    switch value {
    case "gc":
        BuildToolchain = gcToolchain{}
    ...
    }
    ...

    return nil
}
func runBuild(cmd *base.Command, args []string) {
    BuildInit()
    var b Builder
    b.Init()

    pkgs := load.PackagesForBuild(args)
    ...

    depMode := ModeBuild
    if cfg.BuildI {
        depMode = ModeInstall
    }
    ...

    a := &Action{Mode: "go build"}
    for _, p := range pkgs {
        a.Deps = append(a.Deps, b.AutoAction(ModeBuild, depMode, p))
    }
    ...
    b.Do(a)
}
type Builder struct {
    WorkDir     string               // the temporary work directory (ends in filepath.Separator)
    actionCache map[cacheKey]*Action // a cache of already-constructed actions
    mkdirCache  map[string]bool      // a cache of created directories
    flagCache   map[[2]string]bool   // a cache of supported compiler flags
    Print       func(args ...interface{}) (int, error)

    IsCmdList           bool // running as part of go list; set p.Stale and additional fields below
    NeedError           bool // list needs p.Error
    NeedExport          bool // list needs p.Export
    NeedCompiledGoFiles bool // list needs p.CompiledGoFIles

    objdirSeq int // counter for NewObjdir
    pkgSeq    int

    output    sync.Mutex
    scriptDir string // current directory in printed script

    exec      sync.Mutex
    readySema chan bool
    ready     actionQueue

    id           sync.Mutex
    toolIDCache  map[string]string // tool name -> tool ID
    buildIDCache map[string]string // file name -> build ID
}
// AutoAction returns the "right" action for go build or go install of p.
func (b *Builder) AutoAction(mode, depMode BuildMode, p *load.Package) *Action {
    if p.Name == "main" {
        return b.LinkAction(mode, depMode, p)
    }
    return b.CompileAction(mode, depMode, p)
}

TODO: 未完成,当前内容来源于 src/cmd/compile/README.md

最后编辑: kuteng  文档更新时间: 2021-10-19 14:31   作者:kuteng