Mac下安装Go语言调试工具dlv

1 dlv安装

1.1 dlv下载之git clone方式

git clone https://github.com/go-delve/delve.git $GOPATH/src/github.com/go-delve/delve

$GOPATH为环境变量, 是go语言项目的工作目录. 可以在环境变量文件或者配置下找到该路径,将$GOPATH替换为真实目录,如下面实例,Mac环境变量在.bash_profile文件下配置,故$GOPATH=/Users/hanyuxia/go

hanyuxia@HanYuxiadeMacBook-Pro ~ % cat ~/.bash_profile 

JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_271.jdk/Contents/Home
PATH=$JAVA_HOME/bin:$PATH:.
CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:.
export JAVA_HOME
export PATH
export CLASSPATH


M2_HOME=/usr/local/apache-maven-3.6.3
export MAVEN_OPTS="-Xms256m -Xmx512m"
export PATH=$M2_HOME/bin:$PATH
export PATH=/Applications/Google\ Chrome.app/Contents/MacOS:$PATiH

GOROOT=/usr/local/go
export GOROOT
export GOPATH=/Users/hanyuxia/go
export GOBIN=$GOPATH/bin
export PATH=$PATH:$GOBIN:$GOROOT/bin

export PATH=${PATH}:/usr/local/mysql/bin


hanyuxia@HanYuxiadeMacBook-Pro ~ % 

1.2 dlv下载之之go get方式

go get github.com/derekparker/delve/cmd/dlv

命令执行成功后,会在$GOPATH/src目录下有一个github.com文件夹,该文件夹即为dlv安装包,如下所示

hanyuxia@HanYuxiadeMacBook-Pro src % pwd
/Users/hanyuxia/go/src
hanyuxia@HanYuxiadeMacBook-Pro src % ls
github.com

1.3 dlv安装

cd $GOPATH/src/github.com/go-delve/delve
make install

命令执行完后,会返回如下提示,表明自动为dlv生成了证书并对dlv进行签名.需要注意,此处使用codesign对dlv进行签名,没有签名的程序会受到一些限制,例如无法作为调试程序

hanyuxia@HanYuxiadeMacBook-Pro delve % make install
go install -tags=macnative "-ldflags=-s -X main.Build=c068861f95ec570fb7ea93638c87338f25c96af3" github.com/go-delve/delve/cmd/dlv
codesign -s dlv-cert /Users/hanyuxia/go/bin/dlv
自动生成的dlv证书和秘钥.png

在Mac上配置Go语言开发环境的时候,疆场碰到的问题就是dlv调用总是不成功,无法启动应用,无法调试等等,大部分是问题都与Mac的安全机制有关.
此时在终端输入dlv,仍无法识别

hanyuxia@HanYuxiadeMacBook-Pro delve % dlv
zsh: command not found: dlv

需要说明的是,在安装完毕后,在$GOPATH/bin目录下生成一个名为dlv的可执行文件,如下所示

hanyuxia@HanYuxiadeMacBook-Pro go % cd bin 
hanyuxia@HanYuxiadeMacBook-Pro bin % ls
dlv     ferry       go-outline  gopkgs

紧接着,需要将其移动到$GOROOT/bin目录下,这一步是安装dlv的关键,$GOROOT的路径也在~/.bash_profile文件中

hanyuxia@HanYuxiadeMacBook-Pro bin % pwd
/usr/local/go/bin
hanyuxia@HanYuxiadeMacBook-Pro bin % ls
dlv go  gofmt

此时在终端输入dlv,出现如下反馈消息,说明dlv工具安装成功

hanyuxia@HanYuxiadeMacBook-Pro ~ % dlv
Delve is a source level debugger for Go programs.

Delve enables you to interact with your program by controlling the execution of the process,
evaluating variables, and providing information of thread / goroutine state, CPU register state and more.

The goal of this tool is to provide a simple yet powerful interface for debugging Go programs.

Pass flags to the program you are debugging using `--`, for example:

`dlv exec ./hello -- server --config conf/config.toml`

Usage:
  dlv [command]

