Skip to content

Add (some) support for ESP-IDF v6.0#408

Merged
ivmarkov merged 10 commits intoesp-rs:masterfrom
drinkcat:idf-6.0
Mar 28, 2026
Merged

Add (some) support for ESP-IDF v6.0#408
ivmarkov merged 10 commits intoesp-rs:masterfrom
drinkcat:idf-6.0

Conversation

@drinkcat
Copy link
Copy Markdown
Contributor

@drinkcat drinkcat commented Mar 24, 2026

Submission Checklist 📝

  • I have updated existing examples or added new ones (if applicable).
  • I have used cargo fmt command to ensure that all changed code is formatted correctly.
  • I have used cargo clippy command to ensure that all changed code passes latest Clippy nightly lints.
  • My changes were added to the CHANGELOG.md in the proper section.

Pull Request Details 📖

Description

Hi! Making an attempt to add support for ESP-IDF v6.0.

Full log below (bottom to top), I attempted to order commits in order of trivial to... I'd really like your input.

  • The first 3 are trivial, some header location/name changes.
  • pcnt change is also quite simple, it's just a bit unfortunate to have to parse the version from headers (because.... we normally get the version from the generated bindings).
  • picolibc: That's where I struggled the most. IIUC, the problem here is that PICOLIBC in esp-idf isn't compatible with clang. It gets selected by default, with the default GCC toolchain. And then things break when we try to use clang to generate the bindings. Looks like we can hack hardcoded paths to fix the issues though. Feedback more than welcome (I was also pondering blocklisting PICOLIBC as an option...).
  • bindings: The ETH drivers (PHY and SPI) have been moved to external components, we probably still want to generate the bindings (this will become clearer when looking at the pending esp-idf-svc MR).

If the first few commits are ok and you'd like to go ahead with those, happy to carve them out into a different PR.

For transparency, I made extensive use of Claude to help me investigate and generate code, but human is deeply in the loop.

Testing

Compile tested in CI, needs related hal and svc changes, booted a small example on ESPC6 VROOM board.


bindings: add managed ETH PHY and SPI ETH component headers

  • ETH PHY: dp83848, ip101, ksz80xx, lan87xx, rtl8201.
  • SPI ETH: dm9051, w5500, ksz8851snl.

When these components are added as extra_components (managed via the IDF
component manager), their include dirs are already present in the CMake
compile group and thus available to bindgen. Adding the #ifdef guards here
causes bindgen to generate bindings for their functions automatically.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

CHANGELOG.md: Update

.github/workflows/ci.yml: Add v6.0

build: inject picolibc include path for bindgen (ESP-IDF v6.0)

ESP-IDF v6.0 switched from newlib to picolibc. Clang silently ignores
GCC's -specs=picolibc.specs so bindgen falls back to the newlib sysroot
headers, causing errors like 'unknown type name __FILE'.

Detect the picolibc include directory relative to the GCC sysroot and
inject it as -I before the sysroot headers so clang uses the correct
stdlib headers.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

build: expose gcc_sysroot in EspIdfBuildOutput

Compute the GCC sysroot via riscv32-esp-elf-ld/xtensa-esp-elf-ld
--print-sysroot in cargo_driver and expose it as gcc_sysroot in
EspIdfBuildOutput, so build.rs can derive the picolibc include path
without re-running chip detection logic.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

pcnt: disable pcnt.rs for ESP-IDF v6.0+ (legacy API removed)

In ESP-IDF v6.0, the legacy pcnt_unit_t enum and legacy PCNT constants
(PCNT_UNIT_0..MAX) were removed along with the legacy driver API.
The only remaining pcnt_unit_t is the opaque struct used by the new
driver API, which bindgen can handle without the type blocklist workaround.

Stop blocklisting pcnt_unit_t in bindgen for v6.0+ (detected by parsing
header file, unfortunately), and gate the pcnt module (which provides
the enum type and legacy constants) on ESP-IDF < v6.0.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

bindings: explicitly include soc/gpio_reg.h for ESP-IDF v6.0+

In ESP-IDF v6.0, soc/gpio_periph.h dropped its include of soc/gpio_reg.h,
breaking the transitive include chain that previously made GPIO_OUT_REG and
friends visible via driver/gpio.h. Include it explicitly when IDF >= 6.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

bindings: include driver/uart_vfs.h to export uart_vfs_dev_* functions

uart_vfs_dev_use_nonblocking() and related functions were moved from
esp_vfs_dev.h (deprecated) to driver/uart_vfs.h in ESP-IDF v5. Include
it when both the UART driver and VFS components are enabled.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

bindings: guard mbedtls legacy crypto headers for mbedtls v4 (ESP-IDF v6.0)

ESP-IDF v6.0 ships mbedtls v4 which removed the legacy crypto API headers
(aes.h, cipher.h, entropy.h, etc.) in favour of the PSA API. Guard these
includes with MBEDTLS_VERSION_MAJOR < 4 to fix the build.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

