maturin icon indicating copy to clipboard operation
maturin copied to clipboard

Copy `.pdb` files to `Editable Installations` and `Wheel`s for easier debugging on windows

Open WSH032 opened this issue 1 year ago • 8 comments

Copy .pdb files to Editable Installations and Wheels for easier debugging on windows

Hi team, first of all, thank you for developing this awesome tool.

Is your feature request related to a problem? Please describe

I have a project that uses the Mixed Rust/Python layout. After running maturin dev, the project layout looks like this:

my-project
├── Cargo.toml
├── my_project
│   ├── __init__.py
│   ├── bar.py
│   └── lib_name.cp310-win_amd64.pyd
├── README.md
└── src
    └── lib.rs

I then started debugging, but was surprised to find that I couldn’t set breakpoints and saw <unknown> entries in the Rust panic backtrace:

  49:     0x7ffecfdaef5c - CallWindowProcW
  50:     0x7ffecfdae684 - DispatchMessageW
  51:     0x7ffe587e6ccf - PyInit__lib_name
  52:     0x7ffe586207db - <unknown>
  53:     0x7ffe58620e5b - <unknown>
  54:     0x7ffe585d2ae1 - <unknown>
  55:     0x7ffe58565089 - <unknown>
  56:     0x7ffe583b0600 - <unknown>
  57:     0x7ffe583b0e2c - <unknown>
  58:     0x7ffe583b7a63 - <unknown>
  59:     0x7ffe586abb29 - PyInit__lib_name

I realized this was likely due to the lib_name.cp310-win_amd64.pyd/.dll not finding the corresponding .pdb file.

Specifically, cargo build produces both lib_name.dll and lib_name.pdb in the same directory (target\debug\), so there is no problem. However, both maturin dev and maturin build only copy the lib_name.dll to another directory without copying the lib_name.pdb, causing the above issue.

Describe the solution you'd like

Running $env:RUSTFLAGS="--print=link-args"; cargo build, I observed that rustc emits the linker flags /DEBUG and /PDBALTPATH:%_PDB%.

This means that as long as lib_name.cp310-win_amd64.pyd and lib_name.pdb are in the same directory, the debug information should load correctly.

After I manually copied target\debug\lib_name.pdb to my_project\lib_name.pdb, the issue was resolved.

Describe your feature request

I am not an expert in debugging, so if my approach is incorrect or there’s a better solution, please correct me!

I would like maturin to automatically copy the .pdb files to the editable installation directory (my_project\) and also include them in the wheel.

Since developers may not always generate .pdb files, or might modify the /PDBALTPATH:%_PDB% flag, I suggest adding a --pdb[=relative_path] option to maturin.

  • When the --pdb option is specified, maturin should copy the .pdb file (with the same name as lib_name.dll) to my_project\lib_name.pdb and include it in the wheel.
  • When --pdb="foo\bar.pdb" is specified, maturin should copy the .pdb file to my_project\foo\bar.pdb and place it in the corresponding location in the wheel.
    • This is typically used with /PDBALTPATH:<relative_path>

This would only affect Windows, as debugging information on Linux and macOS can be included within the library file.

Describe alternatives you've considered

Manually copying the .pdb files.

Rejection 1

See https://learn.microsoft.com/en-us/visualstudio/debugger/specify-symbol-dot-pdb-and-source-files-in-the-visual-studio-debugger?view=vs-2022

The debugger only loads .pdb files that exactly match the .pdb files created when an app was built (that is, the original .pdb files or copies). This exact duplication is necessary because the layout of apps can change even if the code itself has not changed.

This means manually copying .pdb files every time maturin dev is re-run, which is not ideal.

Rejection 2

Even if developers manually copy the .pdb files, they cannot include them in the wheel.

Additional context

For local development, the debugging experience without .pdb files is very poor, as I am unable to set breakpoints.

If you're curious, Polars has a clever method for setting breakpoints when debugging Python/Rust code.

For wheel users, not having .pdb files means that Rust panic backtraces will only show <unknown> entries, making it harder to report issues to developers. You can see an example here.

WSH032 avatar Sep 08 '24 15:09 WSH032

See also #267, since the default is packed for both Windows and macOS, I don't think this is only specific to Windows, so a --pdb option isn't the right name.

I'm going to ask the same question as in #267 again:

Do you know any Python C/C++ extension that includes debug symbol files as a reference?

messense avatar Sep 09 '24 01:09 messense

See also #267, since the default is packed for both Windows and macOS, I don't think this is only specific to Windows, so a --pdb option isn't the right name.

I don’t have experience developing on macOS, so please correct me if I’m wrong.

For macOS, I think this issue can be alleviated by setting RUSTFLAGS="-Csplit-debuginfo=off", which embeds debug information into the .dylib.

But for MSVC, only packed is supported, so copying the .pdb file seems to be the only solution we have.

If maturin chooses to support packed for macOS, what about packed for Linux? And what about unpacked? I’m not against this approach, but I think the need is more urgent for Windows, as there’s no workaround.


Do you know any Python C/C++ extension that includes debug symbol files as a reference?

meson-python seems to copy .pdb files into the wheel in debug mode. Here’s their code.

According to their documentation, they seem to have strong support for development debugging.

IDEs and other tools will then be able to show correct file locations and line numbers during debugging.

See also mesonbuild/meson#10639

File 'pandas\_libs\window\indexers.cp38-win_amd64.pdb' not found, skipping

This suggests that pandas includes .pdb files in development mode, but does not include them when publishing to pypi.

Personally, I like to include debug information even in release builds. I agree with this perspective.

WSH032 avatar Sep 09 '24 10:09 WSH032

but I think the need is more urgent for Windows, as there’s no workaround.

The workaround is copy the .pdb file manually, right? It's not ergonomic but should work.

I'm in favor of adding the support, but it should be considered for all major supported platforms. --pdb just isn't right, we need a better name. BTW, pdb is also the name of a popular Python debugger, so it'll be confusing.

As always, pull requests are welcome!

messense avatar Sep 09 '24 11:09 messense

The workaround is copy the .pdb file manually, right? It's not ergonomic but should work.

But it's really painful😫.


--pdb just isn't right, we need a better name. BTW, pdb is also the name of a popular Python debugger, so it'll be confusing.

You're right, I realized this while searching for related issues on GitHub. pdb was just a name I came up with casually, I agree that we need a better name.


As always, pull requests are welcome!

Thanks! I might give it a try this weekend if I have time, but I don’t have a macOS to test on.

WSH032 avatar Sep 09 '24 12:09 WSH032

Thanks for the workaround! I never would have figured that out on my own.

ngoldbaum avatar Nov 06 '24 21:11 ngoldbaum

It would be nice to just copy them next to the .pyd file IMO.

This is exactly what PR #2220 does, but that PR still has some finishing work to be done. Unfortunately, I have almost no time to push it.

WSH032 avatar Nov 06 '24 21:11 WSH032

So per my understanding the workaround described here only applies to the project that directly uses maturin but not for projects that has such project as a dependency, right?

saschanaz avatar May 11 '25 12:05 saschanaz

Through GitHub cross-references, I guess you're referring to cryptography.

You can clone and build it locally, which will allow you to obtain the .pdb files. But it seems you've already resolved it yourself 😁.

WSH032 avatar May 12 '25 11:05 WSH032