← board

nilpy includes anything from ESP-IDF and it just works

The goal (one sentence)

Write an app in nilpy, include any ESP-IDF header, call what it declares, build a target .o, let IDF link + flash — and it works — without hand-writing bindings per API.

nilpy app  ──┐
IDF headers ─┤  OUR COMPILER  ──►  main.o (relocatable xtensa/riscv32 ELF)
             │   • parse headers (decls, structs, macros, consts)            │
             │   • compile YOUR code → target machine code                   │
             │   • compile static-inline bodies you USED                     │
             │   • emit ABI calls + UNDEFINED refs for IDF extern symbols    ▼
             └─────────────────────────────────────────►  IDF TOOLCHAIN
                                                            • link .o + IDF .a
                                                            • linker script,
                                                              IRAM/DRAM place
                                                            • firmware + flash

What this milestone needs (dependency chain, by symbol kind)

IDF construct requirement where it lives
extern function (in IDF .a) ABI call + undefined ref feature-esp32-idf-xtensa plumbing + existing FFI
static inline (HAL/LL: *_ll.h, *_hal.h) compile the body feature-c-source-frontend Slices A–C
function-like macros (ESP_LOGI, BIT(x), REG_WRITE, portTICK_PERIOD_MS) expand + compile feature-c-source-frontend Slice E
register structs (soc/*_reg.h, *_struct.h: bitfields + volatile) honor packed/aligned/bitfield/volatile feature-c-source-frontend Slice F
struct/enum/#define consts model layout + values header import (mature)
arbitrary header tree (FreeRTOS + soc + hal + driver + esp_common, keyed on sdkconfig.h) robust import / graceful degrade new work — see below
nilpy untyped surface infer types from imported C signatures new work — see below

The C-frontend slices E, F, and A–C-for-static-inline are the IDF-critical ones (vs nice-to-have for desktop C). This ticket is the reason they matter.

New work owned by THIS ticket (beyond the dependencies)

  1. IDF header-import robustness. IDF's transitive #include tree is GTK-grade macro soup, gated on a Kconfig-generated sdkconfig.h. Need: include-path resolution into the IDF component tree, sdkconfig.h ingestion, and graceful-degrade (opaque fallback) on constructs we can't model while still exposing the symbols/inlines actually called. Reuse the GTK degrade-gracefully strategy (c-skipped-features-audit.md).
  2. nilpy FFI type inference. nilpy is untyped at the surface; infer argument and result types from the imported C signatures so gpio_set_level(pin, 1) type-checks and lowers with the right ABI without a hand-written binding. Builds on the callee-return inference + auto string→const char* already landed (wrapper-free-c-from-nil-python.md); extend to IDF-shaped APIs.
  3. nilpy app_main entry into the IDF component model (the existing IDF tickets wire a Pascal app_main; do the nilpy equivalent).

Non-goals

Acceptance

A nilpy program that includes an arbitrary IDF header (not a curated subset) and:

Log