Available Commands:
  attach      Attach to running process and begin debugging.
  connect     Connect to a headless debug server.
  core        Examine a core dump.
  dap         [EXPERIMENTAL] Starts a TCP server communicating via Debug Adaptor Protocol (DAP).
  debug       Compile and begin debugging main package in current directory, or the package specified.
  exec        Execute a precompiled binary, and begin a debug session.
  help        Help about any command
  run         Deprecated command. Use 'debug' instead.
  test        Compile test binary and begin debugging program.
  trace       Compile and begin tracing program.
  version     Prints version.

Flags:
      --accept-multiclient   Allows a headless server to accept multiple client connections.
      --api-version int      Selects API version when headless. (default 1)
      --backend string       Backend selection (see 'dlv help backend'). (default "default")
      --build-flags string   Build flags, to be passed to the compiler.
      --check-go-version     Checks that the version of Go in use is compatible with Delve. (default true)
      --headless             Run debug server only, in headless mode.
      --init string          Init file, executed by the terminal client.
  -l, --listen string        Debugging server listen address. (default "127.0.0.1:0")
      --log                  Enable debugging server logging.
      --log-dest string      Writes logs to the specified file or file descriptor (see 'dlv help log').
      --log-output string    Comma separated list of components that should produce debug output (see 'dlv help log')
      --only-same-user       Only connections from the same user that started this instance of Delve are allowed to connect. (default true)
      --wd string            Working directory for running the program. (default ".")

Additional help topics:
  dlv backend Help about the --backend flag.
  dlv log     Help about logging flags.

Use "dlv [command] --help" for more information about a command.

*如果dlv仍不能识别,可以继续执行如下命令,对移动到$GOROOT/bin目录下的dlv进行签名

sudo codesign -s "dlv-cert" $GOROOT/bin/dlv

不同的GO环境,安装dlv可能出现不同的问题,如果以上步骤仍不能帮助解决问题,可以查询文末的参考文档,可能会提供一些解决安装问题的思路,我在安装过程中经过不断的查阅文档和试错,才安装成功,也欢迎给我留言

2 dlv调试实例

脚本test.go包含主函数main(),有可执行代码,下面以该脚本为实例,说明调试过程

2.1 进入调试模式

进入调试模式的命令有很多,这里只说一下比较常用的: dlv debug
示例源代码如下,拷贝保存为test.go可执行

package main    // 声明 main 包
import (
    "fmt"       // 导入 fmt 包,打印字符串是需要用到
)
func main() {   // 声明 main 主函数
    fmt.Println("Hello World!") // 打印 Hello World!
    fmt.Println("Hello HanYxuxia!")
}

执行如下命令,进入dlv调试模式,需要注意的是指定调试脚本使用的是相对路径,即该脚本在项目下的相对路径,main.go脚本直接在项目一级目录下,如果在其他目录下,需在脚本文件名前补齐相对路径

hanyuxia@HanYuxiadeMacBook-Pro ferry_api % dlv debug main.go --check-go-version=false
Type 'help' for list of commands.
(dlv)

如下所示,直接使用dlv debug main.go,提示dlv版本比较老,需要再命令行的后面加上参数--check-go-version=false,忽视dlv版本

hanyuxia@HanYuxiadeMacBook-Pro ferry_api % dlv debug main.go
Version of Delve is too old for this version of Go (maximum supported version 1.14, suppress this error with --check-go-version=false)
hanyuxia@HanYuxiadeMacBook-Pro ferry_api %

2.2 追踪调用轨迹

追踪调用轨迹常用的是dlv trace
示例源代码如下,拷贝代码保存为goroutine.go,是一个可以直接执行的go脚本

package main

import (
    "fmt"
    "math/rand"
    "time"
)

// 数据生产者
func producer(header string, channel chan<- string)  {
    // 无限循环,不停的生产数据
    for {
        // 将随机数和字符串格式化为字符串发送给通道
        channel <- fmt.Sprintf("%s: %v", header, rand.Int31())
        // 等待1秒
        time.Sleep(time.Second)
    }
}

// 数据消费者
func customer(channel <-chan string)  {
    // 不停的获取数据
    for  {
        // 从通道中取出数据,此处会阻塞直到信道中返回数据
        message := <-channel
        // 打印数据
        fmt.Println(message)
    }
}

