NBPR.Artifact.LibCheck (NBPR v0.2.1)

Copy Markdown View Source

Firmware-time shared-library resolution check.

After mix nbpr.fetch stages every nbpr package into its priv/, this finds DT_NEEDED shared libraries that a package's binaries link against but that nothing in the assembled firmware provides — surfacing the whole list in one build instead of one missing .so per device boot.

"Provided" is resolved exactly as the dynamic loader would: a soname is satisfied if a file of that name exists on the runtime library path. That path is the union of:

  • the base system's libraries (<system>/staging/{lib,usr/lib,...}), and
  • every nbpr package's own priv/{usr/lib,lib}NBPR.Application prepends these to LD_LIBRARY_PATH at boot, so a library shipped by a sibling nbpr package counts as provided.

So the check is firmware-wide: a soname nbpr_cryptsetup needs from nbpr_popt resolves as long as nbpr_popt is also in the firmware.

Summary

Functions

The base system's existing library directories under system_path's staging/ tree, or [] when system_path is nil or none exist.

Returns [{app, [missing_soname]}] for staged packages with at least one unresolved DT_NEEDED. Empty list when everything resolves.

The set of soname filenames present across dirs — the dynamic loader's notion of "provided".

Pure diff: given each package's required sonames and the provided set, returns [{app, sorted_missing}] for packages with anything unresolved.

Functions

base_lib_dirs(system_path)

@spec base_lib_dirs(Path.t() | nil) :: [Path.t()]

The base system's existing library directories under system_path's staging/ tree, or [] when system_path is nil or none exist.

missing(base_lib_dirs, packages)

@spec missing([Path.t()], [{atom(), Path.t()}]) :: [{atom(), [String.t()]}]

Returns [{app, [missing_soname]}] for staged packages with at least one unresolved DT_NEEDED. Empty list when everything resolves.

base_lib_dirs are the base system's library directories; packages is a list of {app, priv_dir} for the staged nbpr packages.

provided_sonames(dirs)

@spec provided_sonames([Path.t()]) :: MapSet.t()

The set of soname filenames present across dirs — the dynamic loader's notion of "provided".

unresolved(required_by_app, provided)

@spec unresolved([{atom(), [String.t()]}], MapSet.t()) :: [{atom(), [String.t()]}]

Pure diff: given each package's required sonames and the provided set, returns [{app, sorted_missing}] for packages with anything unresolved.