# 6.3 总体逻辑

创建初始化任务的主逻辑在文件`cmd/compile/internal/pkginit/init.go`的方法`Task()`中，刨去细节处理，总体逻辑可以整理如下：

```go
func Task() *ir.Name {
	// Step 1: 处理 import 语句，按顺序查找出所有依赖包中的初始化任务
	var deps []*obj.LSym
	for _, pkg := range typecheck.Target.Imports {
		n := typecheck.Resolve(ir.NewIdent(base.Pos, pkg.Lookup(".inittask")))
		deps = append(deps, n.(*ir.Name).Linksym())
	}

	// Step 2: 处理全局变量赋值语句，函数 initOrder 用来确定初始化顺序，并且返回需要在运行时初始化的赋值语句
	nf := initOrder(typecheck.Target.Decls)
	var fns []*obj.LSym
	if len(nf) > 0 {
		// 如果有需要动态执行的赋值语句，则创建一个 init 函数，并将该函数的函数体设置为所有的动态赋值语句
		// 该 init 函数在所有用户自定义的 init 函数之前
		initializers := typecheck.Lookup("init")
		fn := typecheck.DeclFunc(initializers, ir.NewFuncType(base.Pos, nil, nil, nil))
		fn.Body = nf
		typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
		fns = append(fns, fn.Linksym())
	}

	// Step 3: 处理用户申明的 init 函数，按照顺序添加到 fns 中
	for _, fn := range typecheck.Target.Inits {
		// 代码优化，去除函数中的无效代码，如果优化之后函数体为空，则忽略该 init 函数
		deadcode.Func(fn)

		if len(fn.Body) == 1 {
			if stmt := fn.Body[0]; stmt.Op() == ir.OBLOCK && len(stmt.(*ir.BlockStmt).List) == 0 {
				continue
			}
		}
		fns = append(fns, fn.Nname.Linksym())
	}

	// Step 4: 创建初始化任务 .inittask, 依次写入 deps 及 fns
	sym := typecheck.Lookup(".inittask")
	task := typecheck.NewName(sym)
	task.Class = ir.PEXTERN
	sym.Def = task
	lsym := task.Linksym()
	ot := 0
	ot = objw.Uintptr(lsym, ot, 0) // state: not initialized yet
	ot = objw.Uintptr(lsym, ot, uint64(len(deps)))
	ot = objw.Uintptr(lsym, ot, uint64(len(fns)))
	for _, d := range deps {
		ot = objw.SymPtr(lsym, ot, d, 0)
	}
	for _, f := range fns {
		ot = objw.SymPtr(lsym, ot, f, 0)
	}
	return task
}
```

Step 4 的代码细节不用太在意，重点是我们知道其最终创建了一个名叫`.inittask`的符号对象，并依次将前面三步的初始化内容写了进去。回顾[代码结构](/6.-golang-bian-yi-qi-chu-shi-hua-ren-wu/6.2-dai-ma-jie-gou.md), 编译器最终将`.inittask`设置为 Export 符号，并最终在编译的最后阶段将该符号对象写入对象文件（.o 或者 .a 文件）。所以在 Step 1 中可以通过该名字查找到其他依赖包中的初始化任务。

接下来，我们详细探讨一下 Step 2 中对全局变量的赋值语句的处理逻辑。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gocompiler.shizhz.me/6.-golang-bian-yi-qi-chu-shi-hua-ren-wu/6.3-zong-ti-luo-ji.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
