# `MobDev.TfliteNif`
[🔗](https://github.com/genericjam/mob_dev/blob/master/lib/mob_dev/tflite_nif.ex#L1)

Cross-compiles `tflite_nif.c` (the NIF wrapping TensorFlow Lite's C API)
for one Android or iOS target ABI and archives the result as
`libtflite_nif.a`. The archive gets static-linked into the user app's
main native binary alongside `crypto.a`, `libemlx.a`, and any other
static NIFs.

## Companion bits

* **Native libs** — `MobDev.TfliteDownloader` fetches the TFLite native
  libraries (AAR for Android, xcframework tarball for iOS) and supplies
  headers + the runtime library that gets linked into the launcher
  binary alongside this archive.
* **C source** — `tflite_nif.c` ships in the `:nx_tflite_mob` Hex dep
  (the user adds `{:nx_tflite_mob, ...}` to their `mix.exs` when they
  run `mix mob.enable tflite`). This module looks it up via
  `:code.lib_dir(:nx_tflite_mob)`.
* **Static-NIF table entry** — `:tflite_nif` is registered in
  `MobDev.StaticNifs.default_nifs/0` with guard `MOB_STATIC_TFLITE_NIF`.
  The guard threads into `build_device.zig` as `tflite_static` and is
  set to `true` when the project enables this feature.

## Why static-link this NIF?

Same constraints as every other NIF mob ships on phones:

  * **Android.** `dlopen`'d children inherit `RTLD_LOCAL`, hiding the
    parent's `enif_*` symbols from a separately-loaded `libtflite_nif.so`.
    `on_load` then fails with "cannot locate symbol". Static linking
    sidesteps that — BEAM finds `tflite_nif_nif_init` via
    `dlsym(RTLD_DEFAULT)` against the main app binary.
  * **iOS.** App Store forbids loading unsigned dylibs / `dlopen`; every
    NIF must already be present in the signed binary.

The TFLite runtime itself (`libtensorflowlite_jni.so` on Android,
`TensorFlowLiteC.framework` on iOS) IS allowed to load via the normal
dynamic-linker path: it's code-signed (iOS) or part of the standard
jniLibs/ contract (Android). Only the NIF init has to be static.

## Per-target deltas

| Target        | Source              | Compiler             | nm symbol            |
|---------------|---------------------|----------------------|----------------------|
| android_arm64 | NDK aarch64 clang   | aarch64 cross        | `tflite_nif_nif_init` |
| android_arm32 | NDK arm clang       | arm cross (armv7-a)  | `tflite_nif_nif_init` |
| ios_sim       | xcrun iphonesimulator | arm64-apple-ios-simulator | `_tflite_nif_nif_init` |
| ios_device    | xcrun iphoneos      | arm64-apple-ios      | `_tflite_nif_nif_init` |

## STATIC_ERLANG_NIF_LIBNAME

We pass `-DSTATIC_ERLANG_NIF_LIBNAME=tflite_nif` to make `ERL_NIF_INIT`
emit symbol `tflite_nif_nif_init`. That matches the convention used by
`MobDev.NxEigenNif` (`nx_eigen` → `nx_eigen_nif_init`) and what
`MobDev.StaticNifs.init_fn/1` derives for the `:tflite_nif` module
entry.

# `base_cflags`

```elixir
@spec base_cflags() :: [String.t()]
```

Base CFLAGS shared across all targets. Public for testing.

# `build`

```elixir
@spec build(
  atom(),
  keyword()
) :: {:ok, map()} | MobDev.Release.Errors.t()
```

Compile + archive + verify `libtflite_nif.a` for one target.

Options:
  * `:nx_tflite_mob_dir` — path to the `:nx_tflite_mob` Hex dep (the
    dir containing `c_src/tflite_nif.c`). **Required.**
  * `:tflite_dir` — path returned by `MobDev.TfliteDownloader.ensure/1`
    for this target. **Required.**
  * `:erts_include` — per-target `erts-VSN/include/` dir. **Required.**
  * `:out_dir` — where the archive + object subdir get written.
    **Required.**
  * `:ndk_root` — Android NDK root (Android targets only; defaults to
    `~/Library/Android/sdk/ndk/<NdkVersion.effective()>`).

# `cflags`

```elixir
@spec cflags(
  %MobDev.TfliteNif.Target{
    extra_cflags: term(),
    id: term(),
    nm_symbol: term(),
    tools_fn: term()
  },
  [Path.t()],
  [Path.t()]
) :: [String.t()]
```

Assemble full CFLAGS for a target plus include / framework search paths.

`includes` are `-I`-prefixed; `frameworks` are `-F`-prefixed (iOS only —
ignored on Android targets). Order is preserved.

# `target_spec`

```elixir
@spec target_spec(atom()) :: %MobDev.TfliteNif.Target{
  extra_cflags: term(),
  id: term(),
  nm_symbol: term(),
  tools_fn: term()
}
```

Per-target spec. Public for testing.

# `targets`

```elixir
@spec targets() :: [atom()]
```

All known TFLite NIF targets.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
