ledger_secure_sdk_sys 1.16.2

Bindings to Ledger C SDK
# `build.rs` Process

Flow executed by `build.rs`. `main()` first emits a fixed set of
`cargo:rerun-if-*` directives that tell Cargo which inputs invalidate the
build cache, then runs 8 sequential phases on an `SDKBuilder`. Each phase
reads particular inputs and produces specific outputs — env vars exported
to rustc, files in `$OUT_DIR`, or compiled C objects.

```
 ┌─────────────────────────────────────────────────────────────────────────┐
 │ main() prelude: emit cargo:rerun-if-* directives for every tracked      │
 │ input — LEDGER_SDK_PATH, {DEV}_SDK fallbacks, HEAP_SIZE,                 │
 │ LEDGER_SDK_EXTRA_{DEFINES,CFLAGS}, CC, plus devices/, link.ld, src/c/*. │
 │ Emitted up-front so cache-invalidation fires even if a later phase      │
 │ panics. cc::Build and bindgen::CargoCallbacks add their own             │
 │ rerun-if-changed entries for the C/header files they consume.           │
 └────────────────────────────┬────────────────────────────────────────────┘
                            ┌─────────────────────────────┐
 INPUTS (env + filesystem)  │       SDKBuilder::new()     │   OUTPUTS
                            └──────────────┬──────────────┘
 ┌─────────────────────────┐  ┌────────────▼────────────┐
 │ `arm-none-eabi-gcc      │─▶│ 1. gcc_toolchain()      │  self.gcc_toolchain
 │   -print-sysroot`       │  │    (fallback:           │   = <sysroot PathBuf>
 │ (or /usr/lib/arm-       │  │     /usr/lib/arm-…)     │
 │   none-eabi)            │  └────────────┬────────────┘
 └─────────────────────────┘               │
 ┌─────────────────────────┐  ┌────────────▼────────────┐
 │ CARGO_CFG_TARGET_OS     │  │ 2. device()             │  cargo:rustc-env=
 │   ∈ {nanox, nanosplus,  │  │  ─ find DeviceSpec in   │     TARGET=<name>
 │       stax, flex,       │  │    static SPECS table   │     C_SDK_GRAPHICS=
 │       apex_p}           │  │  ─ read .defines file   │       nbgl | bagl
 │ LEDGER_SDK_PATH (or     │─▶│    (header2define)      │
 │   {DEV}_SDK fallback)   │  │  ─ read .cflags file    │  self.device fully
 │ CARGO_FEATURE_NANO_NBGL │  │    (read_lines)         │     populated:
 │ devices/<dev>/*.defines │  │  ─ derive glyph folders │     name, c_sdk path,
 │ devices/<dev>/*.cflags  │  │    from spec            │     target triple,
 │ devices/<dev>/*.ld      │  │  ─ derive arm_libs path │     defines, cflags,
 │ (all reached via the    │  │    (st33 vs st33k1)     │     glyph folders,
 │  DeviceSpec helpers)    │  │  ─ pick linker_script   │     arm_libs,
 │                         │  │    devices/<dev>/*.ld   │     linker_script
 └─────────────────────────┘  └────────────┬────────────┘
 ┌─────────────────────────┐  ┌────────────▼────────────┐
 │ <c_sdk>/Makefile.defines│  │ 3. get_info()           │  cargo:rustc-env=
 │ <c_sdk>/Makefile.target │  │  retrieve_csdk_info():  │   API_LEVEL
 │ <c_sdk>/target/<dev>/   │─▶│   ├─ Makefile.* parse   │   TARGET_ID
 │   include/bolos_target.h│  │   ├─ bolos_target.h     │   TARGET_NAME
 │ git describe (in c_sdk) │  │   └─ git describe       │   C_SDK_NAME
 │                         │  │                         │   C_SDK_HASH
 │                         │  │                         │   C_SDK_VERSION
 └─────────────────────────┘  └────────────┬────────────┘
 ┌─────────────────────────┐  ┌────────────▼────────────┐
 │ <c_sdk>/Makefile.conf.cx│─▶│ 4. cxdefines()          │  self.cxdefines
 │   (HAVE_* tokens)       │  │  + NATIVE_LITTLE_ENDIAN │   (Vec<String>)
 └─────────────────────────┘  └────────────┬────────────┘
 ┌─────────────────────────┐  ┌────────────▼─────────────┐
 │ AUX_C_FILES (2 files)   │  │ 5. build_c_sdk()         │
 │ SDK_C_FILES (12 files)  │  │   cc::Build (CC=clang)   │
 │ <c_sdk>/include/…       │  │     compiler, target,    │
 │ <c_sdk>/io/…            │  │     includes, defines,   │
 │ <c_sdk>/lib_cxng/…      │  │     cflags               │
 │ <c_sdk>/lib_ux/…        │  │                          │
 │ <c_sdk>/lib_bagl/…      │  │   ┌────────────────────┐ │  libledger-secure-
 │ <c_sdk>/lib_nbgl/…      │─▶│   │ generate_glyphs(): │ │   sdk.a built into
 │ <c_sdk>/lib_stusb/…     │  │   │  if device.is_nbgl │ │   $OUT_DIR
 │ <c_sdk>/lib_blewbxx/…   │  │   │   → icon2glyph.py  │ │
 │ <c_sdk>/lib_u2f/…       │  │   │  else (BAGL)       │ │  $OUT_DIR/glyphs/
 │ ./src/c/src.c, sjlj.s   │  │   │   → icon3.py       │ │   {glyphs.c,glyphs.h}
 │ LEDGER_SDK_EXTRA_DEFINES│  │   │  → glyphs.{c,h}    │ │
 │ LEDGER_SDK_EXTRA_CFLAGS │  │   └─────────┬──────────┘ │  cargo:rustc-link-
 │ CARGO_FEATURE_DEBUG_CSDK│  │             │            │   lib=c
 │                         │  │   if HAVE_IO_USB   →     │  cargo:rustc-link-
 │                         │  │     configure_lib_usb    │   search=<arm_libs>
 │                         │  │   if HAVE_BLE      →     │
 │                         │  │     configure_lib_ble    │
 │                         │  │   if HAVE_NBGL     →     │
 │                         │  │     configure_lib_nbgl   │
 │                         │  │   if HAVE_BAGL     →     │
 │                         │  │     add glyphs.c         │
 │                         │  │   if HAVE_IO_U2F   →     │
 │                         │  │     configure_lib_u2f    │
 │                         │  └────────────┬─────────────┘
 │                         │               │
 │                         │  ┌────────────▼─────────────┐
 │                         │  │ 6. generate_bindings()   │
 │                         │  │   bindgen::builder()     │
 │                         │  │     clang_args + headers │
 │                         │  │     (libcxng.h, os.h,    │  $OUT_DIR/bindings.rs
 │                         │─▶│      syscalls.h, os_ux,  │  (CargoCallbacks adds
 │                         │  │      swap_lib_calls,     │   rerun-if-changed)
 │                         │  │      os_pki, os_hdkey,   │
 │                         │  │      + nbgl_use_case OR  │
 │                         │  │        bagl headers      │
 │                         │  │      — driven by         │
 │                         │  │      device.is_nbgl())   │
 └─────────────────────────┘  │     + cxdefines as -D    │
                              └────────────┬─────────────┘
 ┌─────────────────────────┐  ┌────────────▼────────────┐
 │ HEAP_SIZE env var       │  │ 7. generate_heap_size() │  $OUT_DIR/heap_size.rs
 │   "8192" or             │─▶│  parse & clamp to       │   (pub const
 │   "nanosplus:8192,…"    │  │  [2048, max_per_device] │    HEAP_SIZE: usize)
 │ default = 8192          │  │                         │
 └─────────────────────────┘  └────────────┬────────────┘
 ┌─────────────────────────┐  ┌────────────▼────────────┐
 │ devices/<dev>/<dev>_    │  │ 8. copy_linker_script() │  $OUT_DIR/<dev>_layout.ld
 │   layout.ld             │─▶│                         │  $OUT_DIR/link.ld
 │ ./link.ld               │  │                         │  cargo:rustc-link-
 └─────────────────────────┘  └────────────┬────────────┘   search=$OUT_DIR
                              if LEDGER_SDK_BUILD_TIMING is set:
                              total build.rs time printed via
                              `cargo:warning=…` (off by default)
```

