范例-调试器

调试器示例

因为VS Code只是实现了一个通用的(未知语言)调试器界面,所以他不能和真正的调试器直接通信,而是通过一个所谓的调试适配器使用一个抽象的写入协议来通信。我们称这个协议为VS Code Debug Protocol(简写为CDP)。一个调试适配器是一个单独的可执行程序,它和真正的调试器通信并且将抽象的CDP装换为针对调试器的具体的调试协议。

调试器架构

为了避免本地防火墙的问题,VS Code通过标准输入/输出来替代其他复杂的方式和适配器通信。

每个调试适配器定义了一个从VS Code启动配置中引用的调试类型。当调试会话启动后,VS Code查找一个基于调试类型的调试适配器然后在单独的进程中启动可执行文件。当调试会话结束后,调试适配器停止运行。

调试适配器是VS Code的扩展性架构的一部分:他们被作为插件发布。之所以将调试适配器和其他插件分开是因为调试适配器的代码不运行在插件实例上,而是一个单独的程序。有两个原因:第一,使得可以使用对于调试器或者运行时来说最适合的语言来实现适配器。第二,如果有需要,一个单独的程序可以更容易地运行在高级权限下。

VS Code只内嵌了Node.js的调试器插件更多的调试器插件可以从这里找到VS Code 市场或者你可以自己创建一个调试器插件。

这篇文档将向你展示如何创建一个新的调试器插件。

Debugger Architecture

为了避开本地防火墙问题,VS Code通过 stdin/stdout 来和网络适配器对话,而不是使用一个更加复杂的对话机制。

每个调试适配器声明了一个会被 VS Code 启动配置里面读取的调试类型。当一段调试开始时,VS Code寻找基于调试类型的调试适配器,然后启动一个可独立线程运行的可执行文件。当一段调试结束时,适配器停止工作。

调试适配器是VS Code可扩展架构的一部分:他们贡献于插件。和其他插件不同的是调试适配器代码不是运行在插件主机上,而是一个独立程序上。有两方面原因:首先,可以以一种,对于给定调试器或者运行时最合适语言,来实现适配器;第二,如果需要的话,一个独立程序可以在一个高级模式下更容易运行。

VS Code为 Node.js实现了一个调试插件。更多调试器插件可见VS Code 商店,你也可以自己创造一个调试插件.

这篇文档将会告诉你如何创建一个新的调试插件。

安装一个调试器插件示例 Installing a Sample Debug Extension

因为对于入门教程来说,从零开始创建一个调试适配器有些太复杂了。我们将从一个我们为了教学而创建的'starter kit'简单的调试适配器开始。它名叫'mock-debug' 因为它并没有和真正的调试器通讯,而是虚拟了一个。所以mock-debug模拟了一个调试适配器并且支持单步,继续,断点,异常和变量查看但是它并没有连接到真正的调试器。

在探索mock-debug的开发环境设置之前,让我们先从VS Code市场上安装一个生成前版本,做如下操作:

  • 使用命令面板 扩展: 安装扩展 找到并安装mock-debug插件,
  • 重新启动VS Code。尝试如下步骤:

  • 在VS Code中,创建一个测试项目和一个新的程序文件readme.md然后随意的输入几行文本。

  • 切换到调试试图并且按下齿轮图标。
  • VS Code将让你选择调试环境(选择"Mock Debugger")然后会创建一个默认的启动配置。如果你开始了启动配置,你可以单步调试目标文件,设置断点,运行进异常(如果单词exception出现在某一行里).

虚拟调试器运行

mock-debug开发环境建立

现在让我们获取mock-debug的源码并开始在 VS Code上开发吧:

  1. git clone https://github.com/Microsoft/vscode-mock-debug.git
  2. cd vscode-mock-debug
  3. npm install

在VS Code中打开vscode-mock-debug项目目录。

包中有什么?

  • mock-debug实现在src/mockDebug.ts。这里你可以找到各种CDP请求的请求处理。
  • package.json,mock-debug插件的清单文件:
    • 列举mock-debug插件的配置项
    • compilewatch用来转换TypeScript源码到out目录并且监控随后的代码修改。
    • 两个依赖项vscode-debugprotocolvscode-debugadapter是基于node的调试适配器的简单开发环境NPM模块。现在通过选择Launch Extension配置并且敲击F5来构建并启动调试适配器。最开始将会完全的将TypeScript源码转换到out目录。在完全构建之后,'观察任务'将被启动并增量转换接下来的改动。

在构建完成之后,一个在调试模式运行mock-debug插件的新的VS Code窗口将显示出来。现在你可以打开你的测试项目中的readme.md文件并'调试'它。

