阅读go语言源代码1
前面大概说过bison与yacc的语法,那么其实go也是用bison来实现的,下面来说说怎么阅读go语言源代码。要看代码首先得找到代码的入口,怎么找呢?你可能首先想到grep main是的,一般来说这是一个没有争议的办法,但是对于go语言来说,这个办法对,也不对。怎么说呢?我们用gdb来进行debug就会看到所有的go语言程序的入口居然都在src/lib9/main.c里的main函数。
#include
#define NOPLAN9DEFINES
#include
extern void p9main(int, char**);
int
main(int argc, char **argv)
{
p9main(argc, argv);
exits("main");
return 99;
}
从go/include/libc.h中里我们可以看到这么一句
#ifndef NOPLAN9DEFINES
#define main p9main
#endif
也就是说,在go语言源代码里main函数都重命名了,所有的函数入口都变成了src/lib9/mina.c,也实际的入口各自的代码里,因此说入口是各自的main这句话,对也不对。
那么先大概说一下go语言的代码结构
.
|-- bin//我自己定义的安装目录
|-- doc//相关文档,godoc就是利用这个目录
| |-- codelab
| | `-- wiki
| |-- codewalk
| |-- devel
| |-- gopher
| |-- progs
| `-- talks
| `-- io2010
|-- include//一些全局的定义文件
|-- lib//一些lib9相关的全局库
| |-- codereview
| `-- godoc
|-- misc//一些工具
| |-- arm
| |-- bash
| |-- bbedit
| |-- cgo
| | |-- gmp
| | |-- life
| | `-- stdio
| |-- dashboard
| | `-- godashboard
| |-- emacs
| |-- kate
| |-- nacl
| |-- vim
| | |-- ftdetect
| | `-- syntax
| `-- xcode
|-- pkg//编译好的go库
| `-- linux_amd64
| |-- archive
| |-- compress
| |-- container
| |-- crypto
| |-- debug
| |-- encoding
| |-- exp
| |-- go
| |-- hash
| |-- http
| |-- image
| |-- io
| |-- os
| |-- rpc
| |-- runtime
| `-- testing
|-- src
| |-- cmd//go语言相关的程序
| | |-- 5a
| | |-- 5c
| | |-- 5g
| | |-- 5l
| | |-- 6a//amd64的汇编器
| | |-- 6c//amd64的c编译器
| | |-- 6g//amd64的编译器
| | |-- 6l//amd64的链接器
| | |-- 8a
| | |-- 8c
| | |-- 8g
| | |-- 8l
| | |-- cc
| | |-- cgo
| | |-- cov
| | |-- ebnflint
| | |-- gc
| | |-- godefs
| | |-- godoc
| | |-- gofmt
| | |-- goinstall
| | |-- gopack
| | |-- gotest
| | |-- goyacc
| | |-- hgpatch
| | |-- ld
| | |-- nm
| | `-- prof
| |-- lib9//lib9相关的库
| | |-- fmt
| | `-- utf
| |-- libbio//全局库
| |-- libcgo//cgo的库
| |-- libmach//库
| `-- pkg//go库
| |-- archive
| |-- asn1
| |-- big
| |-- bufio
| |-- bytes
| |-- cmath
| |-- compress
| |-- container
| |-- crypto
| |-- debug
| |-- ebnf
| |-- encoding
| |-- exec
| |-- exp
| |-- expvar
| |-- flag
| |-- fmt
| |-- go
| |-- gob
| |-- hash
| |-- html
| |-- http
| |-- image
| |-- io
| |-- json
| |-- log
| |-- math
| |-- mime
| |-- net
| |-- netchan
| |-- nntp
| |-- once
| |-- os
| |-- patch
| |-- path
| |-- rand
| |-- reflect
| |-- regexp
| |-- rpc
| |-- runtime
| |-- scanner
| |-- sort
| |-- strconv
| |-- strings
| |-- sync
| |-- syscall
| |-- syslog
| |-- tabwriter
| |-- template
| |-- testing
| |-- time
| |-- unicode
| |-- unsafe
| |-- utf16
| |-- utf8
| |-- websocket
| `-- xml
`-- test//测试
|-- bench
|-- bugs
|-- chan
|-- fixedbugs
| |-- bug083.dir
| |-- bug088.dir
| |-- bug106.dir
| |-- bug133.dir
| |-- bug160.dir
| |-- bug191.dir
| |-- bug222.dir
| |-- bug226.dir
| |-- bug248.dir
| `-- bug282.dir
|-- garbage
|-- interface
|-- ken
|-- nilptr
`-- syntax
我们先来看一个go语言的hello world文件hello.go
package main
func main(){
println("Hello World");
}
那么这个文件要被编译链接成一个可执行文件,那么要执行如下命令:
6g hello.o
6l hello.6 -o hello
很显然最关键的就是6g和6l两个程序,那么我们就从6g开始
首先gdb -tui打开tui界面的gdb程序
然后输入file 6g载入6g程序,就可以看到
/home/hoping/go/src/lib9/main.c,然后输入start后,step进入了/home/hoping/go/src/cmd/gc/lex.c的main函数
因此我们只需要看这个文件就大概可以看到程序的执行流程了。接下来暂时不需要gdb了,我们换vi和ctags。
在go目录执行ctags -R *来生成tag,然后用vi打开lex.c进入main函数,其实即使你看了这个函数也不会有太多收获。
正如我们前面说过的那样,6g是用bison的,那么显然我们需要找到bison文件和yylex函数即可。既然入口在gc文件夹,那么猜想y文件也在gc文件夹,于是进入ls *.y之后可以看到go.y。而go.y的输入全是由yylex函数来提供的。所以首先我们来看看yylex函数,在go文件夹下执行vim -t yylex,然后选择gc文件夹那个。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。