Skip to content
This repository was archived by the owner on Sep 19, 2026. It is now read-only.
This repository was archived by the owner on Sep 19, 2026. It is now read-only.

bindgen fails parsing portmacro.h critical-section macros under ESP-IDF v6.0 (xtensa, macOS) #418

Description

@mh0pe

Summary

Fresh cargo build of an ESP-IDF v6.0 firmware on macOS aborts at the esp-idf-sys bindgen step with:

clang diagnosed error:
  components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h:443:75:
    error: too few arguments to function call,
           single argument 'mux' was not specified
  portmacro.h:552:51: note: 'vPortEnterCritical' declared here
  portmacro.h:444:74: error: too few arguments to function call,
           single argument 'mux' was not specified
  portmacro.h:230:6: note: 'vPortExitCritical' declared here

Error: failed to generate bindings in file
  '.../target/xtensa-esp32s3-espidf/release/build/esp-idf-sys-*/out/bindings.rs'

Column 75 of line 443 is the closing ) of vPortEnterCritical(mux) inside the macro definition body:

#define portENTER_CRITICAL(mux)                     vPortEnterCritical(mux)
#define portEXIT_CRITICAL(mux)                      vPortExitCritical(mux)

clang appears to be evaluating the macro body as a function-call expression against the forward declaration of static inline void __attribute__((always_inline)) vPortEnterCritical(portMUX_TYPE *mux); (portmacro.h:215). mux (the macro parameter) doesn't resolve as a C identifier in that context, so clang sees vPortEnterCritical() with zero args and errors on the arity mismatch.

Environment

  • Host: macOS 25.3.0 (Darwin), arm64
  • esp-idf-sys: v0.38.0 (current) — also tested with patched vendor/esp-idf-sys carrying our local v6.0 forward-port patches (no relevant diff in the bindgen invocation)
  • embuild: 0.33.1
  • bindgen: tested 0.69.5, 0.71.1, 0.72.1 — all three produce identical errors
  • libclang: tested all three available on this Mac:
    • Homebrew llvm (clang 22.1.2)
    • Homebrew llvm@20 (clang 20.1.8)
    • ~/.rustup/toolchains/esp/xtensa-esp32-elf-clang/esp-20.1.1_20250829/esp-clang/lib/libclang.dylib (xtensa-aware esp-clang)
    • All three produce identical errors once the freertos sub-include path is on the include search list
  • ESP-IDF: v6.0 commit 662a3be3 ("change(version): Update version to 6.0.0", 2026-03-18)
  • Rust toolchain: rustup esp (1.93.0.0-preexisting per the local setup)
  • Profile: same error in cargo build --release and cargo check

Reproducer

Any project that depends on esp-idf-sys = \"0.38\" and targets xtensa-esp32s3-espidf against ESP-IDF v6.0:

source ~/.espressif/esp-idf/v6.0/export.sh
RUSTUP_TOOLCHAIN=esp cargo build --release \\
  --target xtensa-esp32s3-espidf \\
  -Zbuild-std=std,panic_abort \\
  -p <your-firmware-crate> \\
  --no-default-features

A pre-existing cached bindings.rs from before this issue surfaced will let the build proceed (build script skips the bindgen step on cache-hit), which is why some users haven't seen this. Fresh builds fail.

What I've tried (none fix it)

  • bindgen version downgrade 0.71.1 → 0.69.5 (via vendored embuild + [patch.crates-io])
  • bindgen version upgrade 0.71.1 → 0.72.1 (via embuild PR Include headers for NimBLE GAP & GATT services #104, drinkcat/bindgen)
  • Toggling enable_function_attribute_detection() in vendor/esp-idf-sys/build/build.rs:105
  • Adding blocklist_file(\".*portmacro\\\\.h\") and blocklist_function(\"vPort.*\") patterns (these only affect generated bindings, not clang parse — confirmed)
  • Adding the missing freertos sub-include via BINDGEN_EXTRA_CLANG_ARGS=\"-I.../FreeRTOS-Kernel/include/freertos -I.../FreeRTOS-Kernel/portable/xtensa/include/freertos -I.../config/include/freertos\". This resolves the FreeRTOS.h not-found stage but exposes the portmacro.h error as the next blocker
  • Forwarding the full -I + -D set from the cmake compile_commands.json (~7 KB of args) — same error
  • Switching IDF_PATH between ~/.espressif/esp-idf/v6.0 and the local embuild clone — same error, identical content (both at 662a3be3)

The error is invariant across every permutation. It's deeper than what we can reach from outside esp-idf-sys/embuild.

Likely cause (speculation)

bindgen sets -Xclang -detailed-preprocessing-record unconditionally so it can record macro definitions in the AST. With ESP-IDF v6.0's portmacro.h shape, that AST-recording pass appears to evaluate macro bodies as expressions and trips the function-call validation against the forward declaration above.

A possible fix path is the approach in PR #202 ("Add new bindgen options to generate wrappers for inline functions"): use bindgen::Builder::wrap_static_fns(true) so bindgen treats vPortEnterCritical / vPortExitCritical as wrapped statics rather than parsing them inline.

Workarounds

  • Ship a hand-rolled or cached bindings.rs and set ESP_IDF_SYS_SKIP_BINDGEN=1 (we added this escape hatch in our vendored fork).
  • Locally patch ESP-IDF's portmacro.h with #ifdef __bindgen guards around the four problematic macros (portENTER_CRITICAL, portEXIT_CRITICAL, plus the _ISR variants).

Cross-references

  • esp-idf-sys#202 — Add new bindgen options to generate wrappers for inline functions
  • embuild#104 — Cargo.toml: Update to bindgen 0.72.1 (tested, doesn't fix)

Happy to test patches against this reproducer.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    • Status
      Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions