Ruby調(diào)試器可以用來調(diào)試代碼
許多開發(fā)人員都認為Ruby調(diào)試器是不存在的。這實際上是一個錯誤的觀念。那么Ruby調(diào)試器到底起到一個什么樣的作用,下面我們將會為大家做一個詳細的解讀。有些人說這是Ruby的一個問題。其他人則試圖將所謂的缺少調(diào)試工具解釋為智慧之舉和良好風(fēng)格。#t#
這些觀點都是誤解。Ruby明明是有調(diào)試工具的——實際上有很多。讓我們來看一看這些現(xiàn)有的工具,包括調(diào)試GUI、調(diào)試器實現(xiàn)和各種Ruby實現(xiàn)中的調(diào)試支持。
什么是調(diào)試器?
首先,讓我們搞清楚“調(diào)試器”實際上涉及了哪些東西?
調(diào)試的GUI和接口
當然了,交互式調(diào)試器最重要的部分——至少對于用戶來說——是用戶接口。用戶可以使用Ruby調(diào)試器的命令行接口,例如和Ruby標準庫一起提供的Rubinius調(diào)試器。它顯然可以用來調(diào)試代碼,只不過設(shè)置斷點或查看運行狀態(tài)會比較麻煩。
IDE雖然有時在Ruby世界中不太受推崇,但它無疑令調(diào)試變得更簡單了——畢竟,IDE就是集成開發(fā)環(huán)境。集成對于調(diào)試來說很重要,而IDE正是把代碼編輯和調(diào)試工具整合在一起了。你可以在源代碼編輯器中直接管理斷點——而不用記下代碼的行號,進入命令行調(diào)試器中,然后手工設(shè)置斷點。在IDE中,諸如基于行的單步調(diào)試之類的功能也更加實用,可以正確的找到所打開的文件的棧結(jié)構(gòu)和所在行。
帶有嵌入式腳本支持的IDE還允許對腳本進行調(diào)試。例如 ,Eclipse的EclipseMonkey擴展支持用JRuby寫成的腳本。由于這些腳本和Eclipse IDE都運行在同一個JVM上,由此調(diào)試器實例便可以被訪問和控制了。
調(diào)試器協(xié)議還是連接到后端
把像IDE這樣的調(diào)試器用戶接口和調(diào)試器后端連接起來的一個簡單方法是:使用命令行接口,并通過標準的stdin/stdout/stderr流來進行控制。這樣,編輯器或者IDE的調(diào)試器支持就可以控制調(diào)試器,同時也讓用戶管理斷點變得更加方便了。
另外一個方法是采用線路(wire)協(xié)議,它允許通過某種模式的進程通訊(IPC),現(xiàn)在一般是通過TCP/IP來連接到調(diào)試器?;诰W(wǎng)絡(luò)的協(xié)議還允許GUI和調(diào)試器分布在不同的機器上,也就是說可以使用本地的用戶接口來對遠程機器進行調(diào)試。
基于文本的或者至少基于文檔的簡單調(diào)試協(xié)議也允許使用任何語言來編寫調(diào)試進程腳本。實際上,連接到Ruby調(diào)試器和打開telnet一樣簡單。debug-commons和DBGp命令的協(xié)議就是由單行字符串和XML應(yīng)答構(gòu)成的。
VM支持還是調(diào)試后端
為了支持斷點等功能,語言運行時至少得提供監(jiān)視和控制執(zhí)行的支持??梢院唵蔚叵馬uby的跟蹤(tracing)功能一樣:在一行Ruby代碼執(zhí)行之前,Ruby調(diào)試器會調(diào)用一個叫做set_trace_func的回調(diào)函數(shù)。傳過去的參數(shù)包括即將執(zhí)行的那行代碼的環(huán)境信息,比如行號,所屬文件的名字和所屬的類等等。
這些信息就足以實現(xiàn)斷點功能了:在一個斷點注冊表里面檢查文件名和行號,看看是否被注冊了。 當遇到一個斷點時,執(zhí)行就被掛起,只要不從回調(diào)中返回即可——Ruby運行時只能在回調(diào)返回后才能繼續(xù)運行。基于這些,就可以實現(xiàn)單步調(diào)試等功能了。 雖然使用跟蹤功能可以實現(xiàn)一個調(diào)試器,但是在執(zhí)行每一行之前都要先執(zhí)行跟蹤回調(diào),顯然太慢了。理想地解決方案是僅在執(zhí)行有斷點的行時才引發(fā)斷點處理。
運行時可以通過修改已加載的代碼來實現(xiàn)此功能——不論是AST還是操作碼(opcodes)——在有斷點的行上。有些語言的運行時提供了內(nèi)建的調(diào)試支持,與執(zhí)行機制整合在一起。Java和.NET的二進制代碼都提供調(diào)試信息(即從文件和行到字節(jié)代碼位置一個映射),讓內(nèi)建的調(diào)試支持能使用這些信息來進行調(diào)試。
在Java世界中,例如,JVM配合JVM工具接口(JVM TI)一起實現(xiàn)了這個功能以及用來連接到JVM的Java調(diào)試線路協(xié)議(JDWP)。 還有一個方法是Rubinius調(diào)試器所使用的,它使用可訪問和可修改的Ruby調(diào)試器代碼中的操作碼(Rubinius把Ruby源代碼先編譯成操作碼然后再執(zhí)行)。通過把一個一般操作碼替換成一個特殊操作碼來設(shè)置一個斷點,而這個特殊操作碼則用來掛起當前進程并通知調(diào)試堆棧中的高層。 通過設(shè)置大量的基礎(chǔ)體系和管理數(shù)據(jù)結(jié)構(gòu)以供語言來訪問,語言本身就可以用來建立調(diào)試機制。