From 4dac12cea33dcd5902fc0a487707688038c00675 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 5 Dec 2025 08:52:16 -0800 Subject: [PATCH 1/6] interpreter: use a true function for link_with validation We're going to be expanding it shortly. --- mesonbuild/interpreter/type_checking.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index 28280a996538..91275ceacfa5 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -435,7 +435,14 @@ def _default_options_convertor(raw: T.Union[str, T.List[str], T.Dict[str, Elemen default=[], ) -_link_with_error = '''can only be self-built targets, external dependencies (including libraries) must go in "dependencies".''' +_LINK_WITH_ERROR = '''can only be self-built targets, external dependencies (including libraries) must go in "dependencies".''' + +def _link_with_validator(values: T.List[T.Union[BothLibraries, SharedLibrary, StaticLibrary, + CustomTarget, CustomTargetIndex, Jar, Executable]] + ) -> T.Optional[str]: + if any(isinstance(i, Dependency) for i in values): + return _LINK_WITH_ERROR + return None # Allow Dependency for the better error message? But then in other cases it will list this as one of the allowed types! LINK_WITH_KW: KwargInfo[T.List[T.Union[BothLibraries, SharedLibrary, StaticLibrary, CustomTarget, CustomTargetIndex, Jar, Executable]]] = KwargInfo( @@ -443,7 +450,7 @@ def _default_options_convertor(raw: T.Union[str, T.List[str], T.Dict[str, Elemen ContainerTypeInfo(list, (BothLibraries, SharedLibrary, StaticLibrary, CustomTarget, CustomTargetIndex, Jar, Executable, Dependency)), listify=True, default=[], - validator=lambda x: _link_with_error if any(isinstance(i, Dependency) for i in x) else None, + validator=_link_with_validator, ) def link_whole_validator(values: T.List[T.Union[StaticLibrary, CustomTarget, CustomTargetIndex, Dependency]]) -> T.Optional[str]: @@ -451,7 +458,7 @@ def link_whole_validator(values: T.List[T.Union[StaticLibrary, CustomTarget, Cus if isinstance(l, (CustomTarget, CustomTargetIndex)) and l.links_dynamically(): return f'{type(l).__name__} returning a shared library is not allowed' if isinstance(l, Dependency): - return _link_with_error + return _LINK_WITH_ERROR return None LINK_WHOLE_KW: KwargInfo[T.List[T.Union[BothLibraries, StaticLibrary, CustomTarget, CustomTargetIndex]]] = KwargInfo( From 5a6e178eb0efcf229f78b3635e49cd7ae9f69d69 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 5 Dec 2025 08:58:25 -0800 Subject: [PATCH 2/6] build|interpreter: use the LINK_WHOLE validator for BuildTarget --- mesonbuild/build.py | 14 +++++--------- mesonbuild/interpreter/kwargs.py | 1 + mesonbuild/interpreter/type_checking.py | 1 + 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 138f1ae03233..f061d75f9664 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1516,16 +1516,12 @@ def link(self, targets: T.List[BuildTargetTypes]) -> None: self.check_can_link_together(t) self.link_targets.append(t) - def link_whole(self, targets: T.List[BuildTargetTypes], promoted: bool = False) -> None: + def link_whole( + self, + targets: T.List[T.Union[StaticLibrary, CustomTarget, CustomTargetIndex]], + promoted: bool = False) -> None: for t in targets: - if isinstance(t, (CustomTarget, CustomTargetIndex)): - if not t.is_linkable_target(): - raise InvalidArguments(f'Custom target {t!r} is not linkable.') - if t.links_dynamically(): - raise InvalidArguments('Can only link_whole custom targets that are static archives.') - elif not isinstance(t, StaticLibrary): - raise InvalidArguments(f'{t!r} is not a static library.') - elif isinstance(self, SharedLibrary) and not t.pic: + if isinstance(self, SharedLibrary) and not getattr(t, 'pic', True): msg = f"Can't link non-PIC static library {t.name!r} into shared library {self.name!r}. " msg += "Use the 'pic' option to static_library to build with PIC." raise InvalidArguments(msg) diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index 4935973d95d4..a4666a1deffc 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -345,6 +345,7 @@ class _BaseBuildTarget(TypedDict): implicit_include_directories: bool link_depends: T.List[T.Union[str, File, build.GeneratedTypes]] link_language: T.Optional[str] + link_whole: T.List[T.Union[build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex]] name_prefix: T.Optional[str] name_suffix: T.Optional[str] native: MachineChoice diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index 91275ceacfa5..a8ee8dabd5cd 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -722,6 +722,7 @@ def _pch_convertor(args: T.List[str]) -> T.Optional[T.Tuple[str, T.Optional[str] *_LANGUAGE_KWS, BT_SOURCES_KW, INCLUDE_DIRECTORIES.evolve(name='d_import_dirs'), + LINK_WHOLE_KW, _NAME_PREFIX_KW, _NAME_PREFIX_KW.evolve(name='name_suffix', validator=_name_suffix_validator), RUST_CRATE_TYPE_KW, From 15f195e46b4c591e8b33b47585db907c2c0e3833 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 5 Dec 2025 09:41:57 -0800 Subject: [PATCH 3/6] interpreter: validate that a target is linkable in link_whole check This catches the addition of un-linkable targets at the interpreter level rather than requiring the build layer to handle this. In turn, this gives the end user a better error message. --- mesonbuild/interpreter/type_checking.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index a8ee8dabd5cd..83270320206a 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -459,6 +459,8 @@ def link_whole_validator(values: T.List[T.Union[StaticLibrary, CustomTarget, Cus return f'{type(l).__name__} returning a shared library is not allowed' if isinstance(l, Dependency): return _LINK_WITH_ERROR + if not l.is_linkable_target(): + return f'Link target "{l!s}" is not linkable' return None LINK_WHOLE_KW: KwargInfo[T.List[T.Union[BothLibraries, StaticLibrary, CustomTarget, CustomTargetIndex]]] = KwargInfo( From d11b019d9e02b6a7b5abec3396233f0b7b8ef5db Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 5 Dec 2025 09:06:21 -0800 Subject: [PATCH 4/6] build: clean up some some of the link_whole path This puts subclass specific logic in the subclasses, and cleans up some typing. --- mesonbuild/build.py | 104 ++++++++++++++++++------------- mesonbuild/interpreter/kwargs.py | 4 +- 2 files changed, 63 insertions(+), 45 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index f061d75f9664..a189197dbf36 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -52,6 +52,7 @@ GeneratedTypes: TypeAlias = T.Union['CustomTarget', 'CustomTargetIndex', 'GeneratedList'] LibTypes: TypeAlias = T.Union['SharedLibrary', 'StaticLibrary', 'CustomTarget', 'CustomTargetIndex'] BuildTargetTypes: TypeAlias = T.Union['BuildTarget', 'CustomTarget', 'CustomTargetIndex'] + StaticTargetTypes: TypeAlias = T.Union['StaticLibrary', 'CustomTarget', 'CustomTargetIndex'] ObjectTypes: TypeAlias = T.Union[str, 'File', 'ExtractedObjects', 'GeneratedTypes'] AnyTargetType: TypeAlias = T.Union['Target', 'CustomTargetIndex'] RustCrateType: TypeAlias = Literal['bin', 'lib', 'rlib', 'dylib', 'cdylib', 'staticlib', 'proc-macro'] @@ -90,7 +91,7 @@ class BuildTargetKeywordArguments(TypedDict, total=False): link_args: T.List[str] link_depends: T.List[T.Union[str, File, CustomTarget, CustomTargetIndex]] link_language: str - link_whole: T.List[T.Union[StaticLibrary, CustomTarget, CustomTargetIndex]] + link_whole: T.List[StaticTargetTypes] link_with: T.List[BuildTargetTypes] name_prefix: T.Optional[str] name_suffix: T.Optional[str] @@ -796,7 +797,7 @@ def __init__( self.include_dirs: T.List['IncludeDirs'] = [] self.link_language = kwargs.get('link_language') self.link_targets: T.List[LibTypes] = [] - self.link_whole_targets: T.List[T.Union[StaticLibrary, CustomTarget, CustomTargetIndex]] = [] + self.link_whole_targets: T.List[StaticTargetTypes] = [] self.depend_files: T.List[File] = [] self.link_depends: T.List[T.Union[File, BuildTargetTypes]] = [] self.added_deps = set() @@ -1518,32 +1519,19 @@ def link(self, targets: T.List[BuildTargetTypes]) -> None: def link_whole( self, - targets: T.List[T.Union[StaticLibrary, CustomTarget, CustomTargetIndex]], + targets: T.List[StaticTargetTypes], promoted: bool = False) -> None: for t in targets: - if isinstance(self, SharedLibrary) and not getattr(t, 'pic', True): - msg = f"Can't link non-PIC static library {t.name!r} into shared library {self.name!r}. " - msg += "Use the 'pic' option to static_library to build with PIC." - raise InvalidArguments(msg) self.check_can_link_together(t) - if isinstance(self, StaticLibrary): - # When we're a static library and we link_whole: to another static - # library, we need to add that target's objects to ourselves. - self._bundle_static_library(t, promoted) - # If we install this static library we also need to include objects - # from all uninstalled static libraries it depends on. - if self.install: - for lib in t.get_internal_static_libraries(): - self._bundle_static_library(lib, True) self.link_whole_targets.append(t) @lru_cache(maxsize=None) - def get_internal_static_libraries(self) -> OrderedSet[BuildTargetTypes]: - result: OrderedSet[BuildTargetTypes] = OrderedSet() + def get_internal_static_libraries(self) -> OrderedSet[StaticTargetTypes]: + result: OrderedSet[StaticTargetTypes] = OrderedSet() self.get_internal_static_libraries_recurse(result) return result - def get_internal_static_libraries_recurse(self, result: OrderedSet[BuildTargetTypes]) -> None: + def get_internal_static_libraries_recurse(self, result: OrderedSet[StaticTargetTypes]) -> None: for t in self.link_targets: if t.is_internal() and t not in result: result.add(t) @@ -1552,28 +1540,6 @@ def get_internal_static_libraries_recurse(self, result: OrderedSet[BuildTargetTy if t.is_internal(): t.get_internal_static_libraries_recurse(result) - def _bundle_static_library(self, t: T.Union[BuildTargetTypes], promoted: bool = False) -> None: - if self.uses_rust(): - # Rustc can bundle static libraries, no need to extract objects. - self.link_whole_targets.append(t) - elif isinstance(t, (CustomTarget, CustomTargetIndex)) or t.uses_rust(): - # To extract objects from a custom target we would have to extract - # the archive, WIP implementation can be found in - # https://github.com/mesonbuild/meson/pull/9218. - # For Rust C ABI we could in theory have access to objects, but there - # are several meson issues that need to be fixed: - # https://github.com/mesonbuild/meson/issues/10722 - # https://github.com/mesonbuild/meson/issues/10723 - # https://github.com/mesonbuild/meson/issues/10724 - m = (f'Cannot link_whole a custom or Rust target {t.name!r} into a static library {self.name!r}. ' - 'Instead, pass individual object files with the "objects:" keyword argument if possible.') - if promoted: - m += (f' Meson had to promote link to link_whole because {self.name!r} is installed but not {t.name!r},' - f' and thus has to include objects from {t.name!r} to be usable.') - raise InvalidArguments(m) - else: - self.objects.append(t.extract_all_objects()) - def check_can_link_together(self, t: BuildTargetTypes) -> None: links_with_rust_abi = isinstance(t, BuildTarget) and t.uses_rust_abi() if not self.uses_rust() and links_with_rust_abi: @@ -2405,6 +2371,46 @@ def get(self, lib_type: T.Literal['static', 'shared'], recursive: bool = False) result.link_targets = [t.get(lib_type, True) for t in self.link_targets] return result + def link_whole( + self, + targets: T.List[StaticTargetTypes], + promoted: bool = False) -> None: + for t in targets: + self.check_can_link_together(t) + + # When we're a static library and we link_whole: to another static + # library, we need to add that target's objects to ourselves. + self._bundle_static_library(t, promoted) + + # If we install this static library we also need to include objects + # from all uninstalled static libraries it depends on. + if self.install: + for lib in t.get_internal_static_libraries(): + self._bundle_static_library(lib, True) + self.link_whole_targets.append(t) + + def _bundle_static_library(self, t: StaticTargetTypes, promoted: bool = False) -> None: + if self.uses_rust(): + # Rustc can bundle static libraries, no need to extract objects. + self.link_whole_targets.append(t) + elif isinstance(t, (CustomTarget, CustomTargetIndex)) or t.uses_rust(): + # To extract objects from a custom target we would have to extract + # the archive, WIP implementation can be found in + # https://github.com/mesonbuild/meson/pull/9218. + # For Rust C ABI we could in theory have access to objects, but there + # are several meson issues that need to be fixed: + # https://github.com/mesonbuild/meson/issues/10722 + # https://github.com/mesonbuild/meson/issues/10723 + # https://github.com/mesonbuild/meson/issues/10724 + m = (f'Cannot link_whole a custom or Rust target {t.name!r} into a static library {self.name!r}. ' + 'Instead, pass individual object files with the "objects:" keyword argument if possible.') + if promoted: + m += (f' Meson had to promote link to link_whole because {self.name!r} is installed but not {t.name!r},' + f' and thus has to include objects from {t.name!r} to be usable.') + raise InvalidArguments(m) + else: + self.objects.append(t.extract_all_objects()) + class SharedLibrary(BuildTarget): known_kwargs = known_shlib_kwargs @@ -2709,6 +2715,18 @@ def get(self, lib_type: T.Literal['static', 'shared'], recursive: bool = False) result.link_targets = [t.get(lib_type, True) for t in self.link_targets] return result + def link_whole( + self, + targets: T.List[StaticTargetTypes], + promoted: bool = False) -> None: + for t in targets: + self.check_can_link_together(t) + if not getattr(t, 'pic', True): + msg = f"Can't link non-PIC static library {t.name!r} into shared library {self.name!r}. " + msg += "Use the 'pic' option to static_library to build with PIC." + raise InvalidArguments(msg) + self.link_whole_targets.append(t) + # A shared library that is meant to be used with dlopen rather than linking # into something else. class SharedModule(SharedLibrary): @@ -2823,10 +2841,10 @@ class CustomTargetBase: def get_dependencies_recurse(self, result: OrderedSet[BuildTargetTypes], include_internals: bool = True) -> None: pass - def get_internal_static_libraries(self) -> OrderedSet[BuildTargetTypes]: + def get_internal_static_libraries(self) -> OrderedSet[StaticTargetTypes]: return OrderedSet() - def get_internal_static_libraries_recurse(self, result: OrderedSet[BuildTargetTypes]) -> None: + def get_internal_static_libraries_recurse(self, result: OrderedSet[StaticTargetTypes]) -> None: pass def get_all_linked_targets(self) -> ImmutableListProtocol[BuildTargetTypes]: diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index a4666a1deffc..140d23cbdc23 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -345,7 +345,7 @@ class _BaseBuildTarget(TypedDict): implicit_include_directories: bool link_depends: T.List[T.Union[str, File, build.GeneratedTypes]] link_language: T.Optional[str] - link_whole: T.List[T.Union[build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex]] + link_whole: T.List[build.StaticTargetTypes] name_prefix: T.Optional[str] name_suffix: T.Optional[str] native: MachineChoice @@ -489,7 +489,7 @@ class FuncDeclareDependency(TypedDict): extra_files: T.List[FileOrString] include_directories: T.List[T.Union[build.IncludeDirs, str]] link_args: T.List[str] - link_whole: T.List[T.Union[build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex]] + link_whole: T.List[build.StaticTargetTypes] link_with: T.List[build.LibTypes] objects: T.List[build.ExtractedObjects] sources: T.List[T.Union[FileOrString, build.GeneratedTypes]] From 89d3ffdc986133df0c4827f00e2765ecda23db97 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 5 Dec 2025 09:15:06 -0800 Subject: [PATCH 5/6] build|interpreter: use typed_kwargs for link_with This replaces the long explanation of `external_library`s in the `link_with` parameter to the simpler one used by declare_dependency. Additionally, declare_dependency now checks that a target is linkable when adding it. This just catches the problem before it goes down into the build layer giving a better error message. There is a bug in the declare_dependency annotations, in that they don't mark Executable as acceptable. So I've fixed that. --- mesonbuild/build.py | 18 +++++------------- mesonbuild/interpreter/kwargs.py | 3 ++- mesonbuild/interpreter/type_checking.py | 11 ++++++++--- .../failing/52 link with executable/test.json | 2 +- .../failing/59 string as link target/test.json | 2 +- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index a189197dbf36..ab9b1223d3e5 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -796,7 +796,7 @@ def __init__( self.external_deps: T.List[dependencies.Dependency] = [] self.include_dirs: T.List['IncludeDirs'] = [] self.link_language = kwargs.get('link_language') - self.link_targets: T.List[LibTypes] = [] + self.link_targets: T.List[BuildTargetTypes] = [] self.link_whole_targets: T.List[StaticTargetTypes] = [] self.depend_files: T.List[File] = [] self.link_depends: T.List[T.Union[File, BuildTargetTypes]] = [] @@ -1493,18 +1493,6 @@ def is_internal(self) -> bool: def link(self, targets: T.List[BuildTargetTypes]) -> None: for t in targets: - if not isinstance(t, (Target, CustomTargetIndex)): - if isinstance(t, dependencies.ExternalLibrary): - raise MesonException(textwrap.dedent('''\ - An external library was used in link_with keyword argument, which - is reserved for libraries built as part of this project. External - libraries must be passed using the dependencies keyword argument - instead, because they are conceptually "external dependencies", - just like those detected with the dependency() function. - ''')) - raise InvalidArguments(f'{t!r} is not a target.') - if not t.is_linkable_target(): - raise InvalidArguments(f"Link target '{t!s}' is not linkable.") if isinstance(self, StaticLibrary) and self.install and t.is_internal(): # When we're a static library and we link_with to an # internal/convenience library, promote to link_whole. @@ -2789,6 +2777,10 @@ def get_default_object(self) -> T.Union[StaticLibrary, SharedLibrary]: def get_id(self) -> str: return self.get_default_object().get_id() + def is_linkable_target(self) -> bool: + # For polymorphism with build targets + return True + class CommandBase: depend_files: T.List[File] diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index 140d23cbdc23..a79ff096824c 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -346,6 +346,7 @@ class _BaseBuildTarget(TypedDict): link_depends: T.List[T.Union[str, File, build.GeneratedTypes]] link_language: T.Optional[str] link_whole: T.List[build.StaticTargetTypes] + link_with: T.List[build.BuildTargetTypes] name_prefix: T.Optional[str] name_suffix: T.Optional[str] native: MachineChoice @@ -490,7 +491,7 @@ class FuncDeclareDependency(TypedDict): include_directories: T.List[T.Union[build.IncludeDirs, str]] link_args: T.List[str] link_whole: T.List[build.StaticTargetTypes] - link_with: T.List[build.LibTypes] + link_with: T.List[build.BuildTargetTypes] objects: T.List[build.ExtractedObjects] sources: T.List[T.Union[FileOrString, build.GeneratedTypes]] variables: T.Dict[str, str] diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index 83270320206a..b140ea2a7bf9 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -438,10 +438,14 @@ def _default_options_convertor(raw: T.Union[str, T.List[str], T.Dict[str, Elemen _LINK_WITH_ERROR = '''can only be self-built targets, external dependencies (including libraries) must go in "dependencies".''' def _link_with_validator(values: T.List[T.Union[BothLibraries, SharedLibrary, StaticLibrary, - CustomTarget, CustomTargetIndex, Jar, Executable]] + CustomTarget, CustomTargetIndex, Jar, Executable, + ]] ) -> T.Optional[str]: - if any(isinstance(i, Dependency) for i in values): - return _LINK_WITH_ERROR + for value in values: + if isinstance(value, Dependency): + return _LINK_WITH_ERROR + if not value.is_linkable_target(): + return f'Link target "{value!s}" is not linkable' return None # Allow Dependency for the better error message? But then in other cases it will list this as one of the allowed types! @@ -725,6 +729,7 @@ def _pch_convertor(args: T.List[str]) -> T.Optional[T.Tuple[str, T.Optional[str] BT_SOURCES_KW, INCLUDE_DIRECTORIES.evolve(name='d_import_dirs'), LINK_WHOLE_KW, + LINK_WITH_KW, _NAME_PREFIX_KW, _NAME_PREFIX_KW.evolve(name='name_suffix', validator=_name_suffix_validator), RUST_CRATE_TYPE_KW, diff --git a/test cases/failing/52 link with executable/test.json b/test cases/failing/52 link with executable/test.json index ba9c345496c8..976d9670631c 100644 --- a/test cases/failing/52 link with executable/test.json +++ b/test cases/failing/52 link with executable/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/52 link with executable/meson.build:4:4: ERROR: Link target 'prog' is not linkable." + "line": "test cases/failing/52 link with executable/meson.build:4:4: ERROR: shared_module keyword argument \"link_with\" Link target \"prog\" is not linkable" } ] } diff --git a/test cases/failing/59 string as link target/test.json b/test cases/failing/59 string as link target/test.json index ddc639980108..0921225a82ae 100644 --- a/test cases/failing/59 string as link target/test.json +++ b/test cases/failing/59 string as link target/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/59 string as link target/meson.build:2:0: ERROR: '' is not a target." + "line": "test cases/failing/59 string as link target/meson.build:2:0: ERROR: executable keyword argument 'link_with' was of type array[str] but should have been array[BothLibraries | SharedLibrary | StaticLibrary | CustomTarget | CustomTargetIndex | Jar | Executable | Dependency]" } ] } From b2f7b5e3eae816c0f0ed47bebb1be12d782e76f6 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 5 Dec 2025 09:17:24 -0800 Subject: [PATCH 6/6] build: clean up the `link` helper Splits the subclass specific code into those classes --- mesonbuild/build.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index ab9b1223d3e5..a766d9a09156 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1493,15 +1493,6 @@ def is_internal(self) -> bool: def link(self, targets: T.List[BuildTargetTypes]) -> None: for t in targets: - if isinstance(self, StaticLibrary) and self.install and t.is_internal(): - # When we're a static library and we link_with to an - # internal/convenience library, promote to link_whole. - self.link_whole([t], promoted=True) - continue - if isinstance(self, SharedLibrary) and isinstance(t, StaticLibrary) and not t.pic: - msg = f"Can't link non-PIC static library {t.name!r} into shared library {self.name!r}. " - msg += "Use the 'pic' option to static_library to build with PIC." - raise InvalidArguments(msg) self.check_can_link_together(t) self.link_targets.append(t) @@ -2377,6 +2368,16 @@ def link_whole( self._bundle_static_library(lib, True) self.link_whole_targets.append(t) + def link(self, targets: T.List[BuildTargetTypes]) -> None: + for t in targets: + if self.install and t.is_internal(): + # When we're a static library and we link_with to an + # internal/convenience library, promote to link_whole. + self.link_whole([t], promoted=True) + continue + self.check_can_link_together(t) + self.link_targets.append(t) + def _bundle_static_library(self, t: StaticTargetTypes, promoted: bool = False) -> None: if self.uses_rust(): # Rustc can bundle static libraries, no need to extract objects. @@ -2715,6 +2716,15 @@ def link_whole( raise InvalidArguments(msg) self.link_whole_targets.append(t) + def link(self, targets: T.List[BuildTargetTypes]) -> None: + for t in targets: + if isinstance(t, StaticLibrary) and not t.pic: + msg = f"Can't link non-PIC static library {t.name!r} into shared library {self.name!r}. " + msg += "Use the 'pic' option to static_library to build with PIC." + raise InvalidArguments(msg) + self.check_can_link_together(t) + self.link_targets.append(t) + # A shared library that is meant to be used with dlopen rather than linking # into something else. class SharedModule(SharedLibrary):