Skip to content

Commit

Permalink
build: Simplify recursive function that extracts objects in link_whole
Browse files Browse the repository at this point in the history
  • Loading branch information
xclaesse committed Nov 9, 2023
1 parent 686963f commit 21bf18a
Showing 1 changed file with 18 additions and 19 deletions.
37 changes: 18 additions & 19 deletions mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -1276,21 +1276,21 @@ def get_extra_args(self, language: str) -> T.List[str]:
return self.extra_args[language]

@lru_cache(maxsize=None)
def get_dependencies(self) -> OrderedSet[Target]:
def get_dependencies(self) -> OrderedSet[BuildTargetTypes]:
# Get all targets needed for linking. This includes all link_with and
# link_whole targets, and also all dependencies of static libraries
# recursively. The algorithm here is closely related to what we do in
# get_internal_static_libraries(): Installed static libraries include
# objects from all their dependencies already.
result: OrderedSet[Target] = OrderedSet()
result: OrderedSet[BuildTargetTypes] = OrderedSet()
for t in itertools.chain(self.link_targets, self.link_whole_targets):
if t not in result:
result.add(t)
if isinstance(t, StaticLibrary):
t.get_dependencies_recurse(result)
return result

def get_dependencies_recurse(self, result: OrderedSet[Target], include_internals: bool = True) -> None:
def get_dependencies_recurse(self, result: OrderedSet[BuildTargetTypes], include_internals: bool = True) -> None:
# self is always a static library because we don't need to pull dependencies
# of shared libraries. If self is installed (not internal) it already
# include objects extracted from all its internal dependencies so we can
Expand Down Expand Up @@ -1394,7 +1394,7 @@ def get_external_deps(self) -> T.List[dependencies.Dependency]:
def is_internal(self) -> bool:
return False

def link(self, targets):
def link(self, targets: T.List[BuildTargetTypes]) -> None:
for t in targets:
if not isinstance(t, (Target, CustomTargetIndex)):
if isinstance(t, dependencies.ExternalLibrary):
Expand All @@ -1420,7 +1420,7 @@ def link(self, targets):
self.check_can_link_together(t)
self.link_targets.append(t)

def link_whole(self, targets, promoted: bool = False):
def link_whole(self, targets: T.List[BuildTargetTypes], promoted: bool = False) -> None:
for t in targets:
if isinstance(t, (CustomTarget, CustomTargetIndex)):
if not t.is_linkable_target():
Expand All @@ -1437,32 +1437,30 @@ def link_whole(self, targets, promoted: bool = False):
if isinstance(self, StaticLibrary) and not self.uses_rust():
# 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.check_can_extract_objects(t, origin=self, promoted=promoted)
self.objects += [t.extract_all_objects()]
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(origin=self):
self.objects += [lib.extract_all_objects()]
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, origin: StaticLibrary) -> OrderedSet[Target]:
result: OrderedSet[Target] = OrderedSet()
self.get_internal_static_libraries_recurse(result, origin)
def get_internal_static_libraries(self) -> OrderedSet[BuildTargetTypes]:
result: OrderedSet[BuildTargetTypes] = OrderedSet()
self.get_internal_static_libraries_recurse(result)
return result

def get_internal_static_libraries_recurse(self, result: OrderedSet[Target], origin: StaticLibrary) -> None:
def get_internal_static_libraries_recurse(self, result: OrderedSet[BuildTargetTypes]) -> None:
for t in self.link_targets:
if t.is_internal() and t not in result:
self.check_can_extract_objects(t, origin, promoted=True)
result.add(t)
t.get_internal_static_libraries_recurse(result, origin)
t.get_internal_static_libraries_recurse(result)
for t in self.link_whole_targets:
if t.is_internal():
t.get_internal_static_libraries_recurse(result, origin)
t.get_internal_static_libraries_recurse(result)

def check_can_extract_objects(self, t: T.Union[Target, CustomTargetIndex], origin: StaticLibrary, promoted: bool = False) -> None:
def _bundle_static_library(self, t: T.Union[BuildTargetTypes], promoted: bool = False) -> None:
if 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
Expand All @@ -1472,12 +1470,13 @@ def check_can_extract_objects(self, t: T.Union[Target, CustomTargetIndex], origi
# 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 {origin.name!r}. '
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 {origin.name!r} is installed but not {t.name!r},'
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)
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()
Expand Down

0 comments on commit 21bf18a

Please sign in to comment.