@@ -993,6 +993,11 @@ def __init__(
993993 self .import_options : dict [str , bytes ] = {}
994994 # Cache for transitive dependency check (expensive).
995995 self .transitive_deps_cache : dict [tuple [int , int ], bool ] = {}
996+ # Cache for options_snapshot() keyed by id() of the cloned Options.
997+ # Most modules share a handful of distinct configs. The keepalive
998+ # list keeps clones reachable so id() is stable for cache keys.
999+ self .options_snapshot_cache : dict [int , tuple [str , str ]] = {}
1000+ self ._options_snapshot_keepalive : list [Options ] = []
9961001 # Packages for which we know presence or absence of __getattr__().
9971002 self .known_partial_packages : dict [str , bool ] = {}
9981003
@@ -1966,23 +1971,32 @@ def get_cache_names(id: str, path: str, options: Options) -> tuple[str, str, str
19661971 return prefix + meta_suffix , prefix + data_suffix , deps_json
19671972
19681973
1969- def options_snapshot (id : str , manager : BuildManager ) -> dict [str , object ]:
1974+ def options_snapshot (module : str , manager : BuildManager ) -> dict [str , object ]:
19701975 """Make compact snapshot of options for a module.
19711976
19721977 Separately store only the options we may compare individually, and take a hash
19731978 of everything else. If --debug-cache is specified, fall back to full snapshot.
19741979 """
1975- platform_opt , values = manager .options .clone_for_module (id ). select_options_affecting_cache ( )
1980+ cloned = manager .options .clone_for_module (module )
19761981 if manager .options .debug_cache :
19771982 # Build full options snapshot for debugging purposes.
1983+ platform_opt , values = cloned .select_options_affecting_cache ()
19781984 result : dict [str , object ] = {"platform" : platform_opt }
19791985 for key , val in zip (OPTIONS_AFFECTING_CACHE_NO_PLATFORM , values ):
19801986 result [key ] = val
19811987 return result
1982- # Process most options quickly, since this is performance critical.
1983- buf = WriteBuffer ()
1984- write_json_value (buf , cast (JsonValue , values ))
1985- return {"platform" : platform_opt , "other_options" : hash_digest (buf .getvalue ())}
1988+ cache = manager .options_snapshot_cache
1989+ key = id (cloned )
1990+ cached = cache .get (key )
1991+ if cached is None :
1992+ platform_opt , values = cloned .select_options_affecting_cache ()
1993+ buf = WriteBuffer ()
1994+ write_json_value (buf , cast (JsonValue , values ))
1995+ cached = (platform_opt , hash_digest (buf .getvalue ()))
1996+ cache [key ] = cached
1997+ # Keep cloned reachable so its id() is not reused by a later clone.
1998+ manager ._options_snapshot_keepalive .append (cloned )
1999+ return {"platform" : cached [0 ], "other_options" : cached [1 ]}
19862000
19872001
19882002def find_cache_meta (
0 commit comments