arglist: Split the C/C++ specifics parts into a subclass for CLike

This means that we don't need work arounds for D-like compilers, as the
special c-like hanlding wont be used for D compilers.
pull/7369/head
Dylan Baker 5 years ago
parent 93c3ec7e2d
commit 4f6bd29ac9
  1. 93
      mesonbuild/arglist.py
  2. 56
      mesonbuild/compilers/mixins/clike.py

@ -31,7 +31,6 @@ UNIXY_COMPILER_INTERNAL_LIBS = ['m', 'c', 'pthread', 'dl', 'rt'] # type: T.List
# execinfo is a compiler lib on FreeBSD and NetBSD # execinfo is a compiler lib on FreeBSD and NetBSD
if mesonlib.is_freebsd() or mesonlib.is_netbsd(): if mesonlib.is_freebsd() or mesonlib.is_netbsd():
UNIXY_COMPILER_INTERNAL_LIBS.append('execinfo') UNIXY_COMPILER_INTERNAL_LIBS.append('execinfo')
SOREGEX = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$')
class Dedup(enum.Enum): class Dedup(enum.Enum):
@ -112,11 +111,11 @@ class CompilerArgs(collections.abc.MutableSequence):
def __init__(self, compiler: T.Union['Compiler', 'StaticLinker'], def __init__(self, compiler: T.Union['Compiler', 'StaticLinker'],
iterable: T.Optional[T.Iterable[str]] = None): iterable: T.Optional[T.Iterable[str]] = None):
self.compiler = compiler self.compiler = compiler
self.__container = list(iterable) if iterable is not None else [] # type: T.List[str] self._container = list(iterable) if iterable is not None else [] # type: T.List[str]
self.pre = collections.deque() # type: T.Deque[str] self.pre = collections.deque() # type: T.Deque[str]
self.post = collections.deque() # type: T.Deque[str] self.post = collections.deque() # type: T.Deque[str]
# Flush the saved pre and post list into the __container list # Flush the saved pre and post list into the _container list
# #
# This correctly deduplicates the entries after _can_dedup definition # 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. # Note: This function is designed to work without delete operations, as deletions are worsening the performance a lot.
@ -141,19 +140,19 @@ class CompilerArgs(collections.abc.MutableSequence):
post_flush_set.add(a) post_flush_set.add(a)
#pre and post will overwrite every element that is in the container #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 #only copy over args that are in _container but not in the post flush or pre flush set
for a in self.__container: for a in self._container:
if a not in post_flush_set and a not in pre_flush_set: if a not in post_flush_set and a not in pre_flush_set:
pre_flush.append(a) pre_flush.append(a)
self.__container = list(pre_flush) + list(post_flush) self._container = list(pre_flush) + list(post_flush)
self.pre.clear() self.pre.clear()
self.post.clear() self.post.clear()
def __iter__(self) -> T.Iterator[str]: def __iter__(self) -> T.Iterator[str]:
self.flush_pre_post() self.flush_pre_post()
return iter(self.__container) return iter(self._container)
@T.overload # noqa: F811 @T.overload # noqa: F811
def __getitem__(self, index: int) -> str: # noqa: F811 def __getitem__(self, index: int) -> str: # noqa: F811
@ -165,7 +164,7 @@ class CompilerArgs(collections.abc.MutableSequence):
def __getitem__(self, index): # noqa: F811 def __getitem__(self, index): # noqa: F811
self.flush_pre_post() self.flush_pre_post()
return self.__container[index] return self._container[index]
@T.overload # noqa: F811 @T.overload # noqa: F811
def __setitem__(self, index: int, value: str) -> None: # noqa: F811 def __setitem__(self, index: int, value: str) -> None: # noqa: F811
@ -177,22 +176,22 @@ class CompilerArgs(collections.abc.MutableSequence):
def __setitem__(self, index, value) -> None: # noqa: F811 def __setitem__(self, index, value) -> None: # noqa: F811
self.flush_pre_post() self.flush_pre_post()
self.__container[index] = value self._container[index] = value
def __delitem__(self, index: T.Union[int, slice]) -> None: def __delitem__(self, index: T.Union[int, slice]) -> None:
self.flush_pre_post() self.flush_pre_post()
del self.__container[index] del self._container[index]
def __len__(self) -> int: def __len__(self) -> int:
return len(self.__container) + len(self.pre) + len(self.post) return len(self._container) + len(self.pre) + len(self.post)
def insert(self, index: int, value: str) -> None: def insert(self, index: int, value: str) -> None:
self.flush_pre_post() self.flush_pre_post()
self.__container.insert(index, value) self._container.insert(index, value)
def copy(self) -> 'CompilerArgs': def copy(self) -> 'CompilerArgs':
self.flush_pre_post() self.flush_pre_post()
return type(self)(self.compiler, self.__container.copy()) return type(self)(self.compiler, self._container.copy())
@classmethod @classmethod
@lru_cache(maxsize=None) @lru_cache(maxsize=None)
@ -231,16 +230,7 @@ class CompilerArgs(collections.abc.MutableSequence):
def _should_prepend(cls, arg: str) -> bool: def _should_prepend(cls, arg: str) -> bool:
return arg.startswith(cls.prepend_prefixes) return arg.startswith(cls.prepend_prefixes)
def need_to_split_linker_args(self) -> bool:
# XXX: gross
from .compilers import Compiler
return isinstance(self.compiler, Compiler) and self.compiler.get_language() == 'd'
def to_native(self, copy: bool = False) -> T.List[str]: def to_native(self, copy: bool = False) -> T.List[str]:
# XXX: gross
from .compilers import Compiler
from .linkers import GnuLikeDynamicLinkerMixin, SolarisDynamicLinker
# Check if we need to add --start/end-group for circular dependencies # Check if we need to add --start/end-group for circular dependencies
# between static libraries, and for recursively searching for symbols # between static libraries, and for recursively searching for symbols
# needed by static libraries that are provided by object files or # needed by static libraries that are provided by object files or
@ -250,54 +240,7 @@ class CompilerArgs(collections.abc.MutableSequence):
new = self.copy() new = self.copy()
else: else:
new = self new = self
# To proxy these arguments with D you need to split the return self.compiler.unix_args_to_native(new._container)
# arguments, thus you get `-L=-soname -L=lib.so` we don't
# want to put the lib in a link -roup
split_linker_args = self.need_to_split_linker_args()
# This covers all ld.bfd, ld.gold, ld.gold, and xild on Linux, which
# all act like (or are) gnu ld
# TODO: this could probably be added to the DynamicLinker instead
if (isinstance(self.compiler, Compiler) and
self.compiler.linker is not None and
isinstance(self.compiler.linker, (GnuLikeDynamicLinkerMixin, SolarisDynamicLinker))):
group_start = -1
group_end = -1
is_soname = False
for i, each in enumerate(new):
if is_soname:
is_soname = False
continue
elif split_linker_args and '-soname' in each:
is_soname = True
continue
if not each.startswith(('-Wl,-l', '-l')) and not each.endswith('.a') and \
not SOREGEX.match(each):
continue
group_end = i
if group_start < 0:
# First occurrence of a library
group_start = i
if group_start >= 0:
# Last occurrence of a library
new.insert(group_end + 1, '-Wl,--end-group')
new.insert(group_start, '-Wl,--start-group')
# Remove system/default include paths added with -isystem
if hasattr(self.compiler, 'get_default_include_dirs'):
default_dirs = self.compiler.get_default_include_dirs()
bad_idx_list = [] # type: T.List[int]
for i, each in enumerate(new):
# Remove the -isystem and the path if the path is a default path
if (each == '-isystem' and
i < (len(new) - 1) and
new[i + 1] in default_dirs):
bad_idx_list += [i, i + 1]
elif each.startswith('-isystem=') and each[9:] in default_dirs:
bad_idx_list += [i]
elif each.startswith('-isystem') and each[8:] in default_dirs:
bad_idx_list += [i]
for i in reversed(bad_idx_list):
new.pop(i)
return self.compiler.unix_args_to_native(new.__container)
def append_direct(self, arg: str) -> None: def append_direct(self, arg: str) -> None:
''' '''
@ -309,7 +252,7 @@ class CompilerArgs(collections.abc.MutableSequence):
if os.path.isabs(arg): if os.path.isabs(arg):
self.append(arg) self.append(arg)
else: else:
self.__container.append(arg) self._container.append(arg)
def extend_direct(self, iterable: T.Iterable[str]) -> None: def extend_direct(self, iterable: T.Iterable[str]) -> None:
''' '''
@ -353,7 +296,7 @@ class CompilerArgs(collections.abc.MutableSequence):
dedup = self._can_dedup(arg) dedup = self._can_dedup(arg)
if dedup is Dedup.UNIQUE: if dedup is Dedup.UNIQUE:
# Argument already exists and adding a new instance is useless # Argument already exists and adding a new instance is useless
if arg in self.__container or arg in self.pre or arg in self.post: if arg in self._container or arg in self.pre or arg in self.post:
continue continue
if self._should_prepend(arg): if self._should_prepend(arg):
tmp_pre.appendleft(arg) tmp_pre.appendleft(arg)
@ -373,9 +316,9 @@ class CompilerArgs(collections.abc.MutableSequence):
self.flush_pre_post() self.flush_pre_post()
# Only allow equality checks against other CompilerArgs and lists instances # Only allow equality checks against other CompilerArgs and lists instances
if isinstance(other, CompilerArgs): if isinstance(other, CompilerArgs):
return self.compiler == other.compiler and self.__container == other.__container return self.compiler == other.compiler and self._container == other._container
elif isinstance(other, list): elif isinstance(other, list):
return self.__container == other return self._container == other
return NotImplemented return NotImplemented
def append(self, arg: str) -> None: def append(self, arg: str) -> None:
@ -386,4 +329,4 @@ class CompilerArgs(collections.abc.MutableSequence):
def __repr__(self) -> str: def __repr__(self) -> str:
self.flush_pre_post() self.flush_pre_post()
return '{}({!r}, {!r})'.format(self.__name__, self.compiler, self.__container) return 'CompilerArgs({!r}, {!r})'.format(self.compiler, self._container)

