使用Visual Studio Code(MacOS)调试Pybind11扩展程序

4

最近我一直在使用pybind11,现在我已经开始熟悉它了,对它感到非常兴奋。这是一个很棒的工具。做pybind11的最后一块拼图是调试部分。我遵循下面的指南,用lldb实现了命令行调试:

使用lldb调试pybind11

我花了一些时间尝试在Visual Studio Code中实现debug功能,但成果有限。首先问题是,为了设置附加配置,您需要指定Python可执行文件(而不是进程ID),如果有多个活动Python进程,则我不知道该怎么做。

抛开这点,我设置了一个启动配置,指向ipython可执行文件,这是最方便使用的。当我尝试启动调试时,出现了以下情况:

enter image description here

有人能解释一下吗?

如果我将可执行文件更改为普通Python,则在Debug Console中会得到以下结果:

Could not initialize Python interpreter - only native expressions will be available.
Launching: /Users/andy/anaconda3/envs/SciPy37/bin/python

但是如果我打开终端窗口,就可以成功输入Python表达式并触发代码中设置的断点。太棒了!但还有一个问题。当我的一个扩展需要加载另一个dylib时,它找不到它。

>>> import block_test
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: dlopen(/Users/andy/Dropbox (Personal)/Developer/AudioDev/GenericDSP/Common/SciPy/BlockTest/build/block_test.cpython-37m-darwin.so, 2): Symbol not found: _vDSP_vsmul
  Referenced from: /Users/andy/Dropbox (Personal)/Developer/AudioDev/GenericDSP/Common/SciPy/BlockTest/build/block_test.cpython-37m-darwin.so
  Expected in: flat namespace
 in /Users/andy/Dropbox (Personal)/Developer/AudioDev/GenericDSP/Common/SciPy/BlockTest/build/block_test.cpython-37m-darwin.so

这有些说得通,因为_vDSP_vsmul是苹果DSP加速库的一部分。但我不明白的是,当我使用本帖开头提到的命令行调试技术时,就没有这个问题。显然,这与dylibs的查找方式有关,但为什么会与命令行情况不同呢?

对于这些问题的任何帮助都将非常有用。让Visual Studio Code中的调试工具运行起来是实现Python和C++之间绝妙互操作性缺失的关键。


结果证明,依赖库的第三个问题并不是VSC的问题。Python命令行也有同样的问题。ipython没有这个问题,不知道为什么。通过显式链接加速库来解决了这个问题。但是关于ipython和缺少架构的错误消息的谜团仍然存在。 - Andrew Voelkel
虽然我还没有弄清楚如何实现 Visual Studio Code 和 IPython 的无缝调试,但我已经找到了一种使用 Xcode 的简单方法。如果你正在使用 cmake,你可以用它来生成一个 Xcode 项目。然后你可以启动 iPython,在 Activity Monitor 中找到 pid,并通过 pid 连接到进程进行调试。它工作得非常好。 - Andrew Voelkel
3个回答

1
我找到了如何在Mac OS Catalina上使用Visual Studio Code和iPython进行附加进程调试的方法。在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": [
    {
      "type": "lldb",
      "request": "launch",
      "name": "Debug",
      "program": "path_to/bin/python",
      "args": [],
      "cwd": "${workspaceFolder}/build"
    },
    { 
      "name": "Debug Attach",
      "type": "lldb",
      "request": "attach",
      "program": "path_to/bin/python",
      "processId": "${command:pickProcess}",
      "MIMode": "gdb"
  },
  ]
}

首先,在尝试开始调试之前,请在终端窗口中启动IPython,以便您可以附加到进程。

我最初遇到的问题是VSC抱怨json文件中没有“program”条目,但当附加到进程时似乎与此无关。实际上它可能完全无关,但你必须添加它才能使事情正常工作。我还没有尝试在程序参数中放入虚假条目来查看值是否有影响。

还有一个细节-有时VSC中的断点似乎未启用,创建它们时会出现未填充的圆圈而不是红色圆点。但似乎您仍然会命中断点。然而,根据我的以往经验,为了获得最佳效果,最好在附加到进程后在iPython中导入测试包。


我还没有尝试过在程序参数中放置虚假条目,以查看值是否有关紧要性。对我来说,无效的输入会停止启动,因此这里似乎需要一个有效的程序/可执行文件。 - alexandre iolov

1

我在 macOS 10.14.5 上使用 LLDB 遇到了问题。 对我有用的是安装 "vadimcn.vscode-lldb" 扩展程序,并进行以下配置:

{
    // 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": [
        {
            "type": "lldb",
            "request": "attach",
            "name": "Attach pid",
            "pid": "${command:pickProcess}", // use ${command:pickProcess} to pick other users' processes,
        },
        {
            "name": "Python: Current File",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "stopOnEntry": true,
            "env": {
                "PYTHONPATH": "${workspaceFolder}/build"
            }
        },
        {
            "type": "lldb",
            "request": "launch",
            "name": "LLDB Python",
            "program": "/usr/local/bin/python3",
            "args": [
                "${file}"
            ],
            "cwd": "${workspaceFolder}",
            "stopOnEntry": false,
            "env": {
                "PYTHONPATH": "${workspaceFolder}/build"
            },
        },
    ]
}

你可以使用 lldb 启动 Python (LLDB Python),或者先启动一个 Python 调试会话 (Python: Current File),之后再附加到 (Attach pid)。第二个选项的好处是可以在 Python 和 C++ 中设置断点。


由于出现了三个不同的Python进程,并且当我尝试附加时,"当前文件"和"附加"方法对我来说都无法工作。 - kjohnsen

1

我偶然发现了这篇SO文章如何配置VS Code,以便在调试Python脚本时加载共享库(.so)并能够进入其中?,与其附加到已经运行的调试器上,我可以从VSCode中启动gdb:

    // 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": "(gdb) Launch 1123",
            "type": "cppdbg",
            "request": "launch",
            "program": "/usr/bin/python3",
            "args": ["${file}"],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ]
        }
    ]
}

从这个launch.json设置中,我能够在我的C++代码中跨越断点并调试我的C++代码。然而,正如上一个SO帖子的评论中提到的那样,我不确定是否有一种方法在调试会话期间在Python和C/C++代码之间切换。如果尝试在我的Python文件上设置断点,我也会“得到未填充的圆圈而不是红点”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接