blob: a7644525df9a75d648fa43387c7831d94e0fe96c [file] [log] [blame]
Allen Webb3e498aa2023-09-05 14:40:49 +00001# Copyright 2023 The ChromiumOS Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Check whether a package links libraries not in RDEPEND.
6
7If no argument is provided it will check all installed packages. It takes the
8BOARD environment variable into account.
9
10Example:
Nicholas Bishopda8cc212023-09-26 13:25:39 -040011 package_has_missing_deps.py --board=amd64-generic --match \
Allen Webb3e498aa2023-09-05 14:40:49 +000012 chromeos-base/cryptohome
13"""
14
Allen Webb3350c432023-09-29 11:04:50 -050015from __future__ import annotations
16
Allen Webb3e498aa2023-09-05 14:40:49 +000017import argparse
18import collections
Mike Frysinger494c6182023-09-21 11:44:45 -040019import logging
Allen Webb3e498aa2023-09-05 14:40:49 +000020import os
Allen Webbe8c1da02023-09-08 18:25:22 +000021from pathlib import Path
Allen Webb3e498aa2023-09-05 14:40:49 +000022import pprint
Allen Webb3350c432023-09-29 11:04:50 -050023import re
Allen Webb3e498aa2023-09-05 14:40:49 +000024import sys
Allen Webb3350c432023-09-29 11:04:50 -050025from typing import (
26 Generic,
27 Iterable,
28 List,
29 NamedTuple,
30 Optional,
31 Set,
32 TypeVar,
33 Union,
34)
Allen Webb3e498aa2023-09-05 14:40:49 +000035
36from chromite.lib import build_target_lib
37from chromite.lib import chroot_lib
38from chromite.lib import commandline
39from chromite.lib import cros_build_lib
Allen Webb3e498aa2023-09-05 14:40:49 +000040from chromite.lib import portage_util
41from chromite.lib.parser import package_info
42
43
Allen Webb7cc7cd92023-09-11 16:16:33 +000044VIRTUALS = {
Allen Webb4c582aa2023-09-12 17:20:49 +000045 "virtual/acl": ("sys-apps/acl", "media-libs/img-ddk-bin"),
46 "virtual/arc-opengles": (
47 "media-libs/arc-img-ddk",
48 "media-libs/arc-mesa-img",
49 "media-libs/arc-mali-drivers",
50 "media-libs/arc-mali-drivers-bifrost",
51 "media-libs/arc-mali-drivers-bifrost-bin",
52 "media-libs/arc-mali-drivers-valhall",
53 "media-libs/arc-mali-drivers-valhall-bin",
54 "media-libs/arc-mesa",
55 "media-libs/arc-mesa-amd",
56 "media-libs/arc-mesa-freedreno",
57 "media-libs/arc-mesa-iris",
58 "media-libs/arc-mesa-virgl",
59 "x11-drivers/opengles-headers",
60 ),
61 "virtual/cros-camera-hal": (
62 "media-libs/cros-camera-hal-intel-ipu3",
63 "media-libs/cros-camera-hal-intel-ipu6",
64 "media-libs/cros-camera-hal-mtk",
65 "media-libs/cros-camera-hal-qti",
66 "media-libs/cros-camera-hal-rockchip-isp1",
67 "media-libs/cros-camera-hal-usb",
68 "media-libs/qti-7c-camera-tuning",
69 ),
70 "virtual/img-ddk": ("media-libs/img-ddk", "media-libs/img-ddk-bin"),
71 "virtual/jpeg": ("media-libs/libjpeg-turbo", "media-libs/jpeg"),
72 "virtual/krb5": ("app-crypt/mit-krb5", "app-crypt/heimdal"),
Allen Webb7cc7cd92023-09-11 16:16:33 +000073 "virtual/libcrypt": ("sys-libs/libxcrypt",),
74 "virtual/libelf": ("dev-libs/elfutils", "sys-freebsd/freebsd-lib"),
75 "virtual/libiconv": ("dev-libs/libiconv",),
76 "virtual/libintl": ("dev-libs/libintl",),
77 "virtual/libudev": (
78 "sys-apps/systemd-utils",
79 "sys-fs/udev",
80 "sys-fs/eudev",
81 "sys-apps/systemd",
82 ),
83 "virtual/libusb": ("dev-libs/libusb", "sys-freebsd/freebsd-lib"),
Allen Webb4c582aa2023-09-12 17:20:49 +000084 "virtual/opengles": (
85 "media-libs/img-ddk",
86 "media-libs/img-ddk-bin",
Ricky Liangd5f64432023-09-15 15:50:04 +080087 "media-libs/libglvnd",
Allen Webb4c582aa2023-09-12 17:20:49 +000088 "media-libs/mali-drivers-bin",
89 "media-libs/mali-drivers-bifrost",
90 "media-libs/mali-drivers-bifrost-bin",
91 "media-libs/mali-drivers-valhall",
92 "media-libs/mali-drivers-valhall-bin",
93 "media-libs/mesa",
94 "media-libs/mesa-amd",
95 "media-libs/mesa-freedreno",
96 "media-libs/mesa-iris",
97 "media-libs/mesa-llvmpipe",
98 "media-libs/mesa-panfrost",
99 "media-libs/mesa-reven",
100 "x11-drivers/opengles-headers",
101 ),
102 "virtual/vulkan-icd": (
103 "media-libs/img-ddk",
104 "media-libs/img-ddk-bin",
105 "media-libs/mali-drivers-bifrost",
106 "media-libs/mali-drivers-bifrost-bin",
107 "media-libs/mali-drivers-valhall",
108 "media-libs/mali-drivers-valhall-bin",
109 "media-libs/mesa",
110 "media-libs/mesa-freedreno",
111 "media-libs/mesa-iris",
112 "media-libs/mesa-llvmpipe",
113 "media-libs/mesa-radv",
114 "media-libs/vulkan-loader",
115 ),
Allen Webb7cc7cd92023-09-11 16:16:33 +0000116}
117
118
Allen Webb3350c432023-09-29 11:04:50 -0500119T = TypeVar("T")
Allen Webb3e498aa2023-09-05 14:40:49 +0000120
Allen Webb3350c432023-09-29 11:04:50 -0500121
122class ResultSet(Generic[T], NamedTuple):
123 """Represent separate but related sets for the build target and sdk."""
124
125 target: Set[T]
126 sdk: Set[T]
127
128
129def is_sdk_path(path: str) -> bool:
130 """Match paths for files built for the SDK/builder."""
131 return bool(
132 re.match(
133 "|".join(
134 (
135 r"/usr/src/chromeos-kernel-[^/]+/build"
136 r"/build/bin"
137 r"/build/libexec",
138 )
139 ),
140 path,
141 )
142 )
143
144
145def is_guest_os_path(path: str) -> bool:
146 """Match paths belonging to a guest OS."""
147 return bool(
148 re.match(
149 r"/opt/google/(?:vms|containers)",
150 path,
151 )
152 )
Allen Webb3e498aa2023-09-05 14:40:49 +0000153
154
155class DotSoResolver:
156 """Provides shared library related dependency operations."""
157
158 def __init__(
159 self,
160 board: Optional[str] = None,
161 root: Union[os.PathLike, str] = "/",
162 chroot: Optional[chroot_lib.Chroot] = None,
163 ):
164 self.board = board
165 self.chroot = chroot if chroot else chroot_lib.Chroot()
166
167 self.sdk_db = portage_util.PortageDB()
Mike Frysinger2c65b082023-09-21 12:22:58 -0400168 self._sdk_db_packges = None
Allen Webb3e498aa2023-09-05 14:40:49 +0000169 self.db = self.sdk_db if root == "/" else portage_util.PortageDB(root)
Mike Frysinger2c65b082023-09-21 12:22:58 -0400170 self._db_packges = None
Allen Webb3e498aa2023-09-05 14:40:49 +0000171 self.provided_libs_cache = {}
172
Allen Webbe8c1da02023-09-08 18:25:22 +0000173 # Lazy initialize since it might not be needed.
174 self.lib_to_package_map = None
Allen Webb3350c432023-09-29 11:04:50 -0500175 self.sdk_lib_to_package_map = None
Allen Webbe8c1da02023-09-08 18:25:22 +0000176
Mike Frysinger2c65b082023-09-21 12:22:58 -0400177 @property
178 def sdk_db_packages(self):
179 """Cache sdk_db.InstalledPackages().
180
181 We won't be modifying it, so it's safe for us to reuse the results.
182 """
183 if self._sdk_db_packges is None:
184 self._sdk_db_packges = self.sdk_db.InstalledPackages()
185 return self._sdk_db_packges
186
187 @property
188 def db_packages(self):
189 """Cache db.InstalledPackages().
190
191 We won't be modifying it, so it's safe for us to reuse the results.
192 """
193 if self._db_packges is None:
194 self._db_packges = self.db.InstalledPackages()
195 return self._db_packges
196
Mike Frysinger1e9ac7c2023-09-21 14:53:48 -0400197 def get_packages(
Allen Webb3e498aa2023-09-05 14:40:49 +0000198 self, query: str, from_sdk=False
Mike Frysinger1e9ac7c2023-09-21 14:53:48 -0400199 ) -> Iterable[portage_util.InstalledPackage]:
200 """Find matching InstalledPackage(s) for the |query|."""
Mike Frysinger2c65b082023-09-21 12:22:58 -0400201 packages = self.sdk_db_packages if from_sdk else self.db_packages
Allen Webb3e498aa2023-09-05 14:40:49 +0000202 info = package_info.parse(query)
203 for package in packages:
204 if info.package != package.package:
205 continue
206 if info.category != package.category:
207 continue
208 dep_info = package.package_info
209 if info.revision and info.revision != dep_info.revision:
210 continue
211 if info.pv and info.pv != dep_info.pv:
212 continue
Mike Frysinger494c6182023-09-21 11:44:45 -0400213 logging.debug("query: %s: matched %s", query, dep_info.cpvr)
Mike Frysinger1e9ac7c2023-09-21 14:53:48 -0400214 yield package
Allen Webb3e498aa2023-09-05 14:40:49 +0000215
Allen Webb3350c432023-09-29 11:04:50 -0500216 # TODO Re-enable the lint after we upgrade to Python 3.9 or later.
217 # pylint: disable-next=unsubscriptable-object
218 def get_required_libs(self, package) -> ResultSet[str]:
219 """Return sets of required .so files for the target and the SDK."""
220 sdk = set()
221 target = set()
Allen Webb8fc0bba2023-09-11 14:37:25 +0000222 needed = package.needed
223 if needed is not None:
Allen Webb3350c432023-09-29 11:04:50 -0500224 for file, libs in needed.items():
225 if is_sdk_path(file):
226 sdk.update(libs)
227 elif not is_guest_os_path(file):
228 target.update(libs)
229 return ResultSet(target, sdk)
Allen Webb3e498aa2023-09-05 14:40:49 +0000230
Allen Webb3350c432023-09-29 11:04:50 -0500231 # TODO Re-enable the lint after we upgrade to Python 3.9 or later.
232 # pylint: disable-next=unsubscriptable-object
Mike Frysinger329bd332023-09-21 14:18:18 -0400233 def get_deps(
234 self, package: portage_util.InstalledPackage
Allen Webb3350c432023-09-29 11:04:50 -0500235 ) -> ResultSet[portage_util.InstalledPackage]:
236 """Returns two lists of dependencies.
Allen Webb7cc7cd92023-09-11 16:16:33 +0000237
Allen Webb3350c432023-09-29 11:04:50 -0500238 This expands the virtuals listed in VIRTUALS.
Allen Webb7cc7cd92023-09-11 16:16:33 +0000239 """
Allen Webb3e498aa2023-09-05 14:40:49 +0000240 cpvr = f"{package.category}/{package.pf}"
Mike Frysinger329bd332023-09-21 14:18:18 -0400241
242 # Handling ||() nodes is difficult. Be lazy and expand all of them.
243 # We could compare against the installed db to try and find a match,
244 # but this seems easiest for now as our PortageDB API doesn't support
245 # these kind of primitives yet.
246 def _anyof_reduce(choices: List[str]) -> str:
247 """Reduce ||() nodes."""
248
249 def _flatten(eles):
250 for e in eles:
251 if isinstance(e, tuple):
252 yield from _flatten(e)
253 else:
254 yield e
255
256 citer = _flatten(choices)
257 ret = next(citer)
258 package_dependencies.extend(citer)
259 return ret
260
261 package_dependencies = []
262 package_dependencies.extend(
263 package.depend.reduce(anyof_reduce=_anyof_reduce)
264 )
265 package_dependencies.extend(
266 package.rdepend.reduce(anyof_reduce=_anyof_reduce)
267 )
Allen Webb3350c432023-09-29 11:04:50 -0500268 package_build_dependencies = []
269 package_build_dependencies.extend(
270 package.bdepend.reduce(anyof_reduce=_anyof_reduce)
271 )
Mike Frysinger329bd332023-09-21 14:18:18 -0400272
Allen Webb3350c432023-09-29 11:04:50 -0500273 def _clean_deps(raw_deps: List[str], from_sdk=False) -> Set[str]:
274 deps = set()
275 expanded = []
276 for fulldep in raw_deps:
277 # Preclean the atom. We can only handle basic forms like
278 # CATEGORY/PF, not the full dependency specification. See the
279 # ebuild(5) man page for more details.
280 dep = fulldep
Mike Frysinger329bd332023-09-21 14:18:18 -0400281
Allen Webb3350c432023-09-29 11:04:50 -0500282 # Ignore blockers.
283 if dep.startswith("!"):
284 logging.debug("%s: ignoring blocker: %s", cpvr, dep)
285 continue
Mike Frysinger329bd332023-09-21 14:18:18 -0400286
Allen Webb3350c432023-09-29 11:04:50 -0500287 # Rip off the SLOT spec.
288 dep = dep.split(":", 1)[0]
289 # Rip off any USE flag constraints.
290 dep = dep.split("[", 1)[0]
291 # Trim leading & trailing version ranges.
292 dep = dep.lstrip("<>=~").rstrip("*")
Mike Frysinger329bd332023-09-21 14:18:18 -0400293
Allen Webb3350c432023-09-29 11:04:50 -0500294 logging.debug(
295 "%s: found package dependency: %s -> %s", cpvr, fulldep, dep
296 )
Mike Frysinger329bd332023-09-21 14:18:18 -0400297
Allen Webb3350c432023-09-29 11:04:50 -0500298 info = package_info.parse(dep)
299 if not info:
300 continue
Allen Webb7cc7cd92023-09-11 16:16:33 +0000301
Allen Webb3350c432023-09-29 11:04:50 -0500302 cp = info.cp
303 if cp in VIRTUALS:
304 expanded += VIRTUALS[cp]
305 continue
Allen Webb7cc7cd92023-09-11 16:16:33 +0000306
Allen Webb3350c432023-09-29 11:04:50 -0500307 pkgs = (
308 self.sdk_db if from_sdk else self.db
309 ).GetInstalledPackage(info.category, info.pvr)
310 if not pkgs:
311 pkgs = list(self.get_packages(info.atom, from_sdk))
312 else:
313 pkgs = [pkgs]
Mike Frysinger329bd332023-09-21 14:18:18 -0400314
Allen Webb3350c432023-09-29 11:04:50 -0500315 if pkgs:
316 deps.update(pkgs)
317 else:
318 logging.warning(
319 "%s: could not find installed %s", cpvr, dep
320 )
Allen Webb7cc7cd92023-09-11 16:16:33 +0000321
Allen Webb3350c432023-09-29 11:04:50 -0500322 for dep in expanded:
323 deps.update(self.get_packages(dep))
Allen Webb7cc7cd92023-09-11 16:16:33 +0000324
Allen Webb3350c432023-09-29 11:04:50 -0500325 return deps
326
327 return ResultSet(
328 target=_clean_deps(package_dependencies),
329 sdk=_clean_deps(package_build_dependencies, from_sdk=True),
330 )
Allen Webb3e498aa2023-09-05 14:40:49 +0000331
332 def get_implicit_libs(self):
333 """Return a set of .so files that are provided by the system."""
Allen Webb611e8b12023-09-13 15:54:52 +0000334 # libstdc++ comes from the toolchain so always ignore it.
335 implicit_libs = {"libstdc++.so", "libstdc++.so.6"}
Allen Webb3e498aa2023-09-05 14:40:49 +0000336 for dep, from_sdk in (
337 ("cross-aarch64-cros-linux-gnu/glibc", True),
338 ("cross-armv7a-cros-linux-gnueabihf/glibc", True),
339 ("cross-i686-cros-linux-gnu/glibc", True),
340 ("cross-x86_64-cros-linux-gnu/glibc", True),
341 ("sys-libs/glibc", False),
342 ("sys-libs/libcxx", False),
343 ("sys-libs/llvm-libunwind", False),
344 ):
Mike Frysinger1e9ac7c2023-09-21 14:53:48 -0400345 for pkg in self.get_packages(dep, from_sdk):
346 implicit_libs.update(self.provided_libs(pkg))
Allen Webb3e498aa2023-09-05 14:40:49 +0000347 return implicit_libs
348
349 def provided_libs(self, package: portage_util.InstalledPackage) -> Set[str]:
350 """Return a set of .so files provided by |package|."""
351 cpvr = f"{package.category}/{package.pf}"
352 if cpvr in self.provided_libs_cache:
353 return self.provided_libs_cache[cpvr]
354
355 libs = set()
356 contents = package.ListContents()
357 # Keep only the .so files
358 for typ, path in contents:
359 if typ == package.DIR:
360 continue
361 filename = os.path.basename(path)
Mike Frysinger28f7b952023-09-21 11:40:01 -0400362 if filename.endswith(".so") or (
363 ".so." in filename and not filename.endswith(".debug")
364 ):
Allen Webb3e498aa2023-09-05 14:40:49 +0000365 libs.add(filename)
366 self.provided_libs_cache[cpvr] = libs
367 return libs
368
Allen Webb8fc0bba2023-09-11 14:37:25 +0000369 def cache_libs_from_build(
370 self, package: portage_util.InstalledPackage, image_dir: Path
371 ):
372 """Populate the provided_libs_cache for the package from the image dir.
373
374 When using build-info, CONTENTS might not be available yet. so provide
375 alternative using the destination directory of the ebuild.
376 """
377
378 cpvr = f"{package.category}/{package.pf}"
379 libs = set()
380 for _, _, files in os.walk(image_dir):
381 for file in files:
Mike Frysinger28f7b952023-09-21 11:40:01 -0400382 if file.endswith(".so") or (
383 ".so." in file and not file.endswith(".debug")
384 ):
Allen Webb8fc0bba2023-09-11 14:37:25 +0000385 libs.add(os.path.basename(file))
386 self.provided_libs_cache[cpvr] = libs
387
Allen Webb3350c432023-09-29 11:04:50 -0500388 # TODO Re-enable the lint after we upgrade to Python 3.9 or later.
389 # pylint: disable-next=unsubscriptable-object
Allen Webb3e498aa2023-09-05 14:40:49 +0000390 def get_provided_from_all_deps(
391 self, package: portage_util.InstalledPackage
Allen Webb3350c432023-09-29 11:04:50 -0500392 ) -> ResultSet[str]:
393 """Return sets of .so files provided by the immediate dependencies."""
Allen Webb3e498aa2023-09-05 14:40:49 +0000394
Allen Webb3350c432023-09-29 11:04:50 -0500395 def _expand_to_libs(
396 packages: Set[portage_util.InstalledPackage],
397 ) -> Set[str]:
398 provided_libs = set()
399 # |package| may not actually be installed yet so manually add it too
400 # since a package can depend on its own libs.
401 provided_libs.update(self.provided_libs(package))
402 for pkg in packages:
403 logging.debug(
404 "%s: loading libs from dependency %s",
405 package.package_info.cpvr,
406 pkg.package_info.cpvr,
407 )
408 provided_libs.update(self.provided_libs(pkg))
409 return provided_libs
410
411 deps, sdk_deps = self.get_deps(package)
412 return ResultSet(
413 target=_expand_to_libs(deps), sdk=_expand_to_libs(sdk_deps)
414 )
415
416 def lib_to_package(
417 self, lib_filename: str = None, from_sdk=False
418 ) -> Set[str]:
Allen Webbe8c1da02023-09-08 18:25:22 +0000419 """Return a set of packages that contain the library."""
Allen Webb3350c432023-09-29 11:04:50 -0500420 lookup = (
421 self.sdk_lib_to_package_map if from_sdk else self.lib_to_package_map
422 )
423 if lookup is None:
Allen Webbe8c1da02023-09-08 18:25:22 +0000424 lookup = collections.defaultdict(set)
Allen Webb3350c432023-09-29 11:04:50 -0500425 for pkg in (
426 self.sdk_db.InstalledPackages()
427 if from_sdk
428 else self.db.InstalledPackages()
429 ):
Allen Webbe8c1da02023-09-08 18:25:22 +0000430 cpvr = f"{pkg.category}/{pkg.pf}"
431 # Packages with bundled libs for internal use and/or standaline
432 # binary packages.
433 if f"{pkg.category}/{pkg.package}" in (
434 "app-emulation/qemu",
435 "chromeos-base/aosp-frameworks-ml-nn-vts",
436 "chromeos-base/factory",
437 "chromeos-base/signingtools-bin",
438 "sys-devel/gcc-bin",
439 ):
440 continue
441 for lib in set(self.provided_libs(pkg)):
442 lookup[lib].add(cpvr)
Allen Webb3350c432023-09-29 11:04:50 -0500443 if self.board is None:
444 self.sdk_lib_to_package_map = lookup
445 self.lib_to_package_map = lookup
446 elif from_sdk:
447 self.sdk_lib_to_package_map = lookup
448 else:
449 self.lib_to_package_map = lookup
450
Allen Webbe8c1da02023-09-08 18:25:22 +0000451 if not lib_filename:
452 return set()
453 try:
454 return lookup[lib_filename]
455 except KeyError:
456 return set()
Allen Webb3e498aa2023-09-05 14:40:49 +0000457
458
459def get_parser() -> commandline.ArgumentParser:
460 """Build the argument parser."""
461 parser = commandline.ArgumentParser(description=__doc__)
462
463 parser.add_argument("package", nargs="*", help="package atom")
464
465 parser.add_argument(
466 "-b",
467 "--board",
468 "--build-target",
469 default=cros_build_lib.GetDefaultBoard(),
470 help="ChromeOS board (Uses the SDK if not specified)",
471 )
472
473 parser.add_argument(
Allen Webb7d34a9a2023-09-18 09:02:15 -0500474 "--no-default-board",
475 dest="board",
476 const=None,
477 action="store_const",
478 help="Ignore the default board",
479 )
480
481 parser.add_argument(
Allen Webbe8c1da02023-09-08 18:25:22 +0000482 "-i",
483 "--build-info",
484 default=None,
485 type=Path,
486 help="Path to build-info folder post src_install",
487 )
488
489 parser.add_argument(
Allen Webb8fc0bba2023-09-11 14:37:25 +0000490 "-x",
491 "--image",
492 default=None,
493 type=Path,
494 help="Path to image folder post src_install (${D} if unspecified)",
495 )
496
497 parser.add_argument(
Allen Webb3e498aa2023-09-05 14:40:49 +0000498 "--match",
499 default=False,
500 action="store_true",
501 help="Try to match missing libraries",
502 )
503
504 parser.add_argument(
505 "-j",
506 "--jobs",
507 default=None,
508 type=int,
509 help="Number of parallel processes",
510 )
511
512 return parser
513
514
515def parse_arguments(argv: List[str]) -> argparse.Namespace:
516 """Parse and validate arguments."""
517 parser = get_parser()
518 opts = parser.parse_args(argv)
Allen Webbe8c1da02023-09-08 18:25:22 +0000519 if opts.build_info and opts.package:
Allen Webb8fc0bba2023-09-11 14:37:25 +0000520 parser.error("Do not specify a package when setting --board-info")
521 if opts.image and not opts.build_info:
522 parser.error("--image requires --board-info")
Allen Webbe8c1da02023-09-08 18:25:22 +0000523 if opts.build_info or len(opts.package) == 1:
Allen Webb3e498aa2023-09-05 14:40:49 +0000524 opts.jobs = 1
525 return opts
526
527
528def check_package(
Allen Webbe8c1da02023-09-08 18:25:22 +0000529 package: portage_util.InstalledPackage,
Allen Webb3e498aa2023-09-05 14:40:49 +0000530 implicit: Set[str],
531 resolver: DotSoResolver,
532 match: bool,
533 debug: bool,
534) -> bool:
535 """Returns false if the package has missing dependencies"""
536 if not package:
Allen Webb473464d2023-09-22 15:35:33 -0500537 print("Package not installed")
Allen Webb3e498aa2023-09-05 14:40:49 +0000538 return False
539
Allen Webb3350c432023-09-29 11:04:50 -0500540 provided, sdk_provided = resolver.get_provided_from_all_deps(package)
Allen Webb3e498aa2023-09-05 14:40:49 +0000541 if debug:
542 print("provided")
Mike Frysinger494c6182023-09-21 11:44:45 -0400543 pprint.pprint(sorted(provided))
Allen Webb3e498aa2023-09-05 14:40:49 +0000544
545 available = provided.union(implicit)
Allen Webb3350c432023-09-29 11:04:50 -0500546 sdk_available = sdk_provided.union(implicit)
547 required, sdk_required = resolver.get_required_libs(package)
Allen Webb3e498aa2023-09-05 14:40:49 +0000548 if debug:
549 print("required")
Mike Frysinger494c6182023-09-21 11:44:45 -0400550 pprint.pprint(sorted(required))
Allen Webb3e498aa2023-09-05 14:40:49 +0000551 unsatisfied = required - available
Allen Webb3350c432023-09-29 11:04:50 -0500552 sdk_unsatisfied = sdk_required - sdk_available
553 cpvr = package.package_info.cpvr
Allen Webb3e498aa2023-09-05 14:40:49 +0000554 if unsatisfied:
Allen Webb473464d2023-09-22 15:35:33 -0500555 print(
556 f"'{cpvr}': Package is linked against libraries that are not "
557 "listed as dependencies in the ebuild:"
558 )
Mike Frysinger494c6182023-09-21 11:44:45 -0400559 pprint.pprint(sorted(unsatisfied))
Allen Webb3e498aa2023-09-05 14:40:49 +0000560 if match:
561 missing = set()
562 for lib in unsatisfied:
Allen Webb3350c432023-09-29 11:04:50 -0500563 missing.update(resolver.lib_to_package(lib, from_sdk=False))
Allen Webb3e498aa2023-09-05 14:40:49 +0000564 if missing:
Allen Webb473464d2023-09-22 15:35:33 -0500565 print(f"'{cpvr}': needs the following added to DEPEND/RDEPEND:")
Mike Frysinger494c6182023-09-21 11:44:45 -0400566 pprint.pprint(sorted(missing))
Allen Webb3350c432023-09-29 11:04:50 -0500567 if sdk_unsatisfied:
568 print(
569 f"'{cpvr}': Package is linked against sdk libraries that are not "
570 "listed as build dependencies in the ebuild:"
571 )
572 pprint.pprint(sorted(sdk_unsatisfied))
573 if match:
574 missing = set()
575 for lib in sdk_unsatisfied:
576 missing.update(resolver.lib_to_package(lib, from_sdk=True))
577 if missing:
578 print(f"'{cpvr}': needs the following added to BDEPEND:")
579 pprint.pprint(sorted(missing))
580
581 return not unsatisfied and not sdk_unsatisfied
Allen Webb3e498aa2023-09-05 14:40:49 +0000582
583
584def main(argv: Optional[List[str]]):
585 """Main."""
Allen Webb3353e152023-09-22 21:00:49 +0000586 commandline.RunInsideChroot()
Allen Webb3e498aa2023-09-05 14:40:49 +0000587 opts = parse_arguments(argv)
588 opts.Freeze()
589
590 board = opts.board
591 root = build_target_lib.get_default_sysroot_path(board)
592 if board:
593 os.environ["PORTAGE_CONFIGROOT"] = root
594 os.environ["SYSROOT"] = root
595 os.environ["ROOT"] = root
596
597 failed = False
598 resolver = DotSoResolver(board, root)
Allen Webb3e498aa2023-09-05 14:40:49 +0000599
600 if not opts.package:
Allen Webbe8c1da02023-09-08 18:25:22 +0000601 if opts.build_info:
Allen Webb8fc0bba2023-09-11 14:37:25 +0000602 pkg = portage_util.InstalledPackage(resolver.db, opts.build_info)
603 image_path = opts.image or os.environ.get("D")
604 if image_path:
605 resolver.cache_libs_from_build(pkg, Path(image_path))
606 packages = [pkg]
Allen Webbe8c1da02023-09-08 18:25:22 +0000607 else:
608 packages = resolver.db.InstalledPackages()
Allen Webb3e498aa2023-09-05 14:40:49 +0000609 else:
Mike Frysinger1e9ac7c2023-09-21 14:53:48 -0400610 packages = []
611 for pkg in opts.package:
612 packages.extend(resolver.get_packages(pkg))
Allen Webb3e498aa2023-09-05 14:40:49 +0000613
614 implicit = resolver.get_implicit_libs()
Allen Webb3e498aa2023-09-05 14:40:49 +0000615
Mike Frysinger329bd332023-09-21 14:18:18 -0400616 if opts.match:
617 # Pre initialize the map before starting jobs.
618 resolver.lib_to_package()
619 for package in packages:
620 if not check_package(
621 package,
622 implicit,
623 resolver,
624 opts.match,
625 opts.debug,
Allen Webb3e498aa2023-09-05 14:40:49 +0000626 ):
Mike Frysinger329bd332023-09-21 14:18:18 -0400627 failed = True
Allen Webb3e498aa2023-09-05 14:40:49 +0000628
629 if failed:
Allen Webb473464d2023-09-22 15:35:33 -0500630 print(
631 """\
632For more information about DEPEND vs. RDEPEND in ebuilds see:
633https://chromium.googlesource.com/chromiumos/docs/+/HEAD/portage/\
634ebuild_faq.md#dependency-types"""
635 )
Allen Webb3e498aa2023-09-05 14:40:49 +0000636 sys.exit(1)
637
638
639if __name__ == "__main__":
640 main(sys.argv[1:])