drinkcat and others added 8 commits March 22, 2026 20:08
… v6.0)

ESP-IDF v6.0 ships mbedtls v4 which removed the legacy crypto API headers
(aes.h, cipher.h, entropy.h, etc.) in favour of the PSA API. Guard these
includes with MBEDTLS_VERSION_MAJOR < 4 to fix the build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
uart_vfs_dev_use_nonblocking() and related functions were moved from
esp_vfs_dev.h (deprecated) to driver/uart_vfs.h in ESP-IDF v5. Include
it when both the UART driver and VFS components are enabled.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In ESP-IDF v6.0, soc/gpio_periph.h dropped its include of soc/gpio_reg.h,
breaking the transitive include chain that previously made GPIO_OUT_REG and
friends visible via driver/gpio.h. Include it explicitly when IDF >= 6.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In ESP-IDF v6.0, the legacy pcnt_unit_t enum and legacy PCNT constants
(PCNT_UNIT_0..MAX) were removed along with the legacy driver API.
The only remaining pcnt_unit_t is the opaque struct used by the new
driver API, which bindgen can handle without the type blocklist workaround.

Stop blocklisting pcnt_unit_t in bindgen for v6.0+ (detected by parsing
header file, unfortunately), and gate the pcnt module (which provides
the enum type and legacy constants) on ESP-IDF < v6.0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Compute the GCC sysroot via riscv32-esp-elf-ld/xtensa-esp-elf-ld
--print-sysroot in cargo_driver and expose it as gcc_sysroot in
EspIdfBuildOutput, so build.rs can derive the picolibc include path
without re-running chip detection logic.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ESP-IDF v6.0 switched from newlib to picolibc. Clang silently ignores
GCC's -specs=picolibc.specs so bindgen falls back to the newlib sysroot
headers, causing errors like 'unknown type name __FILE'.

Detect the picolibc include directory relative to the GCC sysroot and
inject it as -I before the sysroot headers so clang uses the correct
stdlib headers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread src/include/esp-idf/bindings.h
@ivmarkov
Copy link
Copy Markdown
Collaborator

@drinkcat Thanks and interesting work!
Need to wait a couple of days until I get to it.

- ETH PHY: dp83848, ip101, ksz80xx, lan87xx, rtl8201.
- SPI ETH: dm9051, w5500, ksz8851snl.

When these components are added as extra_components (managed via the IDF
component manager), their include dirs are already present in the CMake
compile group and thus available to bindgen. Adding the #ifdef guards here
causes bindgen to generate bindings for their functions automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@drinkcat
Copy link
Copy Markdown
Contributor Author

drinkcat commented Mar 26, 2026

(updated -- added one more commit for ETH bindings -- HAL change pushed here: esp-rs/esp-idf-hal#578; SVC here: esp-rs/esp-idf-svc#650)

Follows the same pattern as mdns and websocket client.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@drinkcat
Copy link
Copy Markdown
Contributor Author

Replying to your picolibc comment on the other PR here.

Yep, that's it. I considered forcing to use newlib as well, but I decided to keep the default from esp-idf 6.0 (picolibc), and figure out how to make it work. Apart from the sysroot hack, the rest of support looked easy, I think? (https://github.com/esp-rs/esp-idf-hal/pull/578/changes#diff-2bd60f29989e7f927a4f3f4325d2ec2254df11c50d040d772fbeb67ce3abf008 this should be looked at carefully though, didn't really check how to test)

I agree. Let's keep your approach then!

Ah, almost forgot. picolibc seems to be a fork of newlib. Yet, I'm not 100% sure all definitions here would match the picolibc ones. In the worst case (and if there is a mismatch), we might have to introduce a picolibc module to the Rust libc bindings' crate.

There's a tool that can do comparison between what Rust's libc "thinks" the sizes of these types should be, and what esp-idf-sys actually reports them to be: https://github.com/SergioGasquez/libc-checks

More background: rust-lang/libc#3920

Wow, that looks like some fun ,-P

Some constants missing:
drinkcat/libc-checks@6d71c91

