From ca34c7617036d5af1559767deba36038ecac101d Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Mon, 3 Jul 2023 12:28:00 -0400 Subject: linkers: reorganize code so that linker base classes always come first So that we can later reference them. --- mesonbuild/linkers/linkers.py | 399 +++++++++++++++++++++--------------------- 1 file changed, 200 insertions(+), 199 deletions(-) (limited to 'mesonbuild') diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index 8f413c8..8fb3656 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -109,6 +109,206 @@ class StaticLinker: raise EnvironmentException(f'{self.id} does not implement rsp format, this shouldn\'t be called') +class DynamicLinker(metaclass=abc.ABCMeta): + + """Base class for dynamic linkers.""" + + _BUILDTYPE_ARGS: T.Dict[str, T.List[str]] = { + 'plain': [], + 'debug': [], + 'debugoptimized': [], + 'release': [], + 'minsize': [], + 'custom': [], + } + + @abc.abstractproperty + def id(self) -> str: + pass + + def _apply_prefix(self, arg: T.Union[str, T.List[str]]) -> T.List[str]: + args = [arg] if isinstance(arg, str) else arg + if self.prefix_arg is None: + return args + elif isinstance(self.prefix_arg, str): + return [self.prefix_arg + arg for arg in args] + ret: T.List[str] = [] + for arg in args: + ret += self.prefix_arg + [arg] + return ret + + def __init__(self, exelist: T.List[str], + for_machine: mesonlib.MachineChoice, prefix_arg: T.Union[str, T.List[str]], + always_args: T.List[str], *, version: str = 'unknown version'): + self.exelist = exelist + self.for_machine = for_machine + self.version = version + self.prefix_arg = prefix_arg + self.always_args = always_args + self.machine: T.Optional[str] = None + + def __repr__(self) -> str: + return '<{}: v{} `{}`>'.format(type(self).__name__, self.version, ' '.join(self.exelist)) + + def get_id(self) -> str: + return self.id + + def get_version_string(self) -> str: + return f'({self.id} {self.version})' + + def get_exelist(self) -> T.List[str]: + return self.exelist.copy() + + def get_accepts_rsp(self) -> bool: + # rsp files are only used when building on Windows because we want to + # avoid issues with quoting and max argument length + return mesonlib.is_windows() + + def rsp_file_syntax(self) -> RSPFileSyntax: + """The format of the RSP file that this compiler supports. + + If `self.can_linker_accept_rsp()` returns True, then this needs to + be implemented + """ + return RSPFileSyntax.GCC + + def get_always_args(self) -> T.List[str]: + return self.always_args.copy() + + def get_lib_prefix(self) -> str: + return '' + + # XXX: is use_ldflags a compiler or a linker attribute? + + def get_option_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + return [] + + def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: + raise EnvironmentException(f'Language {self.id} does not support has_multi_link_arguments.') + + def get_debugfile_name(self, targetfile: str) -> T.Optional[str]: + '''Name of debug file written out (see below)''' + return None + + def get_debugfile_args(self, targetfile: str) -> T.List[str]: + """Some compilers (MSVC) write debug into a separate file. + + This method takes the target object path and returns a list of + commands to append to the linker invocation to control where that + file is written. + """ + return [] + + def get_std_shared_lib_args(self) -> T.List[str]: + return [] + + def get_std_shared_module_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + return self.get_std_shared_lib_args() + + def get_pie_args(self) -> T.List[str]: + # TODO: this really needs to take a boolean and return the args to + # disable pie, otherwise it only acts to enable pie if pie *isn't* the + # default. + raise EnvironmentException(f'Linker {self.id} does not support position-independent executable') + + def get_lto_args(self) -> T.List[str]: + return [] + + def get_thinlto_cache_args(self, path: str) -> T.List[str]: + return [] + + def sanitizer_args(self, value: str) -> T.List[str]: + return [] + + def get_buildtype_args(self, buildtype: str) -> T.List[str]: + # We can override these in children by just overriding the + # _BUILDTYPE_ARGS value. + return self._BUILDTYPE_ARGS[buildtype] + + def get_asneeded_args(self) -> T.List[str]: + return [] + + def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: + raise EnvironmentException( + f'Linker {self.id} does not support link_whole') + + def get_allow_undefined_args(self) -> T.List[str]: + raise EnvironmentException( + f'Linker {self.id} does not support allow undefined') + + @abc.abstractmethod + def get_output_args(self, outputname: str) -> T.List[str]: + pass + + def get_coverage_args(self) -> T.List[str]: + raise EnvironmentException(f"Linker {self.id} doesn't implement coverage data generation.") + + @abc.abstractmethod + def get_search_args(self, dirname: str) -> T.List[str]: + pass + + def export_dynamic_args(self, env: 'Environment') -> T.List[str]: + return [] + + def import_library_args(self, implibname: str) -> T.List[str]: + """The name of the outputted import library. + + This implementation is used only on Windows by compilers that use GNU ld + """ + return [] + + def thread_flags(self, env: 'Environment') -> T.List[str]: + return [] + + def no_undefined_args(self) -> T.List[str]: + """Arguments to error if there are any undefined symbols at link time. + + This is the inverse of get_allow_undefined_args(). + + TODO: A future cleanup might merge this and + get_allow_undefined_args() into a single method taking a + boolean + """ + return [] + + def fatal_warnings(self) -> T.List[str]: + """Arguments to make all warnings errors.""" + return [] + + def headerpad_args(self) -> T.List[str]: + # Only used by the Apple linker + return [] + + def get_gui_app_args(self, value: bool) -> T.List[str]: + # Only used by VisualStudioLikeLinkers + return [] + + def get_win_subsystem_args(self, value: str) -> T.List[str]: + # Only used if supported by the dynamic linker and + # only when targeting Windows + return [] + + def bitcode_args(self) -> T.List[str]: + raise MesonException('This linker does not support bitcode bundles') + + def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, + rpath_paths: T.Tuple[str, ...], build_rpath: str, + install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: + return ([], set()) + + def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, + suffix: str, soversion: str, darwin_versions: T.Tuple[str, str]) -> T.List[str]: + return [] + + def get_archive_name(self, filename: str) -> str: + #Only used by AIX. + return str() + + def get_command_to_archive_shlib(self) -> T.List[str]: + #Only used by AIX. + return [] + + class VisualStudioLikeLinker: always_args = ['/NOLOGO'] @@ -351,205 +551,6 @@ def evaluate_rpath(p: str, build_dir: str, from_dir: str) -> str: else: return os.path.relpath(os.path.join(build_dir, p), os.path.join(build_dir, from_dir)) -class DynamicLinker(metaclass=abc.ABCMeta): - - """Base class for dynamic linkers.""" - - _BUILDTYPE_ARGS: T.Dict[str, T.List[str]] = { - 'plain': [], - 'debug': [], - 'debugoptimized': [], - 'release': [], - 'minsize': [], - 'custom': [], - } - - @abc.abstractproperty - def id(self) -> str: - pass - - def _apply_prefix(self, arg: T.Union[str, T.List[str]]) -> T.List[str]: - args = [arg] if isinstance(arg, str) else arg - if self.prefix_arg is None: - return args - elif isinstance(self.prefix_arg, str): - return [self.prefix_arg + arg for arg in args] - ret: T.List[str] = [] - for arg in args: - ret += self.prefix_arg + [arg] - return ret - - def __init__(self, exelist: T.List[str], - for_machine: mesonlib.MachineChoice, prefix_arg: T.Union[str, T.List[str]], - always_args: T.List[str], *, version: str = 'unknown version'): - self.exelist = exelist - self.for_machine = for_machine - self.version = version - self.prefix_arg = prefix_arg - self.always_args = always_args - self.machine: T.Optional[str] = None - - def __repr__(self) -> str: - return '<{}: v{} `{}`>'.format(type(self).__name__, self.version, ' '.join(self.exelist)) - - def get_id(self) -> str: - return self.id - - def get_version_string(self) -> str: - return f'({self.id} {self.version})' - - def get_exelist(self) -> T.List[str]: - return self.exelist.copy() - - def get_accepts_rsp(self) -> bool: - # rsp files are only used when building on Windows because we want to - # avoid issues with quoting and max argument length - return mesonlib.is_windows() - - def rsp_file_syntax(self) -> RSPFileSyntax: - """The format of the RSP file that this compiler supports. - - If `self.can_linker_accept_rsp()` returns True, then this needs to - be implemented - """ - return RSPFileSyntax.GCC - - def get_always_args(self) -> T.List[str]: - return self.always_args.copy() - - def get_lib_prefix(self) -> str: - return '' - - # XXX: is use_ldflags a compiler or a linker attribute? - - def get_option_args(self, options: 'KeyedOptionDictType') -> T.List[str]: - return [] - - def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: - raise EnvironmentException(f'Language {self.id} does not support has_multi_link_arguments.') - - def get_debugfile_name(self, targetfile: str) -> T.Optional[str]: - '''Name of debug file written out (see below)''' - return None - - def get_debugfile_args(self, targetfile: str) -> T.List[str]: - """Some compilers (MSVC) write debug into a separate file. - - This method takes the target object path and returns a list of - commands to append to the linker invocation to control where that - file is written. - """ - return [] - - def get_std_shared_lib_args(self) -> T.List[str]: - return [] - - def get_std_shared_module_args(self, options: 'KeyedOptionDictType') -> T.List[str]: - return self.get_std_shared_lib_args() - - def get_pie_args(self) -> T.List[str]: - # TODO: this really needs to take a boolean and return the args to - # disable pie, otherwise it only acts to enable pie if pie *isn't* the - # default. - raise EnvironmentException(f'Linker {self.id} does not support position-independent executable') - - def get_lto_args(self) -> T.List[str]: - return [] - - def get_thinlto_cache_args(self, path: str) -> T.List[str]: - return [] - - def sanitizer_args(self, value: str) -> T.List[str]: - return [] - - def get_buildtype_args(self, buildtype: str) -> T.List[str]: - # We can override these in children by just overriding the - # _BUILDTYPE_ARGS value. - return self._BUILDTYPE_ARGS[buildtype] - - def get_asneeded_args(self) -> T.List[str]: - return [] - - def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: - raise EnvironmentException( - f'Linker {self.id} does not support link_whole') - - def get_allow_undefined_args(self) -> T.List[str]: - raise EnvironmentException( - f'Linker {self.id} does not support allow undefined') - - @abc.abstractmethod - def get_output_args(self, outputname: str) -> T.List[str]: - pass - - def get_coverage_args(self) -> T.List[str]: - raise EnvironmentException(f"Linker {self.id} doesn't implement coverage data generation.") - - @abc.abstractmethod - def get_search_args(self, dirname: str) -> T.List[str]: - pass - - def export_dynamic_args(self, env: 'Environment') -> T.List[str]: - return [] - - def import_library_args(self, implibname: str) -> T.List[str]: - """The name of the outputted import library. - - This implementation is used only on Windows by compilers that use GNU ld - """ - return [] - - def thread_flags(self, env: 'Environment') -> T.List[str]: - return [] - - def no_undefined_args(self) -> T.List[str]: - """Arguments to error if there are any undefined symbols at link time. - - This is the inverse of get_allow_undefined_args(). - - TODO: A future cleanup might merge this and - get_allow_undefined_args() into a single method taking a - boolean - """ - return [] - - def fatal_warnings(self) -> T.List[str]: - """Arguments to make all warnings errors.""" - return [] - - def headerpad_args(self) -> T.List[str]: - # Only used by the Apple linker - return [] - - def get_gui_app_args(self, value: bool) -> T.List[str]: - # Only used by VisualStudioLikeLinkers - return [] - - def get_win_subsystem_args(self, value: str) -> T.List[str]: - # Only used if supported by the dynamic linker and - # only when targeting Windows - return [] - - def bitcode_args(self) -> T.List[str]: - raise MesonException('This linker does not support bitcode bundles') - - def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, - rpath_paths: T.Tuple[str, ...], build_rpath: str, - install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: - return ([], set()) - - def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, - suffix: str, soversion: str, darwin_versions: T.Tuple[str, str]) -> T.List[str]: - return [] - - def get_archive_name(self, filename: str) -> str: - #Only used by AIX. - return str() - - def get_command_to_archive_shlib(self) -> T.List[str]: - #Only used by AIX. - return [] - class PosixDynamicLinkerMixin: -- cgit v1.1