func main()  {
    // 创建一个字符串类型的通道
    channel := make(chan string)
    // 创建producer()函数的并发goroutine
    go producer("cat", channel)
    go producer("dog", channel)
    // 消费数据
    customer(channel)
}

使用dlv trace追踪producer()方法在脚本中的调用情况如下

hanyuxia@HanYuxiadeMacBook-Pro exercise % dlv trace goroutine.go producer --check-go-version=false
> goroutine(6): main.producer("cat", chan<- string 0/0)
> goroutine(7): main.producer("dog", chan<- string 0/0)
dog: 1298498081
cat: 2019727887
cat: 939984059
dog: 1427131847
dog: 911902081
cat: 1474941318
cat: 140954425
dog: 336122540
dog: 208240456
cat: 646203300
cat: 1106410694
dog: 1747278511
cat: 460128162
dog: 817455089
dog: 683024728
cat: 1006933274
cat: 607811211

示例脚本goroutine.go可以无限循环执行,通过control+C终止脚本运行

2.3 调试模式基本命令

这里用上面的test.go脚本作为示例进行调试

  1. 设置断点: b(break)
    如下有两种设置断点的方式
hanyuxia@HanYuxiadeMacBook-Pro exercise % dlv debug goroutine.go --check-go-version=falseType 'help' for list of commands.
(dlv) b producer // 方法1: b + 方法名设置断点
Breakpoint 1 set at 0x10d48d8 for main.producer() ./goroutine.go:10
(dlv) b goroutine.go:27 // 方法2: b + 调试脚本名:代码行号
Breakpoint 2 set at 0x10d4aea for main.customer() ./goroutine.go:27
(dlv)
  1. 继续执行到断点处: c(continue)
(dlv) c
> main.producer() ./goroutine.go:10 (hits goroutine(18):1 total:2) (PC: 0x10d48d8)
> main.producer() ./goroutine.go:10 (hits goroutine(19):1 total:2) (PC: 0x10d48d8)
     5:         "math/rand"
     6:         "time"
     7: )
     8:
     9: // 数据生产者
=>  10: func producer(header string, channel chan<- string)  {
    11:         // 无限循环,不停的生产数据
    12:         for {
    13:                 // 将随机数和字符串格式化为字符串发送给通道
    14:                 channel <- fmt.Sprintf("%s: %v", header, rand.Int31())
    15:                 // 等待1秒
(dlv) c
> main.customer() ./goroutine.go:27 (hits goroutine(1):1 total:1) (PC: 0x10d4aea)
    22:         // 不停的获取数据
    23:         for  {
    24:                 // 从通道中取出数据,此处会阻塞直到信道中返回数据
    25:                 message := <-channel
    26:                 // 打印数据
=>  27:                 fmt.Println(message)
    28:         }
    29: }
    30:
    31: func main()  {
    32:         // 创建一个字符串类型的通道
  1. 逐行执行代码,不进入函数: n(next)
(dlv) n
dog: 1298498081
> main.customer() ./goroutine.go:25 (PC: 0x10d4ab3)
    20: // 数据消费者
    21: func customer(channel <-chan string)  {
    22:         // 不停的获取数据
    23:         for  {
    24:                 // 从通道中取出数据,此处会阻塞直到信道中返回数据
=>  25:                 message := <-channel
    26:                 // 打印数据
    27:                 fmt.Println(message)
    28:         }
    29: }
    30:
(dlv) 
  1. 退出调试: next
(dlv) exit
hanyuxia@HanYuxiadeMacBook-Pro exercise % 

调试的命令有很多,这里不一一介绍了,如有需要可以翻阅文末参考文档,有详细介绍命令使用方式

3 参考文档

感谢以下文档的作者,在你们的帮助下,我成功安装dlv,开始愉快的调试之旅啦;继续传递分享精神,希望我的文章也能帮助到更多的互联网打工人,哈哈哈
安装Go语言调试工具dlv
Mac上配置VSCode golang调试器dlv
GO语言调试利器dlv快速上手

你可能感兴趣的:(Mac下安装Go语言调试工具dlv)