从main入口开始谈golang

一、问题

1.我们知道一个可独立运行的golang程序,一定要有个main.main(),因为main()是程序的入口。可你知道为什么一定要求是main.main()吗?

2.main()在执行前,根据package的初始化顺序,会先初始化依赖的package,然后初始化main,这些操作是在什么时候完成的呢?

二、溯源

1.源码

以下代码位于go/src/runtime/proc.go,这些源码将会给我们答案。

//go:linkname main_inittask main..inittask
var main_inittask initTask

...

//go:linkname main_main main.main
func main_main()

...

// The main goroutine.
func main() {
   

    ...

    gcenable()//启动gc,sweeping and scavenging

    main_init_done = make(chan bool)

    ...

    doInit(&main_inittask)//此处进行初始化任务

    close(main_init_done)

    ...

    if isarchive || islibrary {
   
        // A program compiled with -buildmode=c-archive or c-shared
        // has a main, but it is not executed.
        return
    }
    fn := main_main // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime
    fn()
    ...
}

2.go:link

在正式理解源码之前我们需要学习下go:link,以下是官方说法:

//go:linkname localname [importpath.name]
The //go:linkname directive instructs the compiler to use “importpath.name” as the object file symbol name for the variable or function declared as “localname” in the source code. If the “importpath.name” argument is omitted, the directive uses the symbol's default object file symbol name and only has the effect of making the symbol accessible to other packages. Because this directive can subvert the type system and package modularity, it is only enabled in files that have imported "unsafe".

简单来说通过这种机制,可以实现调用其他包不能导出的内容。

3.main的入口问题

根据go:link,我们知道

//go:linkname main_main main.main
func main_main()//调用的就是我们熟悉的main package的main()

因此,

fn := main_main // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime
fn()//此处即为执行main(),正式进入我们自己开发的程序逻辑

代码中的fn()即为main(),执行main()即进入我们自己开发的程序逻辑,此处回答了问题1。

4.初始化问题

我们在go:link中提过

我们先看下main_inittask:main_main()即为main.main(),那var main_inittask initTask又是什么呢?我们的main中是没有initTask的,有的只是init,这两者有什么联系呢?问题比较复杂,已经涉及到compile中的内容,有兴趣的可以去看下位于go/src/cmd/compile/internal/gc/init.go中fninit相关的内容,此处不再详细说明。

// fninit makes an initialization record for the package.
// See runtime/proc.go:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值