Skip to content

Lua 调试

Lua 包含一个 debug 库,提供了强大的自省(introspection)能力。它主要用于构建调试器(debuggers)或执行高级自省任务,而不是供应用程序开发人员进行日常调试(日常调试更常使用 print 语句或专用调试器)。

debug 库允许你检查执行栈(execution stack)、获取函数信息(源码、行号、变量名)、访问局部变量(local variables)和 upvalue 变量(upvalue variables)、设置钩子(hooks)进行跟踪等等。

以下是一些最常用的函数:

函数签名用途
debug.debug()进入交互式调试模式。你可以输入 Lua 语句检查变量。输入 cont 退出。
debug.getfenv(object)返回给定对象(函数、线程或 userdata)的环境表(environment table)。在 Lua 5.2+ 中已弃用;请使用 _ENV 和 upvalue 进行词法作用域(lexical scoping)。
debug.setfenv(object, table)设置给定对象的环境。在 Lua 5.2+ 中已弃用。
debug.getinfo([thread,] func_or_stacklevel [, what_string])返回一个关于函数的表。func_or_stacklevel 可以是一个函数或栈级别号。what_string 指定要检索的字段(例如,‘S’ 表示源码,‘l’ 表示当前行,‘n’ 表示名称,‘f’ 表示函数对象,‘u’ 表示 upvalue 的数量)。
debug.getlocal([thread,] stacklevel, local_index)返回位于 stacklevel 栈级别的函数中,local_index 索引处的局部变量的名称和值。如果不存在此类变量则返回 nil。
debug.setlocal([thread,] stacklevel, local_index, value)将 value 赋给局部变量。返回局部变量名称或 nil。
debug.getupvalue(func, upvalue_index)返回函数 func 中,upvalue_index 索引处的 upvalue 的名称和值。
debug.setupvalue(func, upvalue_index, value)将 value 赋给 upvalue。返回 upvalue 名称或 nil。
debug.getmetatable(value)返回给定 value 的元表(metatable)。
debug.setmetatable(value, metatable)设置给定 value 的元表。
debug.traceback([thread,] [message_string,] [level])返回一个包含栈回溯(stack traceback)的字符串。对于构造自定义错误消息很有用。
debug.sethook([thread,] hook_func, mask_string, count)设置一个钩子函数,该函数在由 mask_string(‘c’、‘r’、‘l’)和 count 指定的特定事件(函数调用、返回、行、指令计数)发生时被调用。
local function level_two()
print("--- Inside level_two ---")
-- Get info about the current function (level_two)
local info_current = debug.getinfo(1, "Snl") -- S: source, n: name, l: currentline
print(string.format("Current function name: %s, source: %s, line: %d",
info_current.name or "?", info_current.short_src, info_current.linedefined))
-- Get info about the caller (level_one)
local info_caller = debug.getinfo(2, "Snl")
if info_caller then
print(string.format("Caller function name: %s, source: %s, line defined: %d",
info_caller.name or "?", info_caller.short_src, info_caller.linedefined))
end
print("Stack traceback from level_two:")
print(debug.traceback("Custom message from level_two", 2)) -- Start traceback from caller
end
local function level_one()
print("--- Inside level_one ---")
level_two()
end
level_one()
print("--- Back in main chunk ---")
local main_info = debug.getinfo(1, "S")
print("Main chunk source:", main_info.short_src)

输出将显示关于函数的信息和栈回溯。确切的行号和源文件路径取决于你如何保存和运行文件。

Upvalue 是由闭包(closure)使用的外部局部变量。debug 库可以检查甚至修改它们。

local function create_counter()
local n = 0 -- This is an upvalue for the returned function
return function()
n = n + 1
return n
end
end
local counter1 = create_counter()
print("Counter1:", counter1()) -- Output: 1
print("Counter1:", counter1()) -- Output: 2
-- Inspect and modify counter1's upvalue 'n'
local i = 1
repeat
local name, value = debug.getupvalue(counter1, i)
if name then
print(string.format("Upvalue index %d: name='%s', value=%s", i, name, tostring(value)))
if name == "n" then
print("Modifying upvalue 'n' to 100")
debug.setupvalue(counter1, i, 100)
end
i = i + 1
end
until not name
print("Counter1 after modification:", counter1()) -- Output: 101

upvalue 示例的输出:

Counter1: 1
Counter1: 2
Upvalue index 1: name='n', value=2
Modifying upvalue 'n' to 100
Counter1 after modification: 101

尽管 debug 库功能强大,但对于大多数日常调试,开发人员会使用其他技术:

  • **打印调试(Print Debugging):**最简单的形式,使用 print(variable) 或 print(require('inspect')(variable))(配合合适的 inspect.lua 库美化打印表)在程序的各个点检查变量值。
  • **命令行调试器(Command-Line Debuggers):**允许单步执行代码、设置断点和从命令行检查变量的工具。mobdebug 是一个著名的远程调试器库,可用于构建或集成命令行调试器。
  • **图形化调试器 / IDE 集成(Graphical Debuggers / IDE Integration):**现代 IDE 和文本编辑器通常带有 Lua 调试扩展。它们提供可视化界面用于断点、单步执行、变量检查、调用栈视图等。
  • **VS Code with Lua Extensions:**像 Visual Studio Code 这样的编辑器,配合 lua-language-server (by sumneko/LuaLS) 或 EmmyLua 等扩展,提供了出色的调试支持(通常使用 mobdebug 或类似协议)。这是非常流行的选择。
  • **ZeroBrane Studio:**一个轻量级的 Lua IDE,内置调试器,支持针对各种 Lua 引擎(LuaJIT、LÖVE、Moai 等)的本地和远程调试。开源软件。
  • **Other IDE Plugins:**IntelliJ IDEA(使用 EmmyLua/IntelliJ-Lua 插件)、Eclipse(例如使用 LDT - Lua Development Tools,尽管 LDT 的活跃度有所下降)等可能提供 Lua 调试功能。
  • **RemDebug:**Lua 5.0/5.1 的早期远程调试器。
  • **clidebugger:**一个简单的 Lua 5.1 命令行调试器。
  • **SciTE:**Lua 在 Windows 上的默认 IDE 包含一些基本的调试功能。
  • **Decoda:**一个带有远程调试功能的图形化调试器(近年来状态不太明朗)。

常见的学习障碍:

  • 理解栈级别(Stack Levels):debug.getinfo 和 debug.getlocal 中的栈级别是基于当前执行函数的,从 1 开始计数。级别 0 是 getinfo 本身,级别 1 是调用 getinfo 的函数,依此类推。
  • **debug 库是低级别的(Low-Level):**它是用于构建调试器的工具,而不是一个终端用户调试器。对于应用程序调试,请使用专用调试工具或 IDE。
  • **作用域和环境(Scope and Environments):**理解环境(Lua 5.2+ 中的 _ENV)和 upvalue 的工作原理对于有效使用相关调试函数至关重要。

更多资源:查阅 Lua 官方参考手册中关于 debug 库的部分。对于特定的调试器工具,请参考它们各自的文档(例如 ZeroBrane Studio 文档、VS Code 扩展市场)。