Mojo使用调试工具(Visual Studio Code)详解

时间:2024-10-25 21:29:17

Visual Studio Code 的 Mojo 扩展使您可以将 VS Code 的内置调试器与 Mojo 程序一起使用。(Mojo 扩展还支持调试 C、C++ 和 Objective-C。)

有关 VS Code 调试功能的完整介绍,请参阅 Visual Studio Code 中的调试

本文介绍了可通过 Mojo 扩展获得的功能,以及 Mojo 调试器的当前限制。

Mojo SDK 包含LLDB 调试器和 Mojo LLDB 插件。它们共同为 Mojo 扩展提供了低级调试接口。您还可以使用该mojo debug命令使用 LLDB 启动命令行调试会话或在 VS Code 中启动 Mojo 调试会话。

开始调试


有几种方法可以在 VS Code 中启动调试会话。

要开始调试,您需要有一个 Mojo 项目进行调试。本文以GitHub上的 Mojo repo中有许多从简单到复杂的示例进行展示。

VS Code 老手?
如果您已经熟悉 VS Code 中的调试,本节中的材料将主要作为复习。

快速运行或调试


如果您的活动编辑器选项卡包含带有入口点的 Mojo 文件fn main(),则运行或调试它的最快方法之一是使用编辑器工具栏中的运行或调试按钮。
在这里插入图片描述
开始调试当前文件:

  • 打开运行或调试下拉菜单并选择调试 Mojo 文件或 在专用终端中调试 Mojo 文件。
    在这里插入图片描述
    这两个调试配置在处理输入和输出的方式上有所不同:
  • Debug Mojo File可启动与任何终端分离的 Mojo 程序。程序的标准输出和标准错误输出显示在 Debug Console中。您无法写入程序的标准输入,但您可以在一个位置查看程序的输出并与调试器交互。
  • 专用终端中调试 Mojo 文件会创建 VS Code 集成终端的新实例,并将程序的输入和输出附加到终端。这样您就可以在终端中与程序的标准输入、标准输出和标准错误输出进行交互,而调试控制台仅用于与调试器进行交互。

运行或调试按钮使用预定义的启动配置。目前无法修改使用运行或调试配置args启动的程序的、env或cwd其他设置。如果您需要自定义其中任何内容,请参阅后面的 编辑启动配置

选择其中一个调试配置后,按钮会更新以显示调试符号。单击该按钮可重新运行上一个配置。

在这里插入图片描述

运行和调试视图


运行和调试视图包含一个用于启动调试会话的按钮和一个用于选择调试配置的菜单。它还包含用于显示当前变量、监视表达式、当前调用堆栈和断点的区域。
在这里插入图片描述
图 1.运行和调试视图

要打开运行和调试视图,请单击活动栏(在 VS Code 窗口左侧)中的 运行和调试图标,或者按 (在 macOS 上)。Control+Shift+D Command+Shift+D
在这里插入图片描述
如果您尚未在当前项目中创建任何启动配置,VS Code 将显示运行启动视图。

在这里插入图片描述
图 2.运行开始视图
如果您已经启动了调试会话或创建了文件来定义启动配置,您将看到启动配置菜单,它可以让您选择配置并启动调试会话:
在这里插入图片描述
图 3.启动配置菜单

启动调试会话的其他方法


还有许多其他方法可以启动调试会话。

从命令行启动调试器


一. 从命令面板启动
如果您在活动编辑器中打开了 Mojo 文件,您也可以从命令面板启动调试会话。

  1. 单击视图>命令面板或按Control+Shift+P (Command+Shift+P在 macOS 上)。
  2. 在提示符下输入“Mojo”以调出 Mojo 命令。您应该会看到与快速运行或调试中描述的相同的调试配置。
    二. 从资源管理器视图启动
    从文件资源管理器视图启动调试会话步骤:
  3. 右键单击 Mojo 文件。
  4. 选择 Mojo 调试配置。
    三. 使用F5 启动
    按 F5 使用当前调试配置启动调试会话。

如果您没有任何现有的调试配置可供选择,并且您的活动编辑器包含一个带有入口点的 Mojo 文件,则按 F5 将使用快速运行或调试中描述的调试 Mojo 文件fn main()操作启动并调试当前文件。


使用该mojo debug命令从命令行启动调试会话。您可以从两个调试界面中进行选择:

  • 使用此–rpc标志,mojo debug在具有活动 RPC 调试服务器的外部编辑器中启动 RPC 调试会话。如果您正在运行 VS Code,这将在 VS Code 中启动调试会话。
  • 如果没有该–rpc标志,mojo debug则启动命令行LLDB 调试器会话。

您可以选择构建和调试 Mojo 文件、运行和调试已编译的二进制文件,或者将调试器附加到正在运行的进程。

