summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorSayed Adel <seiko@imavr.com>2021-05-05 12:11:28 +0200
committerSayed Adel <seiko@imavr.com>2021-05-05 12:25:42 +0200
commitd3e666c94230d4b45b9736103446f8b526ef426a (patch)
treec4e4142f6bcff7d511f0ec1f76d25a8a0f17dbec /numpy
parent4d753a0cd67cc381af9d096afdafda674a37c971 (diff)
downloadnumpy-d3e666c94230d4b45b9736103446f8b526ef426a.tar.gz
BLD, BUG: Fix bdist_wheel duplicate building
The bug can occur only if the build option `build` was passed before the option `bdist_wheel`. You may still realize a duplicate printing for the compiler optimization report in the build log, which is normal due to multiple calling of command `build` by setuptools.
Diffstat (limited to 'numpy')
-rw-r--r--numpy/distutils/ccompiler_opt.py41
-rw-r--r--numpy/distutils/command/build_clib.py20
-rw-r--r--numpy/distutils/command/build_ext.py19
3 files changed, 54 insertions, 26 deletions
diff --git a/numpy/distutils/ccompiler_opt.py b/numpy/distutils/ccompiler_opt.py
index aea9835c7..316d3a338 100644
--- a/numpy/distutils/ccompiler_opt.py
+++ b/numpy/distutils/ccompiler_opt.py
@@ -747,12 +747,14 @@ class _Cache:
self.cache_me = {}
self.cache_private = set()
self.cache_infile = False
+ self._cache_path = None
if self.conf_nocache:
self.dist_log("cache is disabled by `Config`")
return
- chash = self.cache_hash(*factors, *self.conf_cache_factors)
+ self._cache_hash = self.cache_hash(*factors, *self.conf_cache_factors)
+ self._cache_path = cache_path
if cache_path:
if os.path.exists(cache_path):
self.dist_log("load cache from file ->", cache_path)
@@ -765,7 +767,7 @@ class _Cache:
elif not hasattr(cache_mod, "hash") or \
not hasattr(cache_mod, "data"):
self.dist_log("invalid cache file", stderr=True)
- elif chash == cache_mod.hash:
+ elif self._cache_hash == cache_mod.hash:
self.dist_log("hit the file cache")
for attr, val in cache_mod.data.items():
setattr(self, attr, val)
@@ -773,10 +775,8 @@ class _Cache:
else:
self.dist_log("miss the file cache")
- atexit.register(self._cache_write, cache_path, chash)
-
if not self.cache_infile:
- other_cache = _share_cache.get(chash)
+ other_cache = _share_cache.get(self._cache_hash)
if other_cache:
self.dist_log("hit the memory cache")
for attr, val in other_cache.__dict__.items():
@@ -785,32 +785,41 @@ class _Cache:
continue
setattr(self, attr, val)
- _share_cache[chash] = self
+ _share_cache[self._cache_hash] = self
+ atexit.register(self.cache_flush)
def __del__(self):
- # TODO: remove the cache form share on del
- pass
+ for h, o in _share_cache.items():
+ if o == self:
+ _share_cache.pop(h)
+ break
- def _cache_write(self, cache_path, cache_hash):
+ def cache_flush(self):
+ """
+ Force update the cache.
+ """
+ if not self._cache_path:
+ return
# TODO: don't write if the cache doesn't change
- self.dist_log("write cache to path ->", cache_path)
- for attr in list(self.__dict__.keys()):
+ self.dist_log("write cache to path ->", self._cache_path)
+ cdict = self.__dict__.copy()
+ for attr in self.__dict__.keys():
if re.match(self._cache_ignore, attr):
- self.__dict__.pop(attr)
+ cdict.pop(attr)
- d = os.path.dirname(cache_path)
+ d = os.path.dirname(self._cache_path)
if not os.path.exists(d):
os.makedirs(d)
- repr_dict = pprint.pformat(self.__dict__, compact=True)
- with open(cache_path, "w") as f:
+ repr_dict = pprint.pformat(cdict, compact=True)
+ with open(self._cache_path, "w") as f:
f.write(textwrap.dedent("""\
# AUTOGENERATED DON'T EDIT
# Please make changes to the code generator \
(distutils/ccompiler_opt.py)
hash = {}
data = \\
- """).format(cache_hash))
+ """).format(self._cache_hash))
f.write(repr_dict)
def cache_hash(self, *factors):
diff --git a/numpy/distutils/command/build_clib.py b/numpy/distutils/command/build_clib.py
index e1f15d465..0e31a7dee 100644
--- a/numpy/distutils/command/build_clib.py
+++ b/numpy/distutils/command/build_clib.py
@@ -123,15 +123,20 @@ class build_clib(old_build_clib):
opt_cache_path = os.path.abspath(
os.path.join(self.build_temp, 'ccompiler_opt_cache_clib.py')
)
+ if hasattr(self, "compiler_opt"):
+ # By default `CCompilerOpt` update the cache at the exit of
+ # the process, which may lead to duplicate building
+ # (see build_extension()/force_rebuild) if run() called
+ # multiple times within the same os process/thread without
+ # giving the chance the previous instances of `CCompilerOpt`
+ # to update the cache.
+ self.compiler_opt.cache_flush()
+
self.compiler_opt = new_ccompiler_opt(
compiler=self.compiler, dispatch_hpath=dispatch_hpath,
cpu_baseline=self.cpu_baseline, cpu_dispatch=self.cpu_dispatch,
cache_path=opt_cache_path
)
- if not self.compiler_opt.is_cached():
- log.info("Detected changes on compiler optimizations, force rebuilding")
- self.force = True
-
def report(copt):
log.info("\n########### CLIB COMPILER OPTIMIZATION ###########")
log.info(copt.report(full=True))
@@ -212,7 +217,12 @@ class build_clib(old_build_clib):
lib_file = compiler.library_filename(lib_name,
output_dir=self.build_clib)
depends = sources + build_info.get('depends', [])
- if not (self.force or newer_group(depends, lib_file, 'newer')):
+
+ force_rebuild = self.force
+ if not self.disable_optimization and not self.compiler_opt.is_cached():
+ log.debug("Detected changes on compiler optimizations")
+ force_rebuild = True
+ if not (force_rebuild or newer_group(depends, lib_file, 'newer')):
log.debug("skipping '%s' library (up-to-date)", lib_name)
return
else:
diff --git a/numpy/distutils/command/build_ext.py b/numpy/distutils/command/build_ext.py
index ca29ad4c0..84ec8aa2c 100644
--- a/numpy/distutils/command/build_ext.py
+++ b/numpy/distutils/command/build_ext.py
@@ -151,15 +151,20 @@ class build_ext (old_build_ext):
opt_cache_path = os.path.abspath(
os.path.join(self.build_temp, 'ccompiler_opt_cache_ext.py')
)
+ if hasattr(self, "compiler_opt"):
+ # By default `CCompilerOpt` update the cache at the exit of
+ # the process, which may lead to duplicate building
+ # (see build_extension()/force_rebuild) if run() called
+ # multiple times within the same os process/thread without
+ # giving the chance the previous instances of `CCompilerOpt`
+ # to update the cache.
+ self.compiler_opt.cache_flush()
+
self.compiler_opt = new_ccompiler_opt(
compiler=self.compiler, dispatch_hpath=dispatch_hpath,
cpu_baseline=self.cpu_baseline, cpu_dispatch=self.cpu_dispatch,
cache_path=opt_cache_path
)
- if not self.compiler_opt.is_cached():
- log.info("Detected changes on compiler optimizations, force rebuilding")
- self.force = True
-
def report(copt):
log.info("\n########### EXT COMPILER OPTIMIZATION ###########")
log.info(copt.report(full=True))
@@ -360,7 +365,11 @@ class build_ext (old_build_ext):
self.get_ext_filename(fullname))
depends = sources + ext.depends
- if not (self.force or newer_group(depends, ext_filename, 'newer')):
+ force_rebuild = self.force
+ if not self.disable_optimization and not self.compiler_opt.is_cached():
+ log.debug("Detected changes on compiler optimizations")
+ force_rebuild = True
+ if not (force_rebuild or newer_group(depends, ext_filename, 'newer')):
log.debug("skipping '%s' extension (up-to-date)", ext.name)
return
else: