diff --git a/Lib/_bootsubprocess.py b/Lib/_bootsubprocess.py index 014782f616c823..aca4d9996d12dc 100644 --- a/Lib/_bootsubprocess.py +++ b/Lib/_bootsubprocess.py @@ -4,6 +4,7 @@ subprocess is unavailable. setup.py is not used on Windows. """ import os +import time # distutils.spawn used by distutils.command.build_ext @@ -70,7 +71,9 @@ def check_output(cmd, **kwargs): if not _check_cmd(cmd): raise ValueError(f"unsupported command: {cmd!r}") - tmp_filename = "check_output.tmp" + # include pid and time stamp to avoid file name clashes with parallel + # builds. + tmp_filename = f"check_output-{os.getpid()}-{int(time.time() )}.tmp" if not isinstance(cmd, str): cmd = " ".join(cmd) cmd = f"{cmd} >{tmp_filename}" diff --git a/Misc/NEWS.d/next/Build/2022-06-07-16-32-37.gh-issue-93584.QHPiBA.rst b/Misc/NEWS.d/next/Build/2022-06-07-16-32-37.gh-issue-93584.QHPiBA.rst new file mode 100644 index 00000000000000..a1f05bdff3d4fd --- /dev/null +++ b/Misc/NEWS.d/next/Build/2022-06-07-16-32-37.gh-issue-93584.QHPiBA.rst @@ -0,0 +1,2 @@ +Avoid file race condition in ``setup.py`` ``add_multiarch_paths()`` method +and ``_bootsubprocess.check_output()`` function. diff --git a/setup.py b/setup.py index 4c497346e8d7e2..6fb6432b22e0d2 100644 --- a/setup.py +++ b/setup.py @@ -10,6 +10,7 @@ import shlex import sys import sysconfig +import time import warnings from glob import glob, escape import _osx_support @@ -688,9 +689,15 @@ def check_extension_import(self, ext): def add_multiarch_paths(self): # Debian/Ubuntu multiarch support. # https://wiki.ubuntu.com/MultiarchSpec - tmpfile = os.path.join(self.build_temp, 'multiarch') - if not os.path.exists(self.build_temp): - os.makedirs(self.build_temp) + + # Poor man's conflict avoidance. PGO build use $(MAKE), which runs + # make in a separate, untracked process. Sometimes main and subproces + # run `make sharedmods` at the same time. One process removes + # "multiarch" file of the other process. + tmpfile = os.path.join( + self.build_temp, f"multiarch-{os.getpid()}-{int(time.time() )}.tmp" + ) + os.makedirs(self.build_temp, exist_ok=True) ret = run_command( '%s -print-multiarch > %s 2> /dev/null' % (CC, tmpfile)) multiarch_path_component = '' @@ -713,9 +720,7 @@ def add_multiarch_paths(self): opt = '' if CROSS_COMPILING: opt = '-t' + sysconfig.get_config_var('HOST_GNU_TYPE') - tmpfile = os.path.join(self.build_temp, 'multiarch') - if not os.path.exists(self.build_temp): - os.makedirs(self.build_temp) + os.makedirs(self.build_temp, exist_ok=True) ret = run_command( 'dpkg-architecture %s -qDEB_HOST_MULTIARCH > %s 2> /dev/null' % (opt, tmpfile))