# Delocate/auditwheel, but for Windows?\`

**URL:** <https://discuss.python.org/t/delocate-auditwheel-but-for-windows/2589>\
**Category:** Packaging\
**Created:** [November 5, 2019, 1:26am UTC](https://discuss.python.org/t/delocate-auditwheel-but-for-windows/2589 "2019-11-05T01:26:43Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![zwol](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/zwol/32/1071_2.png) [@zwol](https://discuss.python.org/u/zwol)\
**Post date:** [November 5, 2019, 1:26am UTC](https://discuss.python.org/t/delocate-auditwheel-but-for-windows/2589/1 "2019-11-05T01:26:43Z")

</div>

Has someone already written a tool that does the same job auditwheel does on Linux, and delocate does on MacOS, but for Windows? That is, for each compiled-code extension in a wheel, find all of the DLLs on the system that the extension needs in order to work correctly, filter out the ones that are guaranteed to be provided by Windows itself, and then copy the rest of them into the wheel? I _think_ on Windows there isn’t any tricky object code rewriting to be done, so it shouldn’t be too complicated and basically I’m hoping someone else has already coded it up.

---

<div class="post-metadata">

**Author:** ![njs](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/njs/32/204_2.png) [@njs](https://discuss.python.org/u/njs)\
**Post date:** [November 5, 2019, 2:28am UTC](https://discuss.python.org/t/delocate-auditwheel-but-for-windows/2589/2 "2019-11-05T02:28:31Z")

</div>

You do need tricky object code rewriting (the windows loader has the exact same funny glitch that the glibc loader does, that necessitates rewriting library names to avoid isolation between wheels), but that code exists. Just no one has packaged it up into a convenient tool. I think adding support to auditwheel itself would be nice, to avoid making the packaging zoo even more confusing.

See:

> [@Need auditwheel-like utility for other platforms](https://discuss.python.org/t/need-auditwheel-like-utility-for-other-platforms/2028):
>
> Title says it all. On Windows for example, your wheel can succeed loading locally even though some dependent DLLs are not bundled, because those wheels exist on your local system. Typical example is zlib.dll, which can be found on many Windows setups but not all of them.

> [@Packaging DLLs on Windows](https://discuss.python.org/t/packaging-dlls-on-windows/1401):
>
> Continuing the discussion from [Drawing a line to the scope of Python packaging](https://discuss.python.org/t/drawing-a-line-to-the-scope-of-python-packaging/883/24): That’s news to me. Do you know of any documentation or simple example package demonstrating how to do that on Windows? For example, something like [https://github.com/pypa/python-manylinux-demo](https://github.com/pypa/python-manylinux-demo) (which shows how to use auditwheel) but for Windows would be great. CC @pf_moore

---

<div class="post-metadata">

**Author:** ![pitrou](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pitrou/32/28_2.png) [@pitrou](https://discuss.python.org/u/pitrou)\
**Post date:** [November 5, 2019, 8:48am UTC](https://discuss.python.org/t/delocate-auditwheel-but-for-windows/2589/3 "2019-11-05T08:48:10Z")

</div>

> [@njs](#):
>
> Just no one has packaged it up into a convenient tool. I think adding support to auditwheel itself would be nice, to avoid making the packaging zoo even more confusing.

Is this the kind of thing the PSF and/or some external party could fund? I know debugging DLL issues in Windows wheels is kind of a chore for [us](https://arrow.apache.org/docs/python/), and any help through better tooling would be more than welcome 😉

cc @brettcannon

---

<div class="post-metadata">

**Author:** ![steve.dower](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steve.dower/32/56_2.png) [@steve.dower](https://discuss.python.org/u/steve.dower)\
**Post date:** [November 5, 2019, 12:17pm UTC](https://discuss.python.org/t/delocate-auditwheel-but-for-windows/2589/4 "2019-11-05T12:17:04Z")

</div>

> [@pitrou](#):
>
> I know debugging DLL issues in Windows wheels is kind of a chore for [us](https://arrow.apache.org/docs/python/), and any help through better tooling would be more than welcom

Are you debugging using an actual debugger on Windows? Because WinDBG, Visual Studio or even Process Monitor are very good tools for this, and at a simpler level, dumpbin (to list load time dependencies) is helpful too.

---

<div class="post-metadata">

**Author:** ![pitrou](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pitrou/32/28_2.png) [@pitrou](https://discuss.python.org/u/pitrou)\
**Post date:** [November 5, 2019, 12:29pm UTC](https://discuss.python.org/t/delocate-auditwheel-but-for-windows/2589/5 "2019-11-05T12:29:29Z")

</div>

By debugging I meant finding out which DLL fails loading when we get an `ImportError`. The only way I’ve found to do that is to use Process Monitor and search manually through trace entries to find the offending one. It is extremely tedious and, more annoying still, we’d need a CLI tool that works in CI (because situations like “the wheel fails loading on this particular AppVeyor setup but we can’t reproduce locally” have occurred several times already).

(as a last resort, we could use [AppVeyor remote desktop](https://www.appveyor.com/docs/how-to/rdp-to-build-worker/) and run Process Monitor over a high-latency connection. Let’s just say it’s not the most convenient solution)

If you’ve got a magic `dumpbin` incantation that finds out DLL dependencies recursively (and which ones are missing) then I’d love to know about it 🙂

---

<div class="post-metadata">

**Author:** ![brettcannon](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/brettcannon/32/34895_2.png) [@brettcannon](https://discuss.python.org/u/brettcannon)\
**Post date:** [November 5, 2019, 7:08pm UTC](https://discuss.python.org/t/delocate-auditwheel-but-for-windows/2589/6 "2019-11-05T19:08:16Z")

</div>

> [@pitrou](#):
>
> Is this the kind of thing the PSF and/or some external party could fund?

I assumed I got looped in for this sentence. For package-related funding the package WG has typically handled that and it requires a proposal to the PSF for a grant.

---

<div class="post-metadata">

**Author:** ![steve.dower](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steve.dower/32/56_2.png) [@steve.dower](https://discuss.python.org/u/steve.dower)\
**Post date:** [November 5, 2019, 11:27pm UTC](https://discuss.python.org/t/delocate-auditwheel-but-for-windows/2589/7 "2019-11-05T23:27:33Z")

</div>

> [@pitrou](#):
>
> we’d need a CLI tool that works in CI (because situations like “the wheel fails loading on this particular AppVeyor setup but we can’t reproduce locally” have occurred several times already).

I’m pretty sure the CLI version would be based on xperf, but I don’t know the incantation to collect the events you want. Running under a native debugger should break at the load, but that’s not trivial to analyze either.

Dumpbin doesn’t attempt to resolve anything, so you really need to debug a running process to take search paths etc into account.

---

<div class="post-metadata">

**Author:** ![ihnorton](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/ihnorton/32/760_2.png) [@ihnorton](https://discuss.python.org/u/ihnorton)\
**Post date:** [November 6, 2019, 3:41am UTC](https://discuss.python.org/t/delocate-auditwheel-but-for-windows/2589/8 "2019-11-06T03:41:38Z")

</div>

> [@pitrou](#):
>
> we’d need a CLI tool that works in CI (because situations like “the wheel fails loading on this particular AppVeyor setup but we can’t reproduce locally” have occurred several times already).

You might want to try:  
[https://lucasg.github.io/2018/04/29/Dependencies-command-line/](https://lucasg.github.io/2018/04/29/Dependencies-command-line/)

(rewrite of the invaluable `Dependency Walker`. I have used the `Dependencies` GUI version a few years ago, but have not tried the CLI)

---

<div class="post-metadata">

**Author:** ![vinayak-mehta](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/vinayak-mehta/32/965_2.png) [@vinayak-mehta](https://discuss.python.org/u/vinayak-mehta)\
**Post date:** [October 22, 2020, 10:39pm UTC](https://discuss.python.org/t/delocate-auditwheel-but-for-windows/2589/9 "2020-10-22T22:39:40Z")

</div>

I’m [trying to wrap a `poppler` utility using `pybind11`](https://github.com/vinayak-mehta/pdftopng/), and getting up to speed on packaging C extensions (that have shared library dependencies) in the process. It was relatively easy to build Linux/macOS wheels compared to Windows ones, but this week [I was able to build Windows wheels](https://github.com/vinayak-mehta/pdftopng/actions/runs/318517360) thanks to all the replies in this post (and all the linked posts)! I’m using [cibuildwheel](https://github.com/joerick/cibuildwheel) to build the wheels using GitHub Actions, [`vcpkg`](https://github.com/microsoft/vcpkg) to install the external shared libraries, and a [`wheel_repair.py`](https://github.com/vinayak-mehta/pdftopng/blob/6e4a9d589228f66dfbb6f0197740b0b7c1bef9b3/scripts/wheel_repair.py) to copy the shared library DLLs into the wheel. `wheel_repair.py` follows a scoped down version of the workflow that @njs described [in this post](https://discuss.python.org/t/need-auditwheel-like-utility-for-other-platforms/2028/4):

- Look for a PYD file in the wheel
- Get the DLL dependencies (both direct and transitive) for that PYD file using [`pefile`](https://github.com/erocarrera/pefile), and look for them in the `vcpkg` directory
- Mangle the DLL names using their `sha256` hash (using the same function as `auditwheel`) and copy them into the wheel directory (alongside the PYD file)
- Modify the PYD import table with the new mangled DLL names using [machomachomangler](https://github.com/njsmith/machomachomangler) by Nathaniel (and also do this for each DLL which depends on other mangled DLLs)

There are some limitations to this approach, (1) it assumes that there’s just one PYD file in the wheel which might not be the case for complex projects but works for my simple extension, and (2) it doesn’t look for DLLs in system directories (as I wasn’t sure what all directories to look into).

The built Windows wheel worked on my machine but I need to test it on a fresh Windows instance to see if I need to bundle any other DLLs.

I wanted to ask you all if this is an ok approach to bundle DLLs within a Windows wheel, if the wheels would work on Windows versions older than 10, and if there’s anything that I might’ve missed or could improve. @steve.dower I would love to have your advice on this! And if you have some more time, could you please look at the DLL imports ([Dependencies tool output as a GitHub gist](https://gist.github.com/vinayak-mehta/350cfb416af44dd4ef01caf5f3de6dbe)) for my compiled PYD file and tell me if I need to bundle any other system DLLs apart from `freetype`, `libpng16`, `jpeg62` (and all of their DLL dependencies that I install using `vcpkg`)?

I’ve also documented my experience building Windows wheels for others looking to do the same. Here are the blog posts in reverse chronological order:

- [Bundling DLLs with Windows wheels (the DLL mangling way)](https://vinayak.io/2020/10/22/day-52-bundling-dlls-with-windows-wheels-the-dll-mangling-way/)
- [Bundling DLLs with Windows wheels (the package\_data way)](https://vinayak.io/2020/10/21/day-51-bundling-dlls-with-windows-wheels-the-package-data-way/)
- [How to (almost) build a C extension wheel on Windows (with external dependencies)](https://vinayak.io/2020/10/14/day-45b-how-to-almost-build-a-c-extension-wheel-on-windows-with-external-dependencies/)

---

<div class="post-metadata">

**Author:** ![duburcqa](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/duburcqa/32/2864_2.png) [@duburcqa](https://discuss.python.org/u/duburcqa)\
**Post date:** [November 12, 2020, 10:02am UTC](https://discuss.python.org/t/delocate-auditwheel-but-for-windows/2589/10 "2020-11-12T10:02:12Z")

</div>

I faced a similar issue so I used your script `wheel_repair.py` and extended it to add new functionalities:

- It supports hierarchical folder architecture with multiple `.pyd`.
- Similarly to `auditwheel`, the dll are bundled in _package\_name_.libs directory, alongside the package but not inside. This way, common dependencies to multiple `.pyd` are shared, not duplicated.

[Here](https://github.com/Wandercraft/jiminy/blob/648c0ec918ca2c2f734a32bada1dbfaf6226de48/build_tools/wheel_repair.py) is the source.

---

<div class="post-metadata">

**Author:** ![adang1345](https://avatars.discourse-cdn.com/v4/letter/a/ad7895/32.png) [@adang1345](https://discuss.python.org/u/adang1345)\
**Post date:** [December 27, 2020, 4:14pm UTC](https://discuss.python.org/t/delocate-auditwheel-but-for-windows/2589/11 "2020-12-27T16:14:22Z")

</div>

I have wanted a fully-functioning tool like `delocate`/`auditwheel` for Windows for a while, so I have developed one myself. It scans the wheel for DLL dependencies, figures out which dependencies are not provided by the Windows system, copies those DLLs into the wheel, mangles the DLL names, and patches ` __init__.py` so that these DLLs are loaded at runtime.

Source: [https://github.com/adang1345/delvewheel](https://github.com/adang1345/delvewheel)  
Release: [https://pypi.org/project/delvewheel/](https://pypi.org/project/delvewheel/)