@ -32,7 +32,7 @@ from pathlib import Path
from ... import arglist from ... import arglist
from ... import mesonlib from ... import mesonlib
from ... import mlog from ... import mlog
from ...arglist import CompilerArgs from ...linkers import GnuLikeDynamicLinkerMixin, SolarisDynamicLinker
from ...mesonlib import LibType from ...mesonlib import LibType
from .. import compilers from .. import compilers
from .visualstudio import VisualStudioLikeCompiler from .visualstudio import VisualStudioLikeCompiler
@ -40,8 +40,9 @@ from .visualstudio import VisualStudioLikeCompiler
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from ...environment import Environment from ...environment import Environment
SOREGEX = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$')
class CLikeCompilerArgs(CompilerArgs): class CLikeCompilerArgs(arglist.CompilerArgs):
prepend_prefixes = ('-I', '-L') prepend_prefixes = ('-I', '-L')
dedup2_prefixes = ('-I', '-isystem', '-L', '-D', '-U') dedup2_prefixes = ('-I', '-isystem', '-L', '-D', '-U')
@ -49,9 +50,58 @@ class CLikeCompilerArgs(CompilerArgs):
# https://github.com/mesonbuild/meson/pull/4593#pullrequestreview-182016038 # https://github.com/mesonbuild/meson/pull/4593#pullrequestreview-182016038
dedup1_prefixes = ('-l', '-Wl,-l', '-Wl,--export-dynamic') dedup1_prefixes = ('-l', '-Wl,-l', '-Wl,--export-dynamic')
dedup1_suffixes = ('.lib', '.dll', '.so', '.dylib', '.a') dedup1_suffixes = ('.lib', '.dll', '.so', '.dylib', '.a')
dedup1_args = ('-c', '-S', '-E', '-pipe', '-pthread') dedup1_args = ('-c', '-S', '-E', '-pipe', '-pthread')
def to_native(self, copy: bool = False) -> T.List[str]:
# Check if we need to add --start/end-group for circular dependencies
# 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:
new = self
# This covers all ld.bfd, ld.gold, ld.gold, and xild on Linux, which
# all act like (or are) gnu ld
# TODO: this could probably be added to the DynamicLinker instead
if isinstance(self.compiler.linker, (GnuLikeDynamicLinkerMixin, SolarisDynamicLinker)):
group_start = -1
group_end = -1
for i, each in enumerate(new):
if not each.startswith(('-Wl,-l', '-l')) and not each.endswith('.a') and \
not SOREGEX.match(each):
continue
group_end = i
if group_start < 0:
# First occurrence of a library
group_start = i
if group_start >= 0:
# Last occurrence of a library
new.insert(group_end + 1, '-Wl,--end-group')
new.insert(group_start, '-Wl,--start-group')
# Remove system/default include paths added with -isystem
if hasattr(self.compiler, 'get_default_include_dirs'):
default_dirs = self.compiler.get_default_include_dirs()
bad_idx_list = [] # type: T.List[int]
for i, each in enumerate(new):
# Remove the -isystem and the path if the path is a default path
if (each == '-isystem' and
i < (len(new) - 1) and
new[i + 1] in default_dirs):
bad_idx_list += [i, i + 1]
elif each.startswith('-isystem=') and each[9:] in default_dirs:
bad_idx_list += [i]
elif each.startswith('-isystem') and each[8:] in default_dirs:
bad_idx_list += [i]
for i in reversed(bad_idx_list):
new.pop(i)
return self.compiler.unix_args_to_native(new._container)
def __repr__(self) -> str:
self.flush_pre_post()
return 'CLikeCompilerArgs({!r}, {!r})'.format(self.compiler, self._container)
class CLikeCompiler: class CLikeCompiler:

Loading…
Cancel
Save