-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[BUG] setuptools does not protect against race conditions on parallel builds #3119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
FWIW, I could add a C extension build to the reproducer to cause version-specific wheels to be built, use different parallel builds with multiple Python versions to more closely match my workflow -- but that feels unnecessary given that the error behaviour is going to be largely the same. |
Does the issue exist with pep517-isolated builds? |
I was able to replicate the behavior, and setting PIP_USE_PEP517=1 dosen't work around the issue. Is that because build isolation isolates the Python environment but not the source? I thought it also copied the source (though I understand why it might not). Aha! I see that pip 21 dropped support for isolated builds. If I downgrade to pip 20.0.2 and set PIP_USE_PEP517=1, the repro no longer occurs. It'll take some work to get setuptools to support parallel builds, and I won't be surprised if it requires changes to distutils as well. It may prove challenging before setuptools has fully adopted distutils (and no longer relies on stdlib). |
Yea, 21.3 switched to in-tree builds unconditionally, instead of copying to a randomised build directory. |
I don't know if this is the same issue since it looks like you're running setuptools in parallel rather than using setuptools to build extensions in parallel, but I've at least ran into a similar issue with that. setup(
ext_modules=[
Extension("A", ["a.c", "common.c"]),
Extension("B", ["b.c", "common.c"])
]
) When this runs in parallel, each module will compile its own copy of |
Hi @Yay295 I believe that is a separated thing. I think your use case might require something like the following: setup(
# ...
libraries=[
# Compile a binary archive once and re-use in extensions
("common", {"sources": ["common.c"]}),
],
ext_modules=[
Extension("A", sources=["a.c"], libraries=["common"]),
Extension("B", sources=["b.c"], libraries=["common"]),
],
) |
Thanks, that seems to work. Though it doesn't look like the https://setuptools.pypa.io/en/latest/references/keywords.html |
Yes, that is probably something inherited from PR for doc improvements are always welcome! |
## Summary I don't love this, but it turns out that setuptools is not robust to parallel builds: pypa/setuptools#3119. As a result, if you run uv from multiple processes, and they each attempt to build the same source distribution, you can hit failures. This PR applies an advisory lock to the source distribution directory. We apply it unconditionally, even if we ultimately find something in the cache and _don't_ do a build, which helps ensure that we only build the distribution once (and wait for that build to complete) rather than kicking off builds from each thread. Closes #3512. ## Test Plan Ran: ```sh #!/bin/bash make_venv(){ target/debug/uv venv $1 source $1/bin/activate target/debug/uv pip install opentracing --no-deps --verbose } for i in {1..8} do make_venv ./$1/$i & done ```
setuptools version
setuptools == 60.9.3
Python version
3.9, although this is Python version agnostic
OS
MacOS, although this is OS-agnostic
Additional environment information
No response
Description
I have a Makefile that tries to build multiple wheels for a Python package, in parallel. This fails, with weird errors such as the following (from a
pip wheel . --log out.log
output):And various other errors related to files in the build directory.
This is because setuptools does not have any isolation/protection against parallel builds.
Expected behavior
setuptools
works properly with parallel builds that use the same working directory. Either through some sort of separation within the build directory, or through filesystem based locks for the build directory.A more targetted behaviour change would be to include the running Python version into the build directory paths, which would enable building extensions in parallel for a Python package; which is my main use case. I do think a more general solution would be nicer, eg for the example I have below. :)
How to Reproduce
I'll take an example of a pure-Python wheel below, but the behavior for platform-specific wheels is similar.
Output
This is more of a reproducer -- examples of setuptools' failure messages are shown above and change depending on what had a race condition in each run. :)
Some example errors are mentioned in the description. If you run this yourself, you can see the failure output and wheels in
one/
,two/
andthree/
directories.The text was updated successfully, but these errors were encountered: