diff options
author | Daan De Meyer <daan.j.demeyer@gmail.com> | 2022-07-15 14:10:31 +0200 |
---|---|---|
committer | Xavier Claessens <xclaesse@gmail.com> | 2023-03-16 17:18:30 -0400 |
commit | adb619db6110d14e8f56366dbc2ce271abc4558c (patch) | |
tree | 6be4f4c5658b5d3b53713e9bace0ff82f418e044 /mesonbuild | |
parent | e0792f48197ff03dab4692e22bd2b13552c53823 (diff) | |
download | meson-adb619db6110d14e8f56366dbc2ce271abc4558c.zip meson-adb619db6110d14e8f56366dbc2ce271abc4558c.tar.gz meson-adb619db6110d14e8f56366dbc2ce271abc4558c.tar.bz2 |
Stop using replace_if_different() for coredata pickle file
This was added in f774609 to only change the access time of the
coredata file if the coredata struct actually changed. However,
this doesn't work as pickle serializations aren't guaranteed to
be stable. Instead, let's manually check if options have changed
values and skip the save if they haven't changed.
We also extend the associated unit test to cover all the option
types and to ensure that configure does get executed if one of the
options changes value.
Diffstat (limited to 'mesonbuild')
-rw-r--r-- | mesonbuild/coredata.py | 51 | ||||
-rw-r--r-- | mesonbuild/mconf.py | 7 |
2 files changed, 37 insertions, 21 deletions
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 38d6fcf..564f54c 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -27,7 +27,7 @@ from .mesonlib import ( default_prefix, default_datadir, default_includedir, default_infodir, default_localedir, default_mandir, default_sbindir, default_sysconfdir, split_args, OptionKey, OptionType, stringlistify, - pickle_load, replace_if_different + pickle_load ) from .wrap import WrapMode import ast @@ -103,8 +103,10 @@ class UserOption(T.Generic[_T], HoldableObject): def validate_value(self, value: T.Any) -> _T: raise RuntimeError('Derived option class did not override validate_value.') - def set_value(self, newvalue: T.Any) -> None: + def set_value(self, newvalue: T.Any) -> bool: + oldvalue = getattr(self, 'value', None) self.value = self.validate_value(newvalue) + return self.value != oldvalue class UserStringOption(UserOption[str]): def __init__(self, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING, @@ -651,7 +653,8 @@ class CoreData: raise MesonException(f'Tried to get unknown builtin option {str(key)}') - def set_option(self, key: OptionKey, value) -> None: + def set_option(self, key: OptionKey, value) -> bool: + dirty = False if key.is_builtin(): if key.name == 'prefix': value = self.sanitize_prefix(value) @@ -691,17 +694,20 @@ class CoreData: newname = opt.deprecated newkey = OptionKey.from_string(newname).evolve(subproject=key.subproject) mlog.deprecation(f'Option {key.name!r} is replaced by {newname!r}') - self.set_option(newkey, value) + dirty |= self.set_option(newkey, value) - opt.set_value(value) + dirty |= opt.set_value(value) if key.name == 'buildtype': - self._set_others_from_buildtype(value) + dirty |= self._set_others_from_buildtype(value) elif key.name in {'wrap_mode', 'force_fallback_for'}: # We could have the system dependency cached for a dependency that # is now forced to use subproject fallback. We probably could have # more fine grained cache invalidation, but better be safe. self.clear_deps_cache() + dirty = True + + return dirty def clear_deps_cache(self): self.deps.host.clear() @@ -736,7 +742,9 @@ class CoreData: result.append(('debug', actual_debug, debug)) return result - def _set_others_from_buildtype(self, value: str) -> None: + def _set_others_from_buildtype(self, value: str) -> bool: + dirty = False + if value == 'plain': opt = 'plain' debug = False @@ -754,9 +762,12 @@ class CoreData: debug = True else: assert value == 'custom' - return - self.options[OptionKey('optimization')].set_value(opt) - self.options[OptionKey('debug')].set_value(debug) + return False + + dirty |= self.options[OptionKey('optimization')].set_value(opt) + dirty |= self.options[OptionKey('debug')].set_value(debug) + + return dirty @staticmethod def is_per_machine_option(optname: OptionKey) -> bool: @@ -797,21 +808,25 @@ class CoreData: return False return len(self.cross_files) > 0 - def copy_build_options_from_regular_ones(self) -> None: + def copy_build_options_from_regular_ones(self) -> bool: + dirty = False assert not self.is_cross_build() for k in BUILTIN_OPTIONS_PER_MACHINE: o = self.options[k] - self.options[k.as_build()].set_value(o.value) + dirty |= self.options[k.as_build()].set_value(o.value) for bk, bv in self.options.items(): if bk.machine is MachineChoice.BUILD: hk = bk.as_host() try: hv = self.options[hk] - bv.set_value(hv.value) + dirty |= bv.set_value(hv.value) except KeyError: continue - def set_options(self, options: T.Dict[OptionKey, T.Any], subproject: str = '') -> None: + return dirty + + def set_options(self, options: T.Dict[OptionKey, T.Any], subproject: str = '') -> bool: + dirty = False if not self.is_cross_build(): options = {k: v for k, v in options.items() if k.machine is not MachineChoice.BUILD} # Set prefix first because it's needed to sanitize other options @@ -828,7 +843,7 @@ class CoreData: if k == pfk: continue elif k in self.options: - self.set_option(k, v) + dirty |= self.set_option(k, v) elif k.machine != MachineChoice.BUILD and k.type != OptionType.COMPILER: unknown_options.append(k) if unknown_options: @@ -837,7 +852,9 @@ class CoreData: raise MesonException(f'{sub}Unknown options: "{unknown_options_str}"') if not self.is_cross_build(): - self.copy_build_options_from_regular_ones() + dirty |= self.copy_build_options_from_regular_ones() + + return dirty def set_default_options(self, default_options: T.MutableMapping[OptionKey, str], subproject: str, env: 'Environment') -> None: # Main project can set default options on subprojects, but subprojects @@ -1072,7 +1089,7 @@ def save(obj: CoreData, build_dir: str) -> str: pickle.dump(obj, f) f.flush() os.fsync(f.fileno()) - replace_if_different(filename, tempfilename) + os.replace(tempfilename, filename) return filename diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index 46d0463..35e862f 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -90,8 +90,8 @@ class Conf: def clear_cache(self): self.coredata.clear_deps_cache() - def set_options(self, options): - self.coredata.set_options(options) + def set_options(self, options) -> bool: + return self.coredata.set_options(options) def save(self): # Do nothing when using introspection @@ -308,9 +308,8 @@ def run(options): save = False if options.cmd_line_options: - c.set_options(options.cmd_line_options) + save = c.set_options(options.cmd_line_options) coredata.update_cmd_line_file(builddir, options) - save = True elif options.clearcache: c.clear_cache() save = True |