diff --git a/CHANGELOG.md b/CHANGELOG.md index 24deab1e..9918498a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Unreleased +### Fixed +- Fix a bug where rebuilding the library would cause any running processes using it to segfault. [#295](https://github.com/PyO3/setuptools-rust/pull/295) + ## 1.5.2 (2022-09-19) ### Fixed - Fix regression in `dylib` build artifacts not being found since 1.5.0. [#290](https://github.com/PyO3/setuptools-rust/pull/290) diff --git a/setuptools_rust/build.py b/setuptools_rust/build.py index 21c19758..26a363b1 100644 --- a/setuptools_rust/build.py +++ b/setuptools_rust/build.py @@ -345,7 +345,18 @@ def install_extension( os.makedirs(os.path.dirname(ext_path), exist_ok=True) log.info("Copying rust artifact from %s to %s", dylib_path, ext_path) - shutil.copyfile(dylib_path, ext_path) + + # We want to atomically replace any existing library file. We can't + # just copy the new library directly on top of the old one as that + # causes the existing library to be modified (rather the replaced). + # This means that any process that currently uses the shared library + # will see it modified and likely segfault. + # + # We first copy the file to the same directory, as `os.rename` + # doesn't work across file system boundaries. + temp_ext_path = ext_path + "~" + shutil.copyfile(dylib_path, temp_ext_path) + os.replace(temp_ext_path, ext_path) if sys.platform != "win32" and not debug_build: args = []