就像像其他插件一样运行来启动调试插件相对于调试来说工作的很好。问题是调试适配器运行在插件实例外的一个单独的进程中。解决方案是以服务模式运行调试适配器:

  • 运行mock-debug server启动配置来以服务模式启动调试适配器(它监听4711端口)
  • mockDebug.ts文件里的launchRequest(…)方法的开始设置断点
  • 在额外的VS Code窗口打开测试项目的readme.md
  • 在项目里添加顶级debugServer属性,如同下面代码:
  1. {
  2. "version": "0.2.0",
  3. "debugServer": 4711,
  4. "configurations": [{
  5. "name": "mock test",
  6. "request": "launch",
  7. "type": "mock",
  8. "program": "${workspaceRoot}/readme.md",
  9. "stopOnEntry": true
  10. }]
  11. }
  • 如果你现在启动调试配置,VS Code将不会在单独的进程启动调试适配器而是连接本地端口4711。
  • 此时你应该已经出发了launchRequest中的断点。通过上面的步骤,你可以容易的修改,编译,调试mock debug并且将它改造成你想要的调试适配器。

实现VS Code调试协议

一个调试适配器必须实现VS Code调试协议。你可以在这里找到它的详细信息.

剖析调试适配器的package.json

让我们进一步看一下VS Code插件的调试适配器属性。和每一个VS Code插件一样,调试适配器插件也拥有package.json文件来声明一些基本的属性如插件的名字, 发布者,和 版本。使用类别 字段去让插件更容易在VS Code插件市场被找到。

  1. {
  2. "name": "mock-debug",
  3. "version": "0.10.18",
  4. "publisher": "vscode",
  5. "description": "Starter extension for developing debug adapters for VS Code.",
  6. "engines": { "vscode": "0.10.x" },
  7. "categories": ["Debuggers"],
  8. "contributes": {
  9. "debuggers": [{
  10. "type": "mock",
  11. "label": "Mock Debugger",
  12. "enableBreakpointsFor": { "languageIds": ["markdown"] },
  13. "program": "./out/mockDebug.js",
  14. "runtime": "node",
  15. "configurationAttributes": {
  16. "launch": {
  17. "required": ["program"],
  18. "properties": {
  19. "program": {
  20. "type": "string",
  21. "description": "Workspace relative path to a text file.",
  22. "default": "${workspaceRoot}/readme.md"
  23. },
  24. "stopOnEntry": {
  25. "type": "boolean",
  26. "description": "Automatically stop after launch.",
  27. "default": true
  28. }
  29. }
  30. }
  31. },
  32. "initialConfigurations": [
  33. {
  34. "name": "Mock-Debug",
  35. "type": "mock",
  36. "request": "launch",
  37. "program": "readme.md",
  38. "stopOnEntry": true
  39. }
  40. ]
  41. }]
  42. }
  43. }

更值得关注的是contributes下的debuggers节。

调试的type下介绍了一个调试适配器。用户可以在启动配置中引用这个类型。可选属性label可以在UI界面里给调试类型里显示一个更好看的名字。

enableBreakpointsFor属性里你可以列出可以设置断点的语言文件类型。

因为调试适配器是一个单独的程序,program属性指定程序的路径。为了让插件自己包含程序,必须把程序放进插件的目录。按照惯例我们应该将程序放在名为out或者bin的目录咯,但是你也可以使用其他名字。

因为VS Code运行在不同的平台下,我们不得不确保调试适配器程序能够很好的支持不同的平台。基于这一点有以下的选项:

  • 如果程序实现是平台无关的,例如程序运行在可以支持全平台的运行时上,你可以通过runtime属性指定有效的运行时。目前,VS Code支持'node'和'mono'运行时。我们的mock-debug就使用了这个特性。

  • 如果调试适配器需要在不同的平台上有不同的可执行程序,program属性可以被用来指定平台,像这样:

  1. "debuggers": [{
  2. "type": "gdb",
  3. "windows": {
  4. "program": "./bin/gdbDebug.exe",
  5. },
  6. "osx": {
  7. "program": "./bin/gdbDebug.sh",
  8. },
  9. "linux": {
  10. "program": "./bin/gdbDebug.sh",
  11. }
  12. }]
  • 而这两种方法的组合也是可能的。接下来的例子就是需要运行在OS X和Linux运行时上的mono程序的mono-debug适配器:
  1. "debuggers": [{
  2. "type": "mono",
  3. "program": "./bin/monoDebug.exe",
  4. "osx": {
  5. "runtime": "mono"
  6. },
  7. "linux": {
  8. "runtime": "mono"
  9. }
  10. }]

configurationAttributes属性指定了调试器在'launch.json'文件中建议和有效的值.

initialConfigurations在VS Code生成'launch.json'的时候被使用。这个默认启动配置将覆盖适配器启动配置。

发布你的调试适配器 Publishing your Debug Adapter

当你完成了你的调试适配器时,你可以将它发布到市场上:

  • 更新package.json中的属性来体现你的调试适配器的名字和用途。
  • 如这篇文章中描述的方法上传到市场共享插件

常见问题 Common Questions