aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/compilers/compilers.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/compilers/compilers.py')
-rw-r--r--mesonbuild/compilers/compilers.py105
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: