diff options
author | Sayed Adel <seiko@imavr.com> | 2021-05-05 12:11:28 +0200 |
---|---|---|
committer | Sayed Adel <seiko@imavr.com> | 2021-05-05 12:25:42 +0200 |
commit | d3e666c94230d4b45b9736103446f8b526ef426a (patch) | |
tree | c4e4142f6bcff7d511f0ec1f76d25a8a0f17dbec | |
parent | 4d753a0cd67cc381af9d096afdafda674a37c971 (diff) | |
download | numpy-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.
-rw-r--r-- | numpy/distutils/ccompiler_opt.py | 41 | ||||
-rw-r--r-- | numpy/distutils/command/build_clib.py | 20 | ||||
-rw-r--r-- | numpy/distutils/command/build_ext.py | 19 |
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: |