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

Single source of truth for the Android NDK version Mob's bundled OTP
runtime was cross-compiled against.

The on-device `libbeam.a` (in the `otp-android-*` tarballs) embeds C++
stdlib symbols using libc++'s versioned inline namespace. NDK 27.2
uses `std::__ne180000::`; NDK 25 uses `std::__ne140000::`. These
don't link cross-version: an app's `libpigeon.so` built with the
wrong NDK fails with `undefined symbol: __cxa_allocate_exception`
(or similar libc++ ABI symbols).

This module is consulted by:

  * `mix mob.doctor` — checks the recommended NDK is installed and
    that the project's gradle pin (or override) doesn't drift.
  * `mix mob.install` — same check during onboarding.
  * `mix mob.new`'s gradle template (via `MobNew.NdkVersion`) — sets
    the `ndkVersion` literal so AGP picks deterministically.
  * `scripts/release/openssl/*.sh` — sources `NDK_VERSION` from
    `_lib.sh` so the host-side OpenSSL cross-compile uses the same
    NDK as the bundled tarballs.

## Recommended vs effective

`recommended/0` is the version Mob's tarballs were built against. It
changes only when we cross-compile new tarballs.

`effective/0` returns the recommended version *unless* the user has
overridden it. Two override mechanisms:

  1. **Environment variable** (`MOB_ANDROID_NDK_VERSION=...`) —
     machine-local. Use when one developer needs a specific NDK on
     their box and the team's project config should stay clean.

  2. **Per-project config** in `mob.exs`:

         config :mob_dev,
           android_ndk_version: "25.1.8937393"

     Travels with the project. Use when the whole team needs to
     build against a non-recommended NDK (legacy library
     dependency, hardware-specific toolchain, etc).

Precedence: env var > mob.exs > recommended.

## Override caveat

When an override is active the user opts out of the libc++ ABI
guarantee against the bundled tarballs. They're navigating that
alone — `mob.doctor` warns but does not fail. Cryptic link errors
against `libbeam.a` are then their problem to debug. See
`~/code/mob/common_fixes.md` "NDK 27 / clang 18 split libc++"
for the symptom and the diagnostic.

# `effective`

```elixir
@spec effective() :: String.t()
```

The NDK version the user's build should target.

Returns `recommended/0` unless overridden via `MOB_ANDROID_NDK_VERSION`
env var or `:android_ndk_version` in `mob.exs`'s `:mob_dev` config.

# `install_command`

```elixir
@spec install_command() :: String.t()
```

Build the suggested install command for the recommended NDK. Used by
`mob.doctor` and `mix mob.install` to give the user a one-liner.

# `installed?`

```elixir
@spec installed?(String.t()) :: boolean()
```

True if the given NDK version is installed under the local Android SDK.

Looks for `<sdk>/ndk/<version>/source.properties` since the directory
alone can be a half-extracted partial install.

# `installed_versions`

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

Returns all NDK versions present under the local SDK, newest-first by
string sort.

# `override`

```elixir
@spec override() :: {:env | :mob_exs, String.t()} | :none
```

Returns `{:env, version}`, `{:mob_exs, version}`, or `:none`
describing which override mechanism is active (if any).

Used by `mob.doctor` to explain *why* the effective version differs
from the recommendation.

# `project_pinned`

```elixir
@spec project_pinned(String.t()) :: String.t() | nil
```

Reads the project's `android/app/build.gradle` (or `.kts`) for the
`ndkVersion` literal. Returns the string or `nil` if not pinned.

Accepts an optional project root; defaults to the current working
directory.

# `recommended`

```elixir
@spec recommended() :: String.t()
```

The NDK version the bundled OTP tarballs were cross-compiled with.

# `recommended_install_path`

```elixir
@spec recommended_install_path() :: String.t() | nil
```

Returns the absolute path to the recommended NDK install if present,
or `nil`.

---

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