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快速上手

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345

推荐阅读更多精彩内容