aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan Baker <dylan@pnwbakers.com>2020-06-11 12:44:53 -0700
committerDylan Baker <dylan@pnwbakers.com>2020-06-22 12:06:10 -0700
commit93c3ec7e2dd6d425baff5fd80e5a46c88d152cb0 (patch)
treed5913f089b2a69de191e5c67b1e8dc8010742b6d
parent9d0ad66c29fccd2ff72c2b40da02cdb2b03ccba6 (diff)
downloadmeson-93c3ec7e2dd6d425baff5fd80e5a46c88d152cb0.zip
meson-93c3ec7e2dd6d425baff5fd80e5a46c88d152cb0.tar.gz
meson-93c3ec7e2dd6d425baff5fd80e5a46c88d152cb0.tar.bz2
compilers: Return CompilerArgs from compiler instance
Since the CompileArgs class already needs to know about the compiler, and we really need at least per-lanaguage if not per-compiler CompilerArgs classes, let's get the CompilerArgs instance from the compiler using a method.
-rw-r--r--mesonbuild/arglist.py43
-rw-r--r--mesonbuild/backend/backends.py3
-rw-r--r--mesonbuild/backend/ninjabackend.py10
-rw-r--r--mesonbuild/backend/vs2010backend.py9
-rw-r--r--mesonbuild/compilers/compilers.py9
-rw-r--r--mesonbuild/compilers/d.py3
-rw-r--r--mesonbuild/compilers/mixins/clike.py18
-rw-r--r--mesonbuild/linkers.py4
-rwxr-xr-xrun_unittests.py20
9 files changed, 63 insertions, 56 deletions
diff --git a/mesonbuild/arglist.py b/mesonbuild/arglist.py
index ac97a41..dcc670b 100644
--- a/mesonbuild/arglist.py
+++ b/mesonbuild/arglist.py
@@ -21,9 +21,6 @@ import re
import typing as T
from . import mesonlib
-from .linkers import (
- GnuLikeDynamicLinkerMixin, LinkerEnvVarsMixin, SolarisDynamicLinker,
-)
if T.TYPE_CHECKING:
from .linkers import StaticLinker
@@ -36,6 +33,7 @@ if mesonlib.is_freebsd() or mesonlib.is_netbsd():
UNIXY_COMPILER_INTERNAL_LIBS.append('execinfo')
SOREGEX = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$')
+
class Dedup(enum.Enum):
"""What kind of deduplication can be done to compiler args.
@@ -88,29 +86,28 @@ class CompilerArgs(collections.abc.MutableSequence):
['-Ifoo', '-Ibar', '-Ifez', '-Ibaz', '-Werror']
'''
- # NOTE: currently this class is only for C-like compilers, but it can be
- # extended to other languages easily. Just move the following to the
- # compiler class and initialize when self.compiler is set.
-
# Arg prefixes that override by prepending instead of appending
- prepend_prefixes = ('-I', '-L')
+ prepend_prefixes = () # type: T.Tuple[str, ...]
+
# Arg prefixes and args that must be de-duped by returning 2
- dedup2_prefixes = ('-I', '-isystem', '-L', '-D', '-U')
- dedup2_suffixes = ()
- dedup2_args = ()
+ dedup2_prefixes = () # type: T.Tuple[str, ...]
+ dedup2_suffixes = () # type: T.Tuple[str, ...]
+ dedup2_args = () # type: T.Tuple[str, ...]
+
# Arg prefixes and args that must be de-duped by returning 1
#
# NOTE: not thorough. A list of potential corner cases can be found in
# https://github.com/mesonbuild/meson/pull/4593#pullrequestreview-182016038
- dedup1_prefixes = ('-l', '-Wl,-l', '-Wl,--export-dynamic')
- dedup1_suffixes = ('.lib', '.dll', '.so', '.dylib', '.a')
+ dedup1_prefixes = () # type: T.Tuple[str, ...]
+ dedup1_suffixes = ('.lib', '.dll', '.so', '.dylib', '.a') # type: T.Tuple[str, ...]
# Match a .so of the form path/to/libfoo.so.0.1.0
# Only UNIX shared libraries require this. Others have a fixed extension.
dedup1_regex = re.compile(r'([\/\\]|\A)lib.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$')
- dedup1_args = ('-c', '-S', '-E', '-pipe', '-pthread')
+ dedup1_args = () # type: T.Tuple[str, ...]
# In generate_link() we add external libs without de-dup, but we must
# *always* de-dup these because they're special arguments to the linker
- always_dedup_args = tuple('-l' + lib for lib in UNIXY_COMPILER_INTERNAL_LIBS)
+ # TODO: these should probably move too
+ always_dedup_args = tuple('-l' + lib for lib in UNIXY_COMPILER_INTERNAL_LIBS) # type : T.Tuple[str, ...]
def __init__(self, compiler: T.Union['Compiler', 'StaticLinker'],
iterable: T.Optional[T.Iterable[str]] = None):
@@ -195,7 +192,7 @@ class CompilerArgs(collections.abc.MutableSequence):
def copy(self) -> 'CompilerArgs':
self.flush_pre_post()
- return CompilerArgs(self.compiler, self.__container.copy())
+ return type(self)(self.compiler, self.__container.copy())
@classmethod
@lru_cache(maxsize=None)
@@ -218,15 +215,6 @@ class CompilerArgs(collections.abc.MutableSequence):
# both of which are invalid.
if arg in cls.dedup2_prefixes:
return Dedup.NO_DEDUP
- if arg.startswith('-L='):
- # DMD and LDC proxy all linker arguments using -L=; in conjunction
- # with ld64 on macOS this can lead to command line arguments such
- # as: `-L=-compatibility_version -L=0 -L=current_version -L=0`.
- # These cannot be combined, ld64 insists they must be passed with
- # spaces and quoting does not work. if we deduplicate these then
- # one of the -L=0 arguments will be removed and the version
- # argument will consume the next argument instead.
- return Dedup.NO_DEDUP
if arg in cls.dedup2_args or \
arg.startswith(cls.dedup2_prefixes) or \
arg.endswith(cls.dedup2_suffixes):
@@ -251,6 +239,7 @@ class CompilerArgs(collections.abc.MutableSequence):
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
# between static libraries, and for recursively searching for symbols
@@ -376,7 +365,7 @@ class CompilerArgs(collections.abc.MutableSequence):
def __radd__(self, args: T.Iterable[str]) -> 'CompilerArgs':
self.flush_pre_post()
- new = CompilerArgs(self.compiler, args)
+ new = type(self)(self.compiler, args)
new += self
return new
@@ -397,4 +386,4 @@ class CompilerArgs(collections.abc.MutableSequence):
def __repr__(self) -> str:
self.flush_pre_post()
- return 'CompilerArgs({!r}, {!r})'.format(self.compiler, self.__container)
+ return '{}({!r}, {!r})'.format(self.__name__, self.compiler, self.__container)
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index bca0304..cfd3a39 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -28,7 +28,6 @@ from .. import build
from .. import dependencies
from .. import mesonlib
from .. import mlog
-from ..arglist import CompilerArgs
from ..mesonlib import (
File, MachineChoice, MesonException, OrderedSet, OptionOverrideProxy,
classify_unity_sources, unholder
@@ -626,7 +625,7 @@ class Backend:
# Create an empty commands list, and start adding arguments from
# various sources in the order in which they must override each other
# starting from hard-coded defaults followed by build options and so on.
- commands = CompilerArgs(compiler)
+ commands = compiler.compiler_args()
copt_proxy = self.get_compiler_options_for_target(target)[compiler.language]
# First, the trivial ones that are impossible to override.
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index b326e3b..62bda1a 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -1202,7 +1202,7 @@ int dummy;
compiler = target.compilers['cs']
rel_srcs = [os.path.normpath(s.rel_to_builddir(self.build_to_src)) for s in src_list]
deps = []
- commands = CompilerArgs(compiler, target.extra_args.get('cs', []))
+ commands = compiler.compiler_args(target.extra_args.get('cs', []))
commands += compiler.get_buildtype_args(buildtype)
commands += compiler.get_optimization_args(self.get_option_for_target('optimization', target))
commands += compiler.get_debug_args(self.get_option_for_target('debug', target))
@@ -2156,7 +2156,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
def generate_llvm_ir_compile(self, target, src):
compiler = get_compiler_for_source(target.compilers.values(), src)
- commands = CompilerArgs(compiler)
+ commands = compiler.compiler_args()
# Compiler args for compiling this target
commands += compilers.get_base_compile_args(self.environment.coredata.base_options,
compiler)
@@ -2245,7 +2245,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
base_proxy = self.get_base_options_for_target(target)
# Create an empty commands list, and start adding arguments from
# various sources in the order in which they must override each other
- commands = CompilerArgs(compiler)
+ commands = compiler.compiler_args()
# Start with symbol visibility.
commands += compiler.gnu_symbol_visibility_args(target.gnu_symbol_visibility)
# Add compiler args for compiling this target derived from 'base' build
@@ -2325,7 +2325,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
compiler = get_compiler_for_source(target.compilers.values(), src)
commands = self._generate_single_compile(target, compiler, is_generated)
- commands = CompilerArgs(commands.compiler, commands)
+ commands = commands.compiler.compiler_args(commands)
# Create introspection information
if is_generated is False:
@@ -2674,7 +2674,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
#
# Once all the linker options have been passed, we will start passing
# libraries and library paths from internal and external sources.
- commands = CompilerArgs(linker)
+ commands = linker.compiler_args()
# First, the trivial ones that are impossible to override.
#
# Add linker args for linking this target derived from 'base' build
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index bd77132..f282d02 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -26,7 +26,6 @@ from .. import build
from .. import dependencies
from .. import mlog
from .. import compilers
-from ..arglist import CompilerArgs
from ..interpreter import Interpreter
from ..mesonlib import (
MesonException, File, python_command, replace_if_different
@@ -899,9 +898,9 @@ class Vs2010Backend(backends.Backend):
#
# file_args is also later split out into defines and include_dirs in
# case someone passed those in there
- file_args = dict((lang, CompilerArgs(comp)) for lang, comp in target.compilers.items())
- file_defines = dict((lang, []) for lang in target.compilers)
- file_inc_dirs = dict((lang, []) for lang in target.compilers)
+ file_args = {l: c.compiler_args() for l, c in target.compilers.items()}
+ file_defines = {l: [] for l in target.compilers}
+ file_inc_dirs = {l: [] for l in target.compilers}
# The order in which these compile args are added must match
# generate_single_compile() and generate_basic_compiler_args()
for l, comp in target.compilers.items():
@@ -1084,7 +1083,7 @@ class Vs2010Backend(backends.Backend):
# Linker options
link = ET.SubElement(compiles, 'Link')
- extra_link_args = CompilerArgs(compiler)
+ extra_link_args = compiler.compiler_args()
# FIXME: Can these buildtype linker args be added as tags in the
# vcxproj file (similar to buildtype compiler args) instead of in
# AdditionalOptions?
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index bf66982..8ecb972 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import abc
import contextlib, os.path, re, tempfile
import itertools
import typing as T
@@ -401,7 +402,7 @@ class RunResult:
self.stderr = stderr
-class Compiler:
+class Compiler(metaclass=abc.ABCMeta):
# Libraries to ignore in find_library() since they are provided by the
# compiler or the C library. Currently only used for MSVC.
ignore_libs = ()
@@ -624,6 +625,10 @@ class Compiler:
args += self.get_preprocess_only_args()
return args
+ def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> CompilerArgs:
+ """Return an appropriate CompilerArgs instance for this class."""
+ return CompilerArgs(self, args)
+
@contextlib.contextmanager
def compile(self, code: str, extra_args: list = None, *, mode: str = 'link', want_output: bool = False, temp_dir: str = None):
if extra_args is None:
@@ -642,7 +647,7 @@ class Compiler:
srcname = code.fname
# Construct the compiler command-line
- commands = CompilerArgs(self)
+ commands = self.compiler_args()
commands.append(srcname)
# Preprocess mode outputs to stdout, so no output args
if mode != 'preprocess':
diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py
index 924ac90..32919e4 100644
--- a/mesonbuild/compilers/d.py
+++ b/mesonbuild/compilers/d.py
@@ -19,7 +19,6 @@ from ..mesonlib import (
EnvironmentException, MachineChoice, version_compare,
)
-from ..arglist import CompilerArgs
from .compilers import (
d_dmd_buildtype_args,
d_gdc_buildtype_args,
@@ -582,7 +581,7 @@ class DCompiler(Compiler):
elif not isinstance(dependencies, list):
dependencies = [dependencies]
# Collect compiler arguments
- args = CompilerArgs(self)
+ args = self.compiler_args()
for d in dependencies:
# Add compile flags needed by dependencies
args += d.get_compile_args()
diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py
index b32ac29..455fbe2 100644
--- a/mesonbuild/compilers/mixins/clike.py
+++ b/mesonbuild/compilers/mixins/clike.py
@@ -32,6 +32,7 @@ from pathlib import Path
from ... import arglist
from ... import mesonlib
from ... import mlog
+from ...arglist import CompilerArgs
from ...mesonlib import LibType
from .. import compilers
from .visualstudio import VisualStudioLikeCompiler
@@ -40,6 +41,18 @@ if T.TYPE_CHECKING:
from ...environment import Environment
+class CLikeCompilerArgs(CompilerArgs):
+ prepend_prefixes = ('-I', '-L')
+ dedup2_prefixes = ('-I', '-isystem', '-L', '-D', '-U')
+
+ # NOTE: not thorough. A list of potential corner cases can be found in
+ # https://github.com/mesonbuild/meson/pull/4593#pullrequestreview-182016038
+ dedup1_prefixes = ('-l', '-Wl,-l', '-Wl,--export-dynamic')
+ dedup1_suffixes = ('.lib', '.dll', '.so', '.dylib', '.a')
+
+ dedup1_args = ('-c', '-S', '-E', '-pipe', '-pthread')
+
+
class CLikeCompiler:
"""Shared bits for the C and CPP Compilers."""
@@ -62,6 +75,9 @@ class CLikeCompiler:
else:
self.exe_wrapper = exe_wrapper.get_command()
+ def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> CLikeCompilerArgs:
+ return CLikeCompilerArgs(self, args)
+
def needs_static_linker(self):
return True # When compiling static libraries, so yes.
@@ -339,7 +355,7 @@ class CLikeCompiler:
elif not isinstance(dependencies, list):
dependencies = [dependencies]
# Collect compiler arguments
- cargs = arglist.CompilerArgs(self)
+ cargs = self.compiler_args()
largs = []
for d in dependencies:
# Add compile flags needed by dependencies
diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py
index bb3229d..805bbc7 100644
--- a/mesonbuild/linkers.py
+++ b/mesonbuild/linkers.py
@@ -17,6 +17,7 @@ import os
import typing as T
from . import mesonlib
+from .arglist import CompilerArgs
from .envconfig import get_env_var
if T.TYPE_CHECKING:
@@ -29,6 +30,9 @@ class StaticLinker:
def __init__(self, exelist: T.List[str]):
self.exelist = exelist
+ def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> CompilerArgs:
+ return CompilerArgs(self, args)
+
def can_linker_accept_rsp(self) -> bool:
"""
Determines whether the linker can accept arguments using the @rsp syntax.
diff --git a/run_unittests.py b/run_unittests.py
index b1ad965..72ca809 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -358,9 +358,8 @@ class InternalTests(unittest.TestCase):
stat.S_IRGRP | stat.S_IXGRP)
def test_compiler_args_class_none_flush(self):
- cargsfunc = mesonbuild.arglist.CompilerArgs
cc = mesonbuild.compilers.CCompiler([], 'fake', False, MachineChoice.HOST, mock.Mock())
- a = cargsfunc(cc, ['-I.'])
+ a = cc.compiler_args(['-I.'])
#first we are checking if the tree construction deduplicates the correct -I argument
a += ['-I..']
a += ['-I./tests/']
@@ -377,16 +376,15 @@ class InternalTests(unittest.TestCase):
def test_compiler_args_class(self):
- cargsfunc = mesonbuild.arglist.CompilerArgs
cc = mesonbuild.compilers.CCompiler([], 'fake', False, MachineChoice.HOST, mock.Mock())
# Test that empty initialization works
- a = cargsfunc(cc)
+ a = cc.compiler_args()
self.assertEqual(a, [])
# Test that list initialization works
- a = cargsfunc(cc, ['-I.', '-I..'])
+ a = cc.compiler_args(['-I.', '-I..'])
self.assertEqual(a, ['-I.', '-I..'])
# Test that there is no de-dup on initialization
- self.assertEqual(cargsfunc(cc, ['-I.', '-I.']), ['-I.', '-I.'])
+ self.assertEqual(cc.compiler_args(['-I.', '-I.']), ['-I.', '-I.'])
## Test that appending works
a.append('-I..')
@@ -432,7 +430,7 @@ class InternalTests(unittest.TestCase):
self.assertEqual(a, ['-Ibar', '-Ifoo', '-Ibaz', '-I..', '-I.', '-Ldir', '-Lbah', '-Werror', '-O3', '-O2', '-Wall'])
## Test that adding libraries works
- l = cargsfunc(cc, ['-Lfoodir', '-lfoo'])
+ l = cc.compiler_args(['-Lfoodir', '-lfoo'])
self.assertEqual(l, ['-Lfoodir', '-lfoo'])
# Adding a library and a libpath appends both correctly
l += ['-Lbardir', '-lbar']
@@ -442,7 +440,7 @@ class InternalTests(unittest.TestCase):
self.assertEqual(l, ['-Lbardir', '-Lfoodir', '-lfoo', '-lbar'])
## Test that 'direct' append and extend works
- l = cargsfunc(cc, ['-Lfoodir', '-lfoo'])
+ l = cc.compiler_args(['-Lfoodir', '-lfoo'])
self.assertEqual(l, ['-Lfoodir', '-lfoo'])
# Direct-adding a library and a libpath appends both correctly
l.extend_direct(['-Lbardir', '-lbar'])
@@ -458,14 +456,13 @@ class InternalTests(unittest.TestCase):
self.assertEqual(l, ['-Lfoodir', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a'])
def test_compiler_args_class_gnuld(self):
- cargsfunc = mesonbuild.arglist.CompilerArgs
## Test --start/end-group
linker = mesonbuild.linkers.GnuDynamicLinker([], MachineChoice.HOST, 'fake', '-Wl,', [])
gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', False, MachineChoice.HOST, mock.Mock(), linker=linker)
## Ensure that the fake compiler is never called by overriding the relevant function
gcc.get_default_include_dirs = lambda: ['/usr/include', '/usr/share/include', '/usr/local/include']
## Test that 'direct' append and extend works
- l = cargsfunc(gcc, ['-Lfoodir', '-lfoo'])
+ l = gcc.compiler_args(['-Lfoodir', '-lfoo'])
self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Wl,--end-group'])
# Direct-adding a library and a libpath appends both correctly
l.extend_direct(['-Lbardir', '-lbar'])
@@ -487,14 +484,13 @@ class InternalTests(unittest.TestCase):
self.assertEqual(l.to_native(copy=True), ['-Lfoo', '-Lfoodir', '-Wl,--start-group', '-lfoo', '-Lbardir', '-lbar', '-lbar', '/libbaz.a', '-Wl,--export-dynamic', '-Wl,-ldl', '-Wl,--end-group'])
def test_compiler_args_remove_system(self):
- cargsfunc = mesonbuild.arglist.CompilerArgs
## Test --start/end-group
linker = mesonbuild.linkers.GnuDynamicLinker([], MachineChoice.HOST, 'fake', '-Wl,', [])
gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', False, MachineChoice.HOST, mock.Mock(), linker=linker)
## Ensure that the fake compiler is never called by overriding the relevant function
gcc.get_default_include_dirs = lambda: ['/usr/include', '/usr/share/include', '/usr/local/include']
## Test that 'direct' append and extend works
- l = cargsfunc(gcc, ['-Lfoodir', '-lfoo'])
+ l = gcc.compiler_args(['-Lfoodir', '-lfoo'])
self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Wl,--end-group'])
## Test that to_native removes all system includes
l += ['-isystem/usr/include', '-isystem=/usr/share/include', '-DSOMETHING_IMPORTANT=1', '-isystem', '/usr/local/include']