当您使用 从命令行调试程序时–rpc,程序将使用终端中设置的环境变量运行。从 VS Code 内部启动时,环境由 VS Code启动配置定义。

从命令行启动调试会话

打开 VS Code 后,运行以下命令(从 VS Code 的集成终端或外部 shell 运行):

mojo debug --rpc myproject.mojo
  • 1

或者调试已编译的二进制文件:

mojo debug --rpc myproject
  • 1

为了获得最佳效果,-O0 -g在构建要调试的二进制文件时,请使用命令行选项进行构建 - 这样会生成包含完整调试信息的二进制文件。(调用mojo debugMojo 源文件时,它默认包含调试信息。)

从命令行将调试器附加到正在运行的进程


您还可以通过在命令行上指定进程 ID 或进程名称将调试器附加到正在运行的进程:

mojo debug --rpc --pid <PROCESS_ID>
  • 1

或者:

mojo debug --rpc --process-name <PROCESS_NAME>
  • 1

启动配置


VS Code启动配置允许您定义用于调试应用程序的设置信息。

Mojo 调试器提供了以下启动配置模板:

  • 调试当前 Mojo 文件。在活动编辑器选项卡中启动并调试 Mojo 文件。实际上与快速运行或调试中描述的 调试 Mojo 文件操作相同,但具有更多配置选项。
  • 调试 Mojo 文件。与上一个条目类似,不同之处在于它会标识要启动和调试的特定文件,而不管活动编辑器中显示的是什么文件。
  • 调试二进制文件。此配置对预构建的二进制文件进行操作,可以使用 LLDB 支持的任何语言组合(Mojo、C、C++ 等)编写。您需要将字段设置program为二进制文件的路径。
  • 附加到进程。启动附加到正在运行的进程的调试会话。启动时,您可以从正在运行的进程列表中选择要调试的进程。

您可以编辑任何这些模板来自定义它们。所有 VS Code 启动配置都必须包含以下属性:

  • name. 启动配置的名称,显示在 UI 中(例如,“运行当前 Mojo 文件”)。
  • request。可以是launch(从 VS Code 运行程序)或attach (附加到并调试正在运行的文件)。
  • type. 用于mojo-lldbMojo 调试器。
    此外,Mojo 启动配置可以包含以下属性:
  • args. 要传递给程序的任何命令行参数。
  • cwd. 运行程序的当前工作目录。
  • description. 配置的详细描述,未在 UI 中显示。
  • env. 运行程序之前要设置的环境变量。
  • mojoFile. 要启动和调试的 Mojo 文件的路径。
  • pid. 要附加到的正在运行的进程的进程 ID。
  • program. 要启动和调试的已编译二进制文件的路径,或要附加到的程序的路径。
  • runInTerminal。如果为 True,则使用专用终端运行程序,这样程序就可以从终端接收标准输入。如果为 False,则运行程序并将其输出定向到调试控制台。

如果配置是一个launch请求,则配置必须包含mojoFile或program属性。

  • 对于attach请求,配置必须包含pid或 program属性。
  • VS Code 在启动配置中执行变量替换。您可以使用${workspaceFolder}替换当前工作区的路径,并 ${file}在活动编辑器选项卡中表示文件。有关变量的完整列表,请参阅 VS Code变量参考

Mojo 启动配置不允许您指定编译选项。如果您需要指定编译选项,您可以使用 构建二进制文件mojo build,然后使用带有选项的启动配置program 来启动已编译的二进制文件。或者,如果您从命令行 启动调试器,则可以将编译选项传递给mojo debug命令。

编辑启动配置


要编辑启动配置:

  1. 如果“运行和调试”视图尚未打开,请单击活动栏(在 VS Code 窗口左侧)中的“运行和调试”图标,或按(在 macOS 上)。Control+Shift+DCommand+Shift+D
    在这里插入图片描述
  2. 创建或打开文件:
  • 如果您看到运行启动视图,请单击创建 文件。
  • 如果您已经设置了启动配置,请单击启动配置菜单旁边的齿轮图标。
    在这里插入图片描述
  1. 从调试器列表中选择Mojo 。

Code在编辑器选项卡中打开新文件,其中包含一些常见调试操作的模板。单击“添加配置”以添加新的配置模板。

使用调试器


当调试会话正在运行时,使用调试工具栏可以暂停、继续和逐步执行程序。
在这里插入图片描述
工具栏上的按钮包括:

  • 继续/暂停:如果程序停止,则恢复程序的正常执行,直到下一个断点、信号或崩溃。否则,立即暂停程序的所有线程。
  • 跳过:执行下一行代码而不停留在函数调用处。
  • 步入:执行下一行代码并在第一个函数调用处停止。如果程序在函数调用之前停止,则步入该函数,以便您可以逐行执行。
  • Step Out:结束当前函数的执行并返回到父函数后立即停止。
  • 重新启动:如果这是一个launch会话,则终止当前程序并重新启动调试会话。否则,从目标进程分离并重新附加到该进程。
  • 停止:如果这是一个launch会话,则终止当前程序。否则,从目标进程分离而不终止它。

