mix mob.add_nif (mob_dev v0.5.7)

Copy Markdown View Source

Scaffolds a new statically-linked NIF in the current Mob project.

mix mob.add_nif <name>                   # default: --type elixir-only
mix mob.add_nif <name> --type c          # also drops c_src/<name>.c skeleton
mix mob.add_nif <name> --type zigler     # Zigler-backed (inline ~Z)
mix mob.add_nif <name> --type rustler    # Rustler-backed (Cargo crate at native/<name>/)
mix mob.add_nif <name> --module MyApp.Nifs.Audio   # custom Elixir module name

Three things change after a successful run:

  • lib/<app>/nifs/<name>.ex — Elixir stub module exporting the NIF function placeholders. Each function returns :erlang.nif_error/1 so the BEAM raises a clear "NIF not loaded" error if the native side hasn't loaded yet, instead of silently returning the stub's body.

  • mob.exs:static_nifs list under config :mob_dev, gains %{module: :<name>, archs: [:all]}. If :static_nifs doesn't exist yet the entry creates it. The schema lives in MobDev.StaticNifs — see its module doc for arch values and per-arch guards.

  • (with --type c) c_src/<name>.c — a minimal C skeleton with the ERL_NIF_INIT macro pre-wired to the registered name. Wire it into your build (Android CMakeLists.txt or iOS build.zig) by adding the file to the static archive that links into libbeam.a.

mix mob.regen_driver_tab is composed into the same Igniter run, so priv/generated/driver_tab_{ios,android}.c updates appear in the same diff as the stub and mob.exs edit. One command, everything wired.

Why a static NIF and not a dlopen'd .so

iOS App Store rejects bundled .dylib files. Android's loader uses RTLD_LOCAL by default, which hides enif_* symbols from a dlopen'd child library. Both platforms force the same answer: link the NIF init function into the main binary alongside the BEAM, and register it in the static NIF table at link time. See MobDev.StaticNifs for the full rationale.

Phase 3 of the build-system migration

This task is the first Igniter-backed surface in mob_dev — it validates the AST-aware code-generation approach before the heavier Phase 4 (mob.enable migration) and Phase 5 (mob.new --liveview rewrite) follow.