And some potential trouble (Full logs https://gist.github.com/drinkcat/d45f0d5274766ae57580f8f65178d6cb)

E (351) libc_checks: Mismatch detected for constant `O_APPEND`: `esp-idf` 1024 | `libc` 8
E (351) libc_checks: Mismatch detected for constant `O_CREAT`: `esp-idf` 64 | `libc` 512
E (361) libc_checks: Mismatch detected for constant `O_TRUNC`: `esp-idf` 512 | `libc` 1024

(but I think that's tomorrow's problem -- I'll take a look)

@ivmarkov
Copy link
Copy Markdown
Collaborator

E (351) libc_checks: Mismatch detected for constant `O_APPEND`: `esp-idf` 1024 | `libc` 8
E (351) libc_checks: Mismatch detected for constant `O_CREAT`: `esp-idf` 64 | `libc` 512
E (361) libc_checks: Mismatch detected for constant `O_TRUNC`: `esp-idf` 512 | `libc` 1024

(but I think that's tomorrow's problem -- I'll take a look)

Yep, no rush but we need to fix at some point.
The annoyance is, the most proper and clean fix would be to introduce new -espidf Rust targets, which list picolibc instead of newlib as their libc, so that we can then branch - in libc - by the type of the libc used by the target...

@drinkcat
Copy link
Copy Markdown
Contributor Author

E (351) libc_checks: Mismatch detected for constant `O_APPEND`: `esp-idf` 1024 | `libc` 8
E (351) libc_checks: Mismatch detected for constant `O_CREAT`: `esp-idf` 64 | `libc` 512
E (361) libc_checks: Mismatch detected for constant `O_TRUNC`: `esp-idf` 512 | `libc` 1024

(but I think that's tomorrow's problem -- I'll take a look)

Yep, no rush but we need to fix at some point. The annoyance is, the most proper and clean fix would be to introduce new -espidf Rust targets, which list picolibc instead of newlib as their libc, so that we can then branch - in libc - by the type of the libc used by the target...

Looked a bit around, and noticed the --cfg espidf_time32 flag that was added when moving from 4.x to 5.x... I wonder if we can do something similar.

And with these (and crates.io overrides, etc.), libc_checks succeeds... but... IIUC, this is still wrong as the toolchain's std will still use the unpatched libc? How did you handle the time32->time64 change? (I'm not completely clear looking at past discussions) You didn't create separate -espidf-timeX Rust targets at the time, did you?

Anyhow, a proper fix will take time, so, for the interest of this PR specifically... How bad do you feel those 3 mismatched constants are? I don't have a good perspective on how frequent filesystem usage would be on esp-rs. Is it bad enough to warrant blocklisting the picolibc option? Or would it be enough to add this in release notes?

@ivmarkov
Copy link
Copy Markdown
Collaborator

You didn't create separate -espidf-timeX Rust targets at the time, did you?

Nope. If I remember correctly, the reasons were:

  • We were afraid there would be too many of those. Basically the existing 6 target x2
  • Over time, folks would migrate from ISP IDF 4.x (time32) to 5.x (time64) and thus the need for those flags (or at least for specifying them / teaching them) would disappear.

Looked a bit around, and noticed the --cfg espidf_time32 flag that was added when moving from 4.x to 5.x... I wonder if we can do something similar.

You are right that you could apply the same reasoning for the current picolibc case (though the picolibc cfg would become obsolete only by ESP-IDF 7.0 or even 8.0 when support for newlib might get removed so we are talking a much longer timeline here). Yet, I'm slowly warming up to the idea of an extra picolibc flag actually.

Anyhow, a proper fix will take time, so, for the interest of this PR specifically... How bad do you feel those 3 mismatched constants are? I don't have a good perspective on how frequent filesystem usage would be on esp-rs. Is it bad enough to warrant blocklisting the picolibc option? Or would it be enough to add this in release notes?

Well it is bad as filesystems are used on top of esp-rs, typically with external storage like SD cards.
But this PR is not only about the option to switch to piclobic but also about general ESP-IDF 6 compat, so the picolibc issue is not a showstopper.

@ivmarkov ivmarkov merged commit ac0a8fe into esp-rs:master Mar 28, 2026
24 checks passed
@drinkcat
Copy link
Copy Markdown
Contributor Author

Thanks! I filed #410 so that we don't forget about that picolibc thing.

Do you plan to make a new release with this sometimes soon? I think I need a new tag to merge the hal/svc PR with CI enabled (otherwise I can disable CI on 6.0 until a new release).

@ivmarkov
Copy link
Copy Markdown
Collaborator

Thanks! I filed #410 so that we don't forget about that picolibc thing.

Do you plan to make a new release with this sometimes soon? I think I need a new tag to merge the hal/svc PR with CI enabled (otherwise I can disable CI on 6.0 until a new release).

We can release whenever we want, but merging the hal/svc changes do not require a release - you just need to have - in hal and svc - a patch that redirects sys to the GIT one. As you actually already did, except the branch should be master.

@drinkcat
Copy link
Copy Markdown
Contributor Author

Thanks! I filed #410 so that we don't forget about that picolibc thing.
Do you plan to make a new release with this sometimes soon? I think I need a new tag to merge the hal/svc PR with CI enabled (otherwise I can disable CI on 6.0 until a new release).

We can release whenever we want, but merging the hal/svc changes do not require a release - you just need to have - in hal and svc - a patch that redirects sys to the GIT one. As you actually already did, except the branch should be master.

Ok, I'll do that (and I guess you'll just have to remove that line before the next release)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants