Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions setuptools/_distutils/command/build_ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,10 +560,11 @@ def build_extension(self, ext) -> None:
macros = ext.define_macros[:]
for undef in ext.undef_macros:
macros.append((undef,))


ext_build_temp = os.path.join(self.build_temp, *ext.name.split('.'))
objects = self.compiler.compile(
sources,
output_dir=self.build_temp,
output_dir=ext_build_temp,
macros=macros,
include_dirs=ext.include_dirs,
debug=self.debug,
Expand Down
43 changes: 43 additions & 0 deletions setuptools/tests/test_build_ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import distutils.command.build_ext as orig
from distutils.sysconfig import get_config_var

from unittest.mock import MagicMock

IS_PYPY = '__pypy__' in sys.builtin_module_names


Expand Down Expand Up @@ -291,3 +293,44 @@ def test_build_ext_config_handling(tmpdir_cwd):
data_stream=(0, 2),
)
assert code == 0, f'\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}'

def test_parallel_build_uses_per_extension_temp_dir(tmp_path):
"""Each extension compiles into its own build_temp subdir (issue #5196)."""
from setuptools._distutils.command.build_ext import build_ext
dist = Distribution({
'ext_modules': [
Extension('pkg.ext1', sources=['a.c']),
Extension('pkg.ext2', sources=['b.c']),
]
})
cmd = build_ext(dist)
cmd.build_temp = str(tmp_path / 'build_temp')
cmd.build_lib = str(tmp_path / 'build_lib')
cmd.inplace = False
cmd.parallel = None
cmd.force = True # skip up-to-date check
cmd.swig_opts = [] # fix NoneType error
cmd.swig_cpp = False
cmd.debug = False

output_dirs = []

def fake_compile(sources, output_dir=None, **kwargs):
output_dirs.append(output_dir)
return []

cmd.compiler = MagicMock()
cmd.compiler.compile.side_effect = fake_compile
cmd.compiler.link_shared_object = MagicMock()
cmd.get_ext_fullpath = MagicMock(return_value=str(tmp_path / 'out.so'))
cmd.get_libraries = MagicMock(return_value=[])
cmd.get_export_symbols = MagicMock(return_value=[])

for ext in dist.ext_modules:
cmd.build_extension(ext)

assert len(output_dirs) == 2
assert output_dirs[0] != output_dirs[1], \
"Both extensions use the same build_temp — race condition!"
assert output_dirs[0].endswith(os.path.join('pkg', 'ext1'))
assert output_dirs[1].endswith(os.path.join('pkg', 'ext2'))