## Notes

- **C compiler**: `cc::Build` is told to use `clang` (cross-compiling via the
  `--target` flag) unless `CC` is set in the environment — it is **not**
  invoking `arm-none-eabi-gcc` directly for compilation. The ARM GCC toolchain
  is used only for its sysroot headers and the prebuilt `libc.a` linked from
  `arm_libs`.
- **`#define main _start`**: silently renames the C SDK's `main` so Rust's
  `_start` (defined in `ledger_device_sdk/src/lib.rs`) becomes the real entry
  point.
- **Single source of truth for per-device config**: everything that differs
  between the five devices (target triple, env-var fallback, ARM lib subdir,
  NBGL glyph folders, `.defines`/`.cflags`/`_layout.ld` filenames) lives in
  the static `SPECS: &[DeviceSpec]` table. `device()` looks up the spec for
  the current `CARGO_CFG_TARGET_OS` and derives everything else; `Device::spec()`
  lets later phases reach the spec from a `Device` value.
- **NBGL vs BAGL is a property of `Device`**: `Device::is_nbgl()` returns
  true for Stax/Flex/ApexP, and for Nano devices when the `nano_nbgl` feature
  is on. It is the single source of truth used by `device()` (which `HAVE_*`
  defines to inject, which glyph folders to use), `generate_glyphs()` (which
  Python helper to invoke), and `generate_bindings()` (which lib_nbgl vs
  lib_bagl headers to bind against). `C_SDK_GRAPHICS=nbgl|bagl` is emitted
  once at the end of `device()`.
- **Per-feature branching in `build_c_sdk`**: the `for s in
  self.device.defines.iter()` loop conditionally pulls in USB/BLE/NBGL/U2F
  sources based on which `HAVE_*` defines the device's `.defines` file
  declared (`cxdefines` from `Makefile.conf.cx` is shared across all devices).
- **`infos.rs`** (referenced by the `cargo:rustc-env=…` lines in steps 2 and
  3) consumes `TARGET`, `API_LEVEL`, `TARGET_ID`, `TARGET_NAME`, `C_SDK_NAME`,
  `C_SDK_HASH`, `C_SDK_VERSION`, `C_SDK_GRAPHICS` at compile time and emits
  the ELF metadata sections (`ledger.target`, `ledger.api_level`, …) that
  `cargo-ledger` later reads.
- **Error handling**: `build.rs` doesn't carry a typed error type — each
  phase either succeeds, returns its payload directly, or panics with a
  message describing what went wrong (build scripts fail the build on
  panic, which is the desired behavior for misconfiguration).