← board

C conformance / feature coverage on ESP (xtensa + ESP32-C3 riscv32 bare)

Scope

Notes

2026-09-24 — C3 wired; three walls in front of it removed (frankS)

Owner: "c-conformance is desired". Getting any C program to RUN under ESP-IDF took three fixes first, all measured on esp32c3 under QEMU:

  1. main never ran. The ESP object writer exports app_main at .text+0, where Pascal puts its body; C put nothing there, so IDF called whatever routine came first (a three-argument helper, in the case measured). True in pinned v416 as well: C through the IDF route had built and never executed. riscv32 ESP objects now get a C entry stub at offset 0 (a fake zeroed initial stack, the initializer shell, main(0, argv) or the source's own app_main, the finalizers, return to IDF).
  2. crtl collided with picolibc. 41 of 323 exported globals, plus errno (TLS in IDF). crtl is now private in an ESP object (ObjRuntimeIsPrivate): local code, no exported state; it reaches IDF through the PAL, as the Pascal RTL does. Whether ESP C should use IDF's libc instead is an OPEN owner question -- his lean, 2026-09-24: "it makes most sense to just use IDF's libraries ... but i'm not sure ... it's a choice - wrap it and keep best portability, or dont wrap it but programmer must be aware". This is the "wrap it" arm; do not start the other without his call.
  3. stdout went nowhere. The ESP PAL refused fds 0-2; they now go through picolibc's putchar/getchar exactly as builtinheap's PXXIdfStdWrite does.

Two smaller ones the run found: an unreferenced extern int x; was refused as a data import (00094.c; now only an import something READS is refused), and the 1 MiB stock app partition overflowed on 00200.c (the harness's private project copy takes IDF's 1.5 MiB single-app table).

Harness controls: a wrong-output, a nonzero-return and a null-store row each FAIL for the right reason, and a correct row passes; a missing suite is exit 2, not SKIP-and-0. Numbers: 216 rows at compiler sha a23e896320ec, the three re-runs (00094, 00200, 00187) at 131ae6c99230, which differs only by the import-refusal change.

Side findings. Filed: bug-c-a-c-call-to-an-external-variadic-function-on-esp-riscv32-reaches-it-without-its-arguments (esp_rom_printf from C prints nothing). Noted, not filed: --target=esp32c3 alone builds a HOSTED-linux object (0 undefined symbols), not an IDF one -- use --target=riscv32 --platform=esp, as tools/esp_run.sh does. And 00207.c (VLA) PASSES here while pxx.skip.riscv32 skips it as "alloca is x86-64 only" -- that skip may be stale; not re-measured on the desktop riscv32 leg.

2026-09-24 (frankS): the esp32s3 leg

Harness gained --chip esp32s3 (hello-s3, --target=xtensa --xtensa-abi=windowed --platform=esp, qemu-system-xtensa), a comma list for --only, a 24-line diff, and C99's fall-off-main rule applied for a test whose main has no return (the rename to pxx_conf_main takes it out of the compiler's own rule; exactly 00206/00211/00212 in the suite, census by script).

First full s3 run, compiler 17be23f99ad8: 209 pass / 10 fail / 1 skip. The nine non-00053 reds were five real xtensa bugs plus the harness artefact, fixed and re-run at f8f9d3f827d3 (see done/feature-a-variadic-c-functions-on-the-windowed-xtensa-abi). 216/3/1 is therefore 211 rows at 17be23f99ad8 and 9 at later binaries whose diffs are the fixes named there; a clean single-binary full run has NOT been done. esp32c3 re-checked on a 5-test subset at f8f9d3f827d3, all pass.

2026-09-24 (frankS): the clean run

One binary, one tree: 5b95400c1a == origin, compiler sha256 41013170dc747df106e246fc429e6262509f8518fc72de3ea88069761b3ac29e. Sharded 3 + 3 concurrently while two other seats were building (load avg ~11-12 on 12 threads).

chip concurrent solo re-run of the fails
esp32c3 217 / 2 / 1 -- 00053 (compile), 00040 (Interrupt wdt crash) 00040 PASS 3/3
esp32s3 217 / 2 / 1 -- 00053 (compile), 00207 (alloca, compile) deterministic compile errors, not re-run

So c3 = 218/1/1 and s3 = 217/2/1, with 00040's concurrent crash recorded as a LOAD ARTEFACT (it had already tripped at 10 QEMUs in an aborted earlier run). The harness header now says so. An earlier attempt at 563f6937f9 was abandoned midway because a push pulled compiler/builtin/builtinheap.pas, a per-program compile input, into the tree under the s3 half; the compiler binary sha did not change, which is why the binary sha alone would not have caught it.