wordpress后台页面加载慢临沂网站优化如何
web/
2025/9/27 15:53:38/
文章来源:
wordpress后台页面加载慢,临沂网站优化如何,网站备案可以自己备案吗,美好乡村建设网站引入编译链接概述 编译过程 词法分析语法分析语义分析中间代码生成目标代码生成与优化链接过程Go 程序启动GoRoot 和 GoPathGo 命令详解 go buildgo installgo run总结参考资料
引入
我们从一个 Hello World 的例子开始#xff1a;
package mainimport fmtfunc…
引入编译链接概述 编译过程 词法分析语法分析语义分析中间代码生成目标代码生成与优化链接过程Go 程序启动GoRoot 和 GoPathGo 命令详解 go buildgo installgo run总结参考资料
引入
我们从一个 Hello World 的例子开始
package mainimport fmtfunc main() {fmt.Println(hello world)
}当我用我那价值 1800 元的 cherry 键盘潇洒地敲完上面的 hello world 代码时保存在硬盘上的 hello.go 文件就是一个字节序列了每个字节代表一个字符。
用 vim 打开 hello.go 文件在命令行模式下输入命令
:%!xxd就能在 vim 里以十六进制查看文件内容 最左边的一列代表地址值中间一列代表文本对应的 ASCII 字符最右边的列就是我们的代码。再在终端里执行 man ascii 和 ASCII 字符表一对比就能发现中间的列和最右边的列是一一对应的。也就是说刚刚写完的 hello.go 文件都是由 ASCII 字符表示的它被称为文本文件其他文件被称为二进制文件。
当然更深入地看计算机中的所有数据像磁盘文件、网络中的数据其实都是一串比特位组成取决于如何看待它。在不同的情景下一个相同的字节序列可能表示成一个整数、浮点数、字符串或者是机器指令。
而像 hello.go 这个文件8 个 bit也就是一个字节看成一个单位假定源程序的字符都是 ASCII 码最终解释成人类能读懂的 Go 源码。
Go 程序并不能直接运行每条 Go 语句必须转化为一系列的低级机器语言指令将这些指令打包到一起并以二进制磁盘文件的形式存储起来也就是可执行目标文件。
从源文件到可执行目标文件的转化过程 完成以上各个阶段的就是 Go 编译系统。你肯定知道大名鼎鼎的 GCCGNU Compile Collection中文名为 GNU 编译器套装它支持像 CCJavaPythonObjective-CAdaFortranPascal能够为很多不同的机器生成机器码。
可执行目标文件可以直接在机器上执行。一般而言先执行一些初始化的工作找到 main 函数的入口执行用户写的代码执行完成后main 函数退出再执行一些收尾的工作整个过程完毕。
在接下来的文章里我们将探索编译和运行的过程。
编译链接概述
Go 源码里的编译器源码位于 src/cmd/compile 路径下链接器源码位于 src/cmd/link 路径下。
编译过程
我比较喜欢用 IDE集成开发环境来写代码 Go 源码用的 Goland有时候直接点击 IDE 菜单栏里的“运行”按钮程序就跑起来了。这实际上隐含了编译和链接的过程我们通常将编译和链接合并到一起的过程称为构建Build。
编译过程就是对源文件进行词法分析、语法分析、语义分析、优化最后生成汇编代码文件以 .s 作为文件后缀。
之后汇编器会将汇编代码转变成机器可以执行的指令。由于每一条汇编语句几乎都与一条机器指令相对应所以只是一个简单的一一对应比较简单没有语法、语义分析也没有优化这些步骤。
编译器是将高级语言翻译成机器语言的一个工具编译过程一般分为 6 步扫描、语法分析、语义分析、源代码优化、代码生成、目标代码优化。下图来自《程序员的自我修养》 词法分析
通过前面的例子我们知道Go 程序文件在机器看来不过是一堆二进制位。我们能读懂是因为 Goland 按照 ASCII 码实际上是 UTF-8把这堆二进制位进行了编码。例如把 8个 bit 位分成一组对应一个字符通过对照 ASCII 码表就可以查出来。
当把所有的二进制位都对应成了 ASCII 码字符后我们就能看到有意义的字符串。它可能是关键字例如package可能是字符串例如“Hello World”。
词法分析其实干的就是这个。输入是原始的 Go 程序文件在词法分析器看来就是一堆二进制位根本不知道是什么东西经过它的分析后变成有意义的记号。简单来说词法分析是计算机科学中将字符序列转换为标记token序列的过程。
我们来看一下维基百科上给出的定义 词法分析lexical analysis是计算机科学中将字符序列转换为标记token序列的过程。进行词法分析的程序或者函数叫作词法分析器lexical analyzer简称lexer也叫扫描器scanner。词法分析器一般以函数的形式存在供语法分析器调用。 .go 文件被输入到扫描器Scanner它使用一种类似于有限状态机的算法将源代码的字符系列分割成一系列的记号Token。
记号一般分为这几类关键字、标识符、字面量包含数字、字符串、特殊符号如加号、等号。
例如对于如下的代码
slice[i] i * (2 6)总共包含 16 个非空字符经过扫描后
记号类型slice标识符[左方括号i标识符]右方括号赋值i标识符*乘号(左圆括号2数字加号6数字)右圆括号
上面的例子源自《程序员的自我修养》主要讲解编译、链接相关的内容很精彩推荐研读。
Go 语言本文的 Go 版本是 1.9.2扫描器支持的 Token 在源码中的路径
src/cmd/compile/internal/syntax/token.go感受一下
var tokstrings [...]string{// source control_EOF: EOF,// names and literals_Name: name,_Literal: literal,// operators and operations_Operator: op,_AssignOp: op,_IncOp: opop,_Assign: ,_Define: :,_Arrow: -,_Star: *,// delimitors_Lparen: (,_Lbrack: [,_Lbrace: {,_Rparen: ),_Rbrack: ],_Rbrace: },_Comma: ,,_Semi: ;,_Colon: :,_Dot: .,_DotDotDot: ...,// keywords_Break: break,_Case: case,_Chan: chan,_Const: const,_Continue: continue,_Default: default,_Defer: defer,_Else: else,_Fallthrough: fallthrough,_For: for,_Func: func,_Go: go,_Goto: goto,_If: if,_Import: import,_Interface: interface,_Map: map,_Package: package,_Range: range,_Return: return,_Select: select,_Struct: struct,_Switch: switch,_Type: type,_Var: var,
}还是比较熟悉的包括名称和字面量、操作符、分隔符和关键字。
而扫描器的路径是
src/cmd/compile/internal/syntax/scanner.go其中最关键的函数就是 next 函数它不断地读取下一个字符不是下一个字节因为 Go 语言支持 Unicode 编码并不是像我们前面举得 ASCII 码的例子一个字符只有一个字节直到这些字符可以构成一个 Token。
func (s *scanner) next() {
// ……redo:// skip white spacec : s.getr()for c || c \t || c \n !nlsemi || c \r {c s.getr()}// token starts.line, s.col s.source.line0, s.source.col0if isLetter(c) || c utf8.RuneSelf s.isIdentRune(c, true) {s.ident()return}switch c {// ……case \n:s.lit newlines.tok _Semicase 0, 1, 2, 3, 4, 5, 6, 7, 8, 9:s.number(c)// ……default:s.tok 0s.error(fmt.Sprintf(invalid character %#U, c))goto redoreturnassignop:if c {s.tok _AssignOpreturn}s.ungetr()s.tok _Operator
}代码的主要逻辑就是通过 c : s.getr() 获取下一个未被解析的字符并且会跳过之后的空格、回车、换行、tab 字符然后进入一个大的 switch-case 语句匹配各种不同的情形最终可以解析出一个 Token并且把相关的行、列数字记录下来这样就完成一次解析过程。 当前包中的词法分析器 scanner 也只是为上层提供了 next 方法词法解析的过程都是惰性的只有在上层的解析器需要时才会调用 next 获取最新的 Token。 语法分析
上一步生成的 Token 序列需要经过进一步处理生成一棵以表达式为结点的语法树。
比如最开始的那个例子slice[i] i * (2 6)得到的一棵语法树如下 整个语句被看作是一个赋值表达式左子树是一个数组表达式右子树是一个乘法表达式数组表达式由 2 个符号表达式组成乘号表达式则是由一个符号表达式和一个加号表达式组成加号表达式则是由两个数字组成。符号和数字是最小的表达式它们不能再被分解通常作为树的叶子节点。
语法分析的过程可以检测一些形式上的错误例如括号是否缺少一半 号表达式缺少一个操作数等。 语法分析是根据某种特定的形式文法Grammar对 Token 序列构成的输入文本进行分析并确定其语法结构的一种过程。 语义分析
语法分析完成后我们并不知道语句的具体意义是什么。像上面的 * 号的两棵子树如果是两个指针这是不合法的但语法分析检测不出来语义分析就是干这个事。
编译期所能检查的是静态语义可以认为这是在“代码”阶段包括变量类型的匹配、转换等。例如将一个浮点值赋给一个指针变量的时候明显的类型不匹配就会报编译错误。而对于运行期间才会出现的错误不小心除了一个 0 语义分析是没办法检测的。
语义分析阶段完成之后会在每个节点上标注上类型 Go 语言编译器在这一阶段检查常量、类型、函数声明以及变量赋值语句的类型然后检查哈希中键的类型。实现类型检查的函数通常都是几千行的巨型 switch/case 语句。 类型检查是 Go 语言编译的第二个阶段在词法和语法分析之后我们得到了每个文件对应的抽象语法树随后的类型检查会遍历抽象语法树中的节点对每个节点的类型进行检验找出其中存在的语法错误。 在这个过程中也可能会对抽象语法树进行改写这不仅能够去除一些不会被执行的代码对编译进行优化提高执行效率而且也会修改 make、new 等关键字对应节点的操作类型。 例如比较常用的 make 关键字用它可以创建各种类型如 slicemapchannel 等等。到这一步的时候对于 make 关键字也就是 OMAKE 节点会先检查它的参数类型根据类型的不同进入相应的分支。如果参数类型是 slice就会进入 TSLICE case 分支检查 len 和 cap 是否满足要求如 len cap。最后节点类型会从 OMAKE 改成 OMAKESLICE。
中间代码生成
我们知道编译过程一般可以分为前端和后端前端生成和平台无关的中间代码后端会针对不同的平台生成不同的机器码。
前面词法分析、语法分析、语义分析等都属于编译器前端之后的阶段属于编译器后端。
编译过程有很多优化的环节在这个环节是指源代码级别的优化。它将语法树转换成中间代码它是语法树的顺序表示。
中间代码一般和目标机器以及运行时环境无关它有几种常见的形式三地址码、P-代码。例如最基本的三地址码是这样的
x y op z表示变量 y 和 变量 z 进行 op 操作后赋值给 x。op 可以是数学运算例如加减乘除。
前面我们举的例子可以写成如下的形式
t1 2 6
t2 i * t1
slice[i] t2这里 2 6 是可以直接计算出来的这样就把 t1 这个临时变量“优化”掉了而且 t1 变量可以重复利用因此 t2 也可以“优化”掉。优化之后
t1 i * 8
slice[i] t1Go 语言的中间代码表示形式为 SSAStatic Single-Assignment静态单赋值之所以称之为单赋值是因为每个名字在 SSA 中仅被赋值一次。。
这一阶段会根据 CPU 的架构设置相应的用于生成中间代码的变量例如编译器使用的指针和寄存器的大小、可用寄存器列表等。中间代码生成和机器码生成这两部分会共享相同的设置。
在生成中间代码之前会对抽象语法树中节点的一些元素进行替换。这里引用《面向信仰编程》编译原理相关博客里的一张图 例如对于 map 的操作 m[i]在这里会被转换成 mapacess 或 mapassign。 Go 语言的主程序在执行时会调用 runtime 中的函数也就是说关键字和内置函数的功能其实是由语言的编译器和运行时共同完成的。 中间代码的生成过程其实就是从 AST 抽象语法树到 SSA 中间代码的转换过程在这期间会对语法树中的关键字在进行一次更新更新后的语法树会经过多轮处理转变最后的 SSA 中间代码。 目标代码生成与优化
不同机器的机器字长、寄存器等等都不一样意味着在不同机器上跑的机器码是不一样的。最后一步的目的就是要生成能在不同 CPU 架构上运行的代码。
为了榨干机器的每一滴油水目标代码优化器会对一些指令进行优化例如使用移位指令代替乘法指令等。
这块实在没能力深入幸好也不需要深入。对于应用层的软件开发工程师来说了解一下就可以了。
链接过程
编译过程是针对单个文件进行的文件与文件之间不可避免地要引用定义在其他模块的全局变量或者函数这些变量或函数的地址只有在此阶段才能确定。
链接过程就是要把编译器生成的一个个目标文件链接成可执行文件。最终得到的文件是分成各种段的比如数据段、代码段、BSS段等等运行时会被装载到内存中。各个段具有不同的读写、执行属性保护了程序的安全运行。
这部分内容推荐看《程序员的自我修养》和《深入理解计算机系统》。
Go 程序启动
仍然使用 hello-world 项目的例子。在项目根目录下执行
go build -gcflags -N -l -o hello src/main.go-gcflags -N -l 是为了关闭编译器优化和函数内联防止后面在设置断点的时候找不到相对应的代码位置。
得到了可执行文件 hello执行
[qcraoqcrao hello-world]$ gdb hello进入 gdb 调试模式执行 info files得到可执行文件的文件头列出了各种段 同时我们也得到了入口地址0x450e20。
(gdb) b *0x450e20
Breakpoint 1 at 0x450e20: file /usr/local/go/src/runtime/rt0_linux_amd64.s, line 8.这就是 Go 程序的入口地址我是在 linux 上运行的所以入口文件为 src/runtime/rt0_linux_amd64.sruntime 目录下有各种不同名称的程序入口文件支持各种操作系统和架构代码为
TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8LEAQ 8(SP), SI // argvMOVQ 0(SP), DI // argcMOVQ $main(SB), AXJMP AX主要是把 argcargv 从内存拉到了寄存器。这里 LEAQ 是计算内存地址然后把内存地址本身放进寄存器里也就是把 argv 的地址放到了 SI 寄存器中。最后跳转到
TEXT main(SB),NOSPLIT,$-8MOVQ $runtime·rt0_go(SB), AXJMP AX继续跳转到 runtime·rt0_go(SB)位置/usr/local/go/src/runtime/asm_amd64.s代码
TEXT runtime·rt0_go(SB),NOSPLIT,$0// 省略很多 CPU 相关的特性标志位检查的代码// 主要是看不懂^_^// ………………………………// 下面是最后调用的一些函数比较重要// 初始化执行文件的绝对路径CALL runtime·args(SB)// 初始化 CPU 个数和内存页大小CALL runtime·osinit(SB)// 初始化命令行参数、环境变量、gc、栈空间、内存管理、所有 P 实例、HASH算法等CALL runtime·schedinit(SB)// 要在 main goroutine 上运行的函数MOVQ $runtime·mainPC(SB), AX // entryPUSHQ AXPUSHQ $0 // arg size// 新建一个 goroutine该 goroutine 绑定 runtime.main放在 P 的本地队列等待调度CALL runtime·newproc(SB)POPQ AXPOPQ AX// 启动M开始调度goroutineCALL runtime·mstart(SB)MOVL $0xf1, 0xf1 // crashRETDATA runtime·mainPC0(SB)/8,$runtime·main(SB)
GLOBL runtime·mainPC(SB),RODATA,$8 参考文献里的一篇文章【探索 golang 程序启动过程】研究得比较深入总结下 检查运行平台的CPU设置好程序运行需要相关标志。 TLS的初始化。runtime.args、runtime.osinit、runtime.schedinit 三个方法做好程序运行需要的各种变量与调度器。runtime.newproc创建新的goroutine用于绑定用户写的main方法。runtime.mstart开始goroutine的调度。
最后用一张图来总结 go bootstrap 过程吧 main 函数里执行的一些重要的操作包括新建一个线程执行 sysmon 函数定期垃圾回收和调度抢占启动 gc执行所有的 init 函数等等。
上面是启动过程看一下退出过程 当 main 函数执行结束之后会执行 exit(0) 来退出进程。若执行 exit(0) 后进程没有退出main 函数最后的代码会一直访问非法地址 exit(0)
for {var x *int32*x 0
}正常情况下一旦出现非法地址访问系统会把进程杀死用这样的方法确保进程退出。 关于程序退出这一段的阐述来自群聊《golang runtime 阅读》又是一个高阶的读源码的组织github 主页见参考资料。
当然 Go 程序启动这一部分其实还会涉及到 fork 一个新进程、装载可执行文件控制权转移等问题。还是推荐看前面的两本书我觉得我不会写得更好就不叙述了。
GoRoot 和 GoPath
GoRoot 是 Go 的安装路径。mac 或 unix 是在 /usr/local/go 路径上来看下这里都装了些什么 bin 目录下面 pkg 目录下面 Go 工具目录如下其中比较重要的有编译器 compile链接器 link GoPath 的作用在于提供一个可以寻找 .go 源码的路径它是一个工作空间的概念可以设置多个目录。Go 官方要求GoPath 下面需要包含三个文件夹
src
pkg
binsrc 存放源文件pkg 存放源文件编译后的库文件后缀为 .abin 则存放可执行文件。
Go 命令详解
直接在终端执行
go就能得到和 go 相关的命令简介 和编译相关的命令主要是
go build
go install
go rungo build
go build 用来编译指定 packages 里的源码文件以及它们的依赖包编译的时候会到 $GoPath/src/package 路径下寻找源码文件。go build 还可以直接编译指定的源码文件并且可以同时指定多个。
通过执行 go help build 命令得到 go build 的使用方法
usage: go build [-o output] [-i] [build flags] [packages]-o 只能在编译单个包的时候出现它指定输出的可执行文件的名字。
-i 会安装编译目标所依赖的包安装是指生成与代码包相对应的 .a 文件即静态库文件后面要参与链接并且放置到当前工作区的 pkg 目录下且库文件的目录层级和源码层级一致。
至于 build flags 参数build, clean, get, install, list, run, test 这些命令会共用一套
参数作用-a强制重新编译所有涉及到的包包括标准库中的代码包这会重写 /usr/local/go 目录下的 .a 文件-n打印命令执行过程不真正执行-p n指定编译过程中命令执行的并行数n 默认为 CPU 核数-race检测并报告程序中的数据竞争问题-v打印命令执行过程中所涉及到的代码包名称-x打印命令执行过程中所涉及到的命令并执行-work打印编译过程中的临时文件夹。通常情况下编译完成后会被删除
我们知道Go 语言的源码文件分为三类命令源码、库源码、测试源码。 命令源码文件是 Go 程序的入口包含 func main() 函数且第一行用 package main 声明属于 main 包。 库源码文件主要是各种函数、接口等例如工具类的函数。 测试源码文件以 _test.go 为后缀的文件用于测试程序的功能和性能。 注意go build 会忽略 *_test.go 文件。
我们通过一个很简单的例子来演示 go build 命令。我用 Goland 新建了一个 hello-world 项目为了展示引用自定义的包和之前的 hello-world 程序不同项目的结构如下 最左边可以看到项目的结构包含三个文件夹binpkgsrc。其中 src 目录下有一个 main.go里面定义了 main 函数是整个项目的入口也就是前面提过的所谓的命令源码文件src 目录下还有一个 util 目录里面有 util.go 文件定义了一个可以获取本机 IP 地址的函数也就是所谓的库源码文件。
中间是 main.go 的源码引用了两个包一个是标准库的 fmt一个是 util 包util 的导入路径是 util。所谓的导入路径是指相对于 Go 的源码目录 $GoRoot/src 或者 $GoPath/src 的下的子路径。例如 main 包里引用的 fmt 的源码路径是 /usr/local/go/src/fmt而 util 的源码路径是 /Users/qcrao/hello-world/src/util正好我们设置的 GoPath /Users/qcrao/hello-world。
最右边是库函数的源码实现了获取本机 IP 的函数。
在 src 目录下直接执行 go build 命令在同级目录生成了一个可执行文件文件名为 src使用 ./src 命令直接执行输出
hello world!
Local IP: 192.168.1.3我们也可以指定生成的可执行文件的名称
go build -o bin/hello这样在 bin 目录下会生成一个可执行文件运行结果和上面的 src 一样。
其实util 包可以单独被编译。我们可以在项目根目录下执行
go build util编译程序会去 $GoPath/src 路径找 util 包其实是找文件夹。还可以在 ./src/util 目录下直接执行 go build 编译。
当然直接编译库源码文件不会生成 .a 文件因为 go build 命令在编译只包含库源码文件的代码包或者同时编译多个代码包时只会做检查性的编译而不会输出任何结果文件。 为了展示整个编译链接的运行过程我们在项目根目录执行如下的命令
go build -v -x -work -o bin/hello src/main.go-v 会打印所编译过的包名字-x 打印编译期间所执行的命令-work 打印编译期间生成的临时文件路径并且编译完成之后不会被删除。
执行结果 从结果来看图中用箭头标注了本次编译过程涉及 2 个包utilcommand-line-arguments。第二个包比较诡异源码里根本就没有这个名字好吗其实这是 go build 命令检测到 [packages] 处填的是一个 .go 文件因此创建了一个虚拟的包command-line-arguments。
同时用红框圈出了 compile, link也就是先编译了 util 包和 main.go 文件分别得到 .a 文件之后将两者进行链接最终生成可执行文件并且移动到 bin 目录下改名为 hello。
另外第一行显示了编译过程中的工作目录此目录的文件结构是 可以看到和 hello-world 目录的层级基本一致。command-line-arguments 就是虚拟的 main.go 文件所处的包。exe 目录下的可执行文件在最后一步被移动到了 bin 目录下所以这里是空的。
整体来看go build 在执行时会先递归寻找 main.go 所依赖的包以及依赖的依赖直至最底层的包。这里可以是深度优先遍历也可以是宽度优先遍历。如果发现有循环依赖就会直接退出这也是经常会发生的循环引用编译错误。
正常情况下这些依赖关系会形成一棵倒着生长的树树根在最上面就是 main.go 文件最下面是没有任何其他依赖的包。编译器会从最左的节点所代表的包开始挨个编译完成之后再去编译上一层的包。
这里引用郝林老师几年前在 github 上发表的 go 命令教程可以从参考资料找到原文地址。 从代码包编译的角度来说如果代码包 A 依赖代码包 B则称代码包 B 是代码包 A 的依赖代码包以下简称依赖包代码包 A 是代码包 B 的触发代码包以下简称触发包。 执行 go build 命令的计算机如果拥有多个逻辑 CPU 核心那么编译代码包的顺序可能会存在一些不确定性。但是它一定会满足这样的约束条件依赖代码包 - 当前代码包 - 触发代码包。 顺便推荐一个浏览器插件 Octotree在看 github 项目的时候此插件可以在浏览器里直接展示整个项目的文件结构非常方便 到这里你一定会发现对于 hello-wrold 文件夹下的 pkg 目录好像一直没有涉及到。
其实pkg 目录下面应该存放的是涉及到的库文件编译后的包也就是一些 .a 文件。但是 go build 执行过程中这些 .a 文件放在临时文件夹中编译完成后会被直接删掉因此一般不会用到。
前面我们提到过在 go build 命令里加上 -i 参数会安装这些库文件编译的包也就是这些 .a 文件会放到 pkg 目录下。
在项目根目录执行 go build -i src/main.go 后pkg 目录里增加了 util.a 文件 darwin_amd64 表示的是 GOOS 和 GOARCH。这两个环境变量不用我们设置系统默认的。 GOOS 是 Go 所在的操作系统类型GOARCH 是 Go 所在的计算架构。 Mac 平台上这个目录名就是 darwin_amd64。 生成了 util.a 文件后再次编译的时候就不会再重新编译 util.go 文件加快了编译速度。
同时在根目录下生成了名称为 main 的可执行文件这是以 main.go 的文件名命令的。
hello-world 这个项目的代码已经上传到了 github 项目 Go-Questions这个项目由问题导入企图串连 Go 的所有知识点正在完善期待你的 star。 地址见参考资料【Go-Questions hello-world项目】。
go install
go install 用于编译并安装指定的代码包及它们的依赖包。相比 go build它只是多了一个“安装编译后的结果文件到指定目录”的步骤。
还是使用之前 hello-world 项目的例子我们先将 pkg 目录删掉在项目根目录执行
go install src/main.go或者go install util两者都会在根目录下新建一个 pkg 目录并且生成一个 util.a 文件。
并且在执行前者的时候会在 GOBIN 目录下生成名为 main 的可执行文件。
所以运行 go install 命令库源码包对应的 .a 文件会被放置到 pkg 目录下命令源码包生成的可执行文件会被放到 GOBIN 目录。
go install 在 GoPath 有多个目录的时候会产生一些问题具体可以去看郝林老师的 Go 命令教程这里不展开了。
go run
go run 用于编译并运行命令源码文件。
在 hello-world 项目的根目录执行 go run 命令
go run -x -work src/main.go-x 可以打印整个过程涉及到的命令-work 可以看到临时的工作目录 从上图中可以看到仍然是先编译再连接最后直接执行并打印出了执行结果。
第一行打印的就是工作目录最终生成的可执行文件就是放置于此 main 就是最终生成的可执行文件。
总结
这次的话题太大了困难重重。从编译原理到 go 启动时的流程到 go 命令原理每个话题单独抽出来都可以写很多。
幸好有一些很不错的书和博客文章可以去参考。这篇文章就作为一个引子你可以跟随参考资料里推荐的一些内容去发散。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/82849.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!