MobDev.Plugin.Prebuilt (mob_dev v0.7.22)

Copy Markdown View Source

Fetches the prebuilt bundle a lang: :cpp_archive plugin NIF declares under :prebuilt, and resolves the headers and static libraries it contributes.

Some plugin NIFs sit on a large third-party C++ library that ships prebuilt: mob_scene3d's iOS renderer is Objective-C++ against Filament, whose release tarball carries the headers plus one static-library xcframework per component. That can't ride in a Hex package (tens of MB), and the plugin's own .a (MobDev.Plugin.CppArchive) only holds objects compiled from its sources. A cpp_archive entry therefore names the bundle and what to take from it:

%{
  module: :mob_scene3d_nif,
  lang: :cpp_archive,
  platform: :ios,
  sources: ["priv/native/ios/mob_scene3d_nif.m", "priv/native/ios/MobScene3dView.mm"],
  includes: ["priv/native/ios", {:prebuilt, "filament/include"}],
  nm_symbol: "mob_scene3d_nif_nif_init",
  prebuilt: %{
    url: "https://github.com/google/filament/releases/download/v1.75.1/filament-v1.75.1-ios.tgz",
    sha256: "afdfdccfb0870a667c73400d9e81e5ec69c8604d867fc4430b9fbfe72934ade3",
    static_libs: %{
      ios_sim: ["filament/lib/libfilament.xcframework/ios-arm64_x86_64-simulator/libfilament.a"],
      ios_device: ["filament/lib/libfilament.xcframework/ios-arm64/libfilament.a"]
    }
  }
}
  • {:prebuilt, subpath} in :includes is a directory inside the extracted bundle, passed to the compiler as -I.
  • :static_libs maps a CppArchive target id to archives inside the bundle. They are linked into the app beside lib<module>.a, through the same -Dplugin_static_libs / MOB_PLUGIN_STATIC_LIBS inputs, so the simulator and device deploys and mix mob.release --ios all link them.

The bundle is downloaded once per sha256 into ~/.mob/cache/plugin-prebuilt/ (or $MOB_CACHE_DIR/plugin-prebuilt/) and shared by every project, the MobDev.MLXDownloader pattern. The tarball must hash to the manifest's sha256 before anything is extracted: the manifest is covered by the plugin signature, so the pin carries that trust to a file the signature cannot cover.

Offline builds and mirrors

Set MOB_PLUGIN_PREBUILT_DIR=/path/to/dir to take each tarball from <dir>/<file name of the url> instead of downloading it. The sha256 is checked all the same.

Summary

Types

t()

A cpp_archive entry's :prebuilt map.

Functions

A path inside an extracted bundle: relative, no .. component. Pure.

Cache directory for a bundle: <cache>/plugin-prebuilt/<name>-<sha256 prefix>, where <name> is the URL's file name without its tarball extension. Keyed by the hash, so a manifest that pins a new file gets a new directory. Pure apart from reading MOB_CACHE_DIR / HOME.

Ensure the bundle is downloaded, verified and extracted. Returns {:ok, dir} (see dir/1). A cached extraction is reused only when it records the same sha256; anything else in its place is removed and fetched again.

Structural problems with a :prebuilt map, as messages (empty when it is well formed): the URL must be https, the sha256 64 lowercase hex characters, and :static_libs a map of CppArchive targets to relative paths that stay inside the bundle. MobDev.Plugin.Manifest.validate/1 reports these, and prepare/2 refuses a bundle that has any, since a host build does not run manifest validation. Pure.

Make a Merge.static_archives/2 spec ready for CppArchive.build/3 on target_id: fetch its prebuilt bundle (when it declares one), resolve {:prebuilt, _} includes, and return the bundle archives to link.

Replace each {:prebuilt, subpath} include with its path under root; other entries pass through unchanged. Pure.

The bundle's archives to link for target_id, as absolute paths under root. A target the manifest doesn't list links none. Pure.

Types

t()

@type t() :: %{
  :url => String.t(),
  :sha256 => String.t(),
  optional(:static_libs) => %{optional(atom()) => [String.t()]}
}

A cpp_archive entry's :prebuilt map.

Functions

bundle_relative?(path)

@spec bundle_relative?(term()) :: boolean()

A path inside an extracted bundle: relative, no .. component. Pure.

dir(map)

@spec dir(t()) :: Path.t()

Cache directory for a bundle: <cache>/plugin-prebuilt/<name>-<sha256 prefix>, where <name> is the URL's file name without its tarball extension. Keyed by the hash, so a manifest that pins a new file gets a new directory. Pure apart from reading MOB_CACHE_DIR / HOME.

ensure(prebuilt)

@spec ensure(t()) :: {:ok, Path.t()} | {:error, String.t()}

Ensure the bundle is downloaded, verified and extracted. Returns {:ok, dir} (see dir/1). A cached extraction is reused only when it records the same sha256; anything else in its place is removed and fetched again.

errors(prebuilt)

@spec errors(term()) :: [String.t()]

Structural problems with a :prebuilt map, as messages (empty when it is well formed): the URL must be https, the sha256 64 lowercase hex characters, and :static_libs a map of CppArchive targets to relative paths that stay inside the bundle. MobDev.Plugin.Manifest.validate/1 reports these, and prepare/2 refuses a bundle that has any, since a host build does not run manifest validation. Pure.

prepare(spec, target_id)

@spec prepare(map(), atom()) :: {:ok, map(), [Path.t()]} | {:error, String.t()}

Make a Merge.static_archives/2 spec ready for CppArchive.build/3 on target_id: fetch its prebuilt bundle (when it declares one), resolve {:prebuilt, _} includes, and return the bundle archives to link.

Returns {:ok, spec, link_libs}; a spec without :prebuilt comes back unchanged with []. Fails, with a message, on a malformed :prebuilt or include, a failed download, hash or extraction, or a listed archive missing from the bundle.

resolve_includes(includes, root)

@spec resolve_includes([term()], Path.t()) :: [term()]

Replace each {:prebuilt, subpath} include with its path under root; other entries pass through unchanged. Pure.

static_libs(prebuilt, target_id, root)

@spec static_libs(t(), atom(), Path.t()) :: [Path.t()]

The bundle's archives to link for target_id, as absolute paths under root. A target the manifest doesn't list links none. Pure.