探究vscode debug流程,解決無法運(yùn)行g(shù)o程序的問題

問題描述

vscode 無法以 run 模式運(yùn)行 go 項(xiàng)目(只能以 debug 模式調(diào)試),并且有如下報(bào)錯(cuò)。

圖中被遮蓋的部分是項(xiàng)目內(nèi)的 package,并非第三方 package,也就是說在以 run 模式運(yùn)行 go 項(xiàng)目時(shí)無法找到其他的 go 文件,只能找到入口文件。

初步排查

找不到其他文件,首先想到的是 GO_PATH 的問題,但是項(xiàng)目使用了 go mod,允許在 GO_PATH 之外的路徑創(chuàng)建項(xiàng)目,所以這個(gè)懷疑點(diǎn)排除。接下來懷疑 vscode 的配置有問題,每個(gè) vscode 項(xiàng)目中都有 .launch.json 文件,配置運(yùn)行代碼時(shí)的環(huán)境,下面是項(xiàng)目中的 .launch.json。

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch",
            "type": "go",
            "request": "launch",
            "mode": "auto",
            "program": "${workspaceRoot}/src/main.go",
            "env": {},
            "args": []
        }
    ]
}

可以看到 .launch.json 里沒有指定程序的工作目錄,debug 模式和 run 模式會(huì)不會(huì)默認(rèn)的工作路徑不同呢?于是在 main 函數(shù)里使用 os.Getwd() 打印一下當(dāng)前的路徑,結(jié)果如下:

  • debug 模式:項(xiàng)目所在目錄
  • run 模式:用戶目錄

基本可以確認(rèn),run 模式下的工作路徑設(shè)置不正確,導(dǎo)致找不到路徑。在 .launch.json 中加入 cwd 參數(shù),手動(dòng)填入項(xiàng)目路徑。

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch",
            "type": "go",
            "request": "launch",
            "mode": "auto",
            "program": "${workspaceRoot}/src/main.go",
            "cwd": "${workspaceRoot}",
            "env": {},
            "args": []
        }
    ]
}

但是修改 .launch.json 后運(yùn)行程序,輸出的工作目錄仍然是用戶目錄,cwd 參數(shù)并沒有生效。

探究 vscode 的 debug 流程

至此,bug 的氣息越來越濃厚,cwd 參數(shù)沒有生效,肯定有問題!

一不做二不休,索性看看 vscode 的調(diào)試流程吧,用一個(gè)很暴力的方式,看看點(diǎn)擊運(yùn)行按鈕后,vscode 到底是如何運(yùn)行 go 程序的。

package main
import "time"
func main() {
    time.Sleep(10000000000)
}

運(yùn)行程序后,使用 ps -ef|grep go 查看進(jìn)程。

截圖中三個(gè)進(jìn)程從上到下均是父子關(guān)系,也就是說在 vscode 中即便使用 run 模式運(yùn)行,也不是直接執(zhí)行 go run xxxx.go,這與 Goland 等其他 IDE 的行為是不同的。vscode 首先調(diào)用了 language server 中的 node,執(zhí)行了 go extention(vscode 的 go 擴(kuò)展,安裝后才支持 go 語言項(xiàng)目)中的一個(gè) goDebug.js,而后 goDebug.js 中調(diào)用了 go run xxxx.go。(圖中 /tmp 路徑下的 main 文件是 go run 執(zhí)行過程中生成的二進(jìn)制文件)

接下來查看 goDebug.js 的邏輯,找到了調(diào)用 go run 的代碼。

this.debugProcess = spawn(getBinPathWithPreferredGopath('go', []), runArgs, { env });

查看代碼上面幾行的邏輯,根據(jù)參數(shù)的命名,可以猜測出來,.launch.json 中的配置在這里是可以獲取到的。接下來直接修改 js 文件,進(jìn)行調(diào)試,證實(shí)上述的猜測,由于我們無法直接看到 node goDebug.js 的輸出,所以通過寫入文件的方式進(jìn)行調(diào)試。

fs.writeFile('test.log', this.debugProcess.cwd(), function (err) {}

加入這句后再次運(yùn)行,我們可以看到 test.log 文件中已經(jīng)打印出了這個(gè)進(jìn)程的工作路徑,也就是 go run 的工作路徑,是用戶目錄。至此,可以將問題縮小到:在 node 調(diào)用 go run 時(shí)沒有將 .launch.json 文件中的 cwd 傳給子進(jìn)程(go run)。

spawn 是 nodejs 中的函數(shù),看一下 spawn 的文檔可以發(fā)現(xiàn),spawn 有三個(gè)參數(shù) child_process.spawn(command[, args][, options]) 第三個(gè)參數(shù) options 中可以指定 cwd 工作路徑。而 goDebug.js 這段啟動(dòng)子進(jìn)程的代碼并沒有設(shè)置 cwd,只設(shè)置了env 參數(shù),這就是 run 模式無法運(yùn)行 go 程序的原因。

解決方案

在發(fā)現(xiàn)這個(gè)問題時(shí),vscode go extention的最新版本是0.13,這個(gè)問題暫時(shí)只能通過修改 goDebug.js 的源碼解決,如下圖所示加入注釋中的代碼,將 cwd 參數(shù)傳入子進(jìn)程,就可以解決問題。

同時(shí),這個(gè) bug 已經(jīng)被解決,可以參考 ISSUE #3096,程序員在解決另一個(gè)問題這個(gè) ISSUE 的問題時(shí),“順手”把 cwd 的問題修復(fù)了。在 vscode go extention 0.14版發(fā)布后(已發(fā)布),將 go extension 更新到最新版就可以正常運(yùn)行和調(diào)試 go 項(xiàng)目了。

參考資料

Debugging in Visual Studio Code

Node.js v13.13.0 Documentation

Debug: add "go run ." support #3096

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容