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 nameThree 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/1so 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_nifslist underconfig :mob_dev,gains%{module: :<name>, archs: [:all]}. If:static_nifsdoesn't exist yet the entry creates it. The schema lives inMobDev.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 intolibbeam.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.