diff options
Diffstat (limited to 'mesonbuild/compilers/compilers.py')
-rw-r--r-- | mesonbuild/compilers/compilers.py | 105 |
1 files changed, 68 insertions, 37 deletions
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 3d75811..4b286fe 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -14,6 +14,7 @@ import contextlib, os.path, re, tempfile import collections.abc +from collections import deque import itertools import typing as T from functools import lru_cache @@ -138,11 +139,15 @@ def is_llvm_ir(fname): fname = fname.fname return fname.split('.')[-1] == 'll' +@lru_cache(maxsize=None) +def cached_by_name(fname): + suffix = fname.split('.')[-1] + return suffix in obj_suffixes + def is_object(fname): if hasattr(fname, 'fname'): fname = fname.fname - suffix = fname.split('.')[-1] - return suffix in obj_suffixes + return cached_by_name(fname) def is_library(fname): if hasattr(fname, 'fname'): @@ -462,9 +467,47 @@ class CompilerArgs(collections.abc.MutableSequence): iterable: T.Optional[T.Iterable[str]] = None): self.compiler = compiler self.__container = list(iterable) if iterable is not None else [] # type: T.List[str] - self.__seen_args = set() - for arg in self.__container: - self.__seen_args.add(arg) + self.pre = deque() + self.post = deque() + + # Flush the saved pre and post list into the __container list + # + # This correctly deduplicates the entries after _can_dedup definition + # Note: This function is designed to work without delete operations, as deletions are worsening the performance a lot. + def flush_pre_post(self): + pre_flush = deque() + pre_flush_set = set() + post_flush = deque() + post_flush_set = set() + + #The two lists are here walked from the front to the back, in order to not need removals for deduplication + for a in reversed(self.pre): + dedup = self._can_dedup(a) + if a not in pre_flush_set: + pre_flush.appendleft(a) + if dedup == 2: + pre_flush_set.add(a) + for a in reversed(self.post): + dedup = self._can_dedup(a) + if a not in post_flush_set: + post_flush.appendleft(a) + if dedup == 2: + post_flush_set.add(a) + + #pre and post will overwrite every element that is in the container + #only copy over args that are in __container but not in the post flush or pre flush set + + for a in self.__container: + if a not in post_flush_set and a not in pre_flush_set: + pre_flush.append(a) + + self.__container = list(pre_flush) + list(post_flush) + self.pre.clear() + self.post.clear() + + def __iter__(self): + self.flush_pre_post() + return iter(self.__container); @T.overload # noqa: F811 def __getitem__(self, index: int) -> str: # noqa: F811 @@ -475,6 +518,7 @@ class CompilerArgs(collections.abc.MutableSequence): pass def __getitem__(self, index): # noqa: F811 + self.flush_pre_post() return self.__container[index] @T.overload # noqa: F811 @@ -486,24 +530,22 @@ class CompilerArgs(collections.abc.MutableSequence): pass def __setitem__(self, index, value) -> None: # noqa: F811 + self.flush_pre_post() self.__container[index] = value - for v in value: - self.__seen_args.add(v) def __delitem__(self, index: T.Union[int, slice]) -> None: - value = self.__container[index] + self.flush_pre_post() del self.__container[index] - if value in self.__seen_args and value in self.__container: # this is also honoring that you can have duplicated entries - self.__seen_args.remove(value) def __len__(self) -> int: - return len(self.__container) + return len(self.__container) + len(self.pre) + len(self.post) def insert(self, index: int, value: str) -> None: + self.flush_pre_post() self.__container.insert(index, value) - self.__seen_args.add(value) def copy(self) -> 'CompilerArgs': + self.flush_pre_post() return CompilerArgs(self.compiler, self.__container.copy()) @classmethod @@ -576,6 +618,7 @@ class CompilerArgs(collections.abc.MutableSequence): # between static libraries, and for recursively searching for symbols # needed by static libraries that are provided by object files or # shared libraries. + self.flush_pre_post() if copy: new = self.copy() else: @@ -635,11 +678,11 @@ class CompilerArgs(collections.abc.MutableSequence): for absolute paths to libraries, etc, which can always be de-duped safely. ''' + self.flush_pre_post() if os.path.isabs(arg): self.append(arg) else: self.__container.append(arg) - self.__seen_args.add(arg) def extend_direct(self, iterable: T.Iterable[str]) -> None: ''' @@ -647,6 +690,7 @@ class CompilerArgs(collections.abc.MutableSequence): reordering or de-dup except for absolute paths where the order of include search directories is not relevant ''' + self.flush_pre_post() for elem in iterable: self.append_direct(elem) @@ -662,6 +706,7 @@ class CompilerArgs(collections.abc.MutableSequence): self.extend_direct(lflags) def __add__(self, args: T.Iterable[str]) -> 'CompilerArgs': + self.flush_pre_post() new = self.copy() new += args return new @@ -671,9 +716,7 @@ class CompilerArgs(collections.abc.MutableSequence): Add two CompilerArgs while taking into account overriding of arguments and while preserving the order of arguments as much as possible ''' - this_round_added = set() # a dict that contains a value, when the value was added this round - pre = [] # type: T.List[str] - post = [] # type: T.List[str] + tmp_pre = deque() if not isinstance(args, collections.abc.Iterable): raise TypeError('can only concatenate Iterable[str] (not "{}") to CompilerArgs'.format(args)) for arg in args: @@ -683,37 +726,24 @@ class CompilerArgs(collections.abc.MutableSequence): dedup = self._can_dedup(arg) if dedup == 1: # Argument already exists and adding a new instance is useless - if arg in self.__seen_args or arg in pre or arg in post: + if arg in self.__container or arg in self.pre or arg in self.post: continue - should_prepend = self._should_prepend(arg) - if dedup == 2: - # Remove all previous occurrences of the arg and add it anew - if arg in self.__seen_args and arg not in this_round_added: # if __seen_args contains arg as well as this_round_added, then its not yet part in self. - self.remove(arg) - if should_prepend: - if arg in pre: - pre.remove(arg) - else: - if arg in post: - post.remove(arg) - if should_prepend: - pre.append(arg) + if self._should_prepend(arg): + tmp_pre.appendleft(arg) else: - post.append(arg) - self.__seen_args.add(arg) - this_round_added.add(arg) - # Insert at the beginning - self[:0] = pre - # Append to the end - self.__container += post + self.post.append(arg) + self.pre.extendleft(tmp_pre) + #pre and post is going to be merged later before a iter call return self def __radd__(self, args: T.Iterable[str]): + self.flush_pre_post() new = CompilerArgs(self.compiler, args) new += self return new def __eq__(self, other: T.Any) -> T.Union[bool, type(NotImplemented)]: + self.flush_pre_post() # Only allow equality checks against other CompilerArgs and lists instances if isinstance(other, CompilerArgs): return self.compiler == other.compiler and self.__container == other.__container @@ -728,6 +758,7 @@ class CompilerArgs(collections.abc.MutableSequence): self.__iadd__(args) def __repr__(self) -> str: + self.flush_pre_post() return 'CompilerArgs({!r}, {!r})'.format(self.compiler, self.__container) class Compiler: |