diff options
author | Dylan Baker <dylan@pnwbakers.com> | 2020-06-11 12:44:53 -0700 |
---|---|---|
committer | Dylan Baker <dylan@pnwbakers.com> | 2020-06-22 12:06:10 -0700 |
commit | 93c3ec7e2dd6d425baff5fd80e5a46c88d152cb0 (patch) | |
tree | d5913f089b2a69de191e5c67b1e8dc8010742b6d | |
parent | 9d0ad66c29fccd2ff72c2b40da02cdb2b03ccba6 (diff) | |
download | meson-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.py | 43 | ||||
-rw-r--r-- | mesonbuild/backend/backends.py | 3 | ||||
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 10 | ||||
-rw-r--r-- | mesonbuild/backend/vs2010backend.py | 9 | ||||
-rw-r--r-- | mesonbuild/compilers/compilers.py | 9 | ||||
-rw-r--r-- | mesonbuild/compilers/d.py | 3 | ||||
-rw-r--r-- | mesonbuild/compilers/mixins/clike.py | 18 | ||||
-rw-r--r-- | mesonbuild/linkers.py | 4 | ||||
-rwxr-xr-x | run_unittests.py | 20 |
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'] |