调试器当前有以下限制:

  • 不支持 Mojo 错误时自动中断。
  • 当退出函数时,不显示返回值。
  • LLDB 不支持停止或恢复单个线程。

断点


Mojo 调试器支持设置标准断点、 日志点和 触发断点,如 VS Code 文档中所述。

在调试 Mojo 代码时,调试器不支持函数断点、数据断点或基于表达式的条件断点(它支持命中计数,VS Code 将其归类为一种条件断点)。

编辑断点时,您有四个选项:

  • 表达式。设置条件断点(当前不支持)。
  • 命中计数。为断点添加命中计数(支持)。
  • 日志消息。添加日志点(支持)
  • 等待断点。添加触发断点(支持)。

设置命中计数

命中计数断点是仅当调试器命中指定次数后才会中断执行的断点。

要添加命中次数断点:

  1. 右键单击编辑器左侧边缘想要放置断点的位置,然后选择“添加条件断点”。
  2. 从菜单中选择命中次数并输入所需的命中次数。
    要将现有断点更改为命中次数断点:
  3. 右键单击编辑器左侧边栏中的断点,然后选择 “编辑断点”。
  4. 从菜单中选择命中次数并输入所需的命中次数。
    您还可以从“运行和调试”视图的“断点”部分编辑断点:
  • 右键单击断点并选择编辑条件,或者
  • 单击断点旁边的编辑条件图标。

这将在编辑器选项卡中的断点旁边显示相同的菜单。

查看局部变量


当程序在调试器中暂停时,编辑器会以内联方式显示局部变量值。您还可以在“运行和调试”视图的“变量”部分找到它们。
在这里插入图片描述
图 4.调试器中显示的局部变量值

查看调用堆栈


当程序在调试器中暂停时,“运行和调试”视图将显示当前调用堆栈。(您可能会看到多个调用堆栈,程序中的每个活动线程都有一个调用堆栈。)
在这里插入图片描述
图 5.运行和调试视图中的调用堆栈

Run and Debug 视图的Call Stack部分显示当前调用堆栈中每个函数调用的堆栈框架。单击函数名称会突出显示该函数中的当前行。例如,在图 5 中,程序在 中的断点处暂停nested2(),但父函数nested1()在调用堆栈中处于选定状态。编辑器突出显示 中的当前行nested1()(即对 的调用nested2())并显示 的当前局部变量值nested1()。

使用调试控制台


调试控制台为您提供调试器的命令行界面。 调试控制台处理 LLDB 命令和 Mojo 表达式。

任何以冒号 ( ???? 为前缀的内容都被视为 LLDB 命令。任何其他输入都被视为表达式。

目前,Mojo 表达式仅限于检查变量及其字段。控制台还支持vector[index]标准库中某些数据结构的下标符号 ( ),包括 List、SIMD和ListLiteral。

将来,我们打算在调试控制台中提供一种让任意数据结构支持下标符号的方法。

调试控制台仅在程序暂停时接受输入。

技巧和窍门


标准库中有几个功能与调试器没有直接关系,但可以帮助您调试程序。这些功能包括:

  • 程序断点。
  • 从 Mojo 命令行设置参数。

设置编程断点


要在代码的特定点中断,可以使用内置 breakpoint()函数:

if some_value.is_valid():
   do_the_right_thing()
else:
   # We should never get here!
   breakpoint()
  • 1
  • 2
  • 3
  • 4
  • 5

如果您打开 VS Code 并在调试模式下运行此代码(使用 VS Code 或mojo debug),则点击breakpoint()调用会导致错误,从而触发调试器。

该testing模块包含多种指定断言的方法。断言也会触发错误,因此可以像调用一样打开调试器breakpoint()。

从Mojo命令行设置参数


您可以使用该param_env模块检索 Mojo 命令行上指定的参数值。除此之外,这是一种打开和关闭调试逻辑的简单方法。例如:

from param_env import is_defined

def some_function_with_issues():
    # ...
    @parameter
    if is_defined["DEBUG_ME"]():
        breakpoint()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

要激活此代码,请使用-D命令行选项定义DEBUG_ME:

mojo debug -D DEBUG_ME main.mojo
  • 1

该is_defined()函数根据指定名称是否已定义返回编译时 true 或 false 值。由于调用breakpoint()位于 参数if语句DEBUG_ME内,因此仅当在命令行上定义名称时,它才会包含在编译代码中。