[esp32_camera] Enable PicolibC Newlib compatibility on IDF 6.0+ (#16703)

This commit is contained in:
Jonathan Swoboda authored and GitHub committed 2026-05-29 05:16:55 +00:00
1 parent dd961156d0
commit 091a05ccde
3 files changed
+45 -13

No files matched your search

@@ -1,5 +1,8 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components.esp32 import add_idf_component from esphome.components.esp32 import (
add_idf_component,
require_libc_picolibc_newlib_compat,
)
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_BUFFER_SIZE, CONF_ID, CONF_TYPE from esphome.const import CONF_BUFFER_SIZE, CONF_ID, CONF_TYPE
from esphome.types import ConfigType from esphome.types import ConfigType
@@ -51,6 +54,8 @@ async def to_code(config: ConfigType) -> None:
cg.add(buffer.set_buffer_size(config[CONF_BUFFER_SIZE])) cg.add(buffer.set_buffer_size(config[CONF_BUFFER_SIZE]))
if config[CONF_TYPE] == ESP32_CAMERA_ENCODER: if config[CONF_TYPE] == ESP32_CAMERA_ENCODER:
add_idf_component(name="espressif/esp32-camera", ref="2.1.5") add_idf_component(name="espressif/esp32-camera", ref="2.1.5")
# esp32-camera 2.1.5 needs the Newlib shim on IDF 6.0+; remove when fixed upstream
require_libc_picolibc_newlib_compat()
cg.add_define("USE_ESP32_CAMERA_JPEG_ENCODER") cg.add_define("USE_ESP32_CAMERA_JPEG_ENCODER")
var = cg.new_Pvariable( var = cg.new_Pvariable(
config[CONF_ID], config[CONF_ID],
+32 -11
View File
@@ -1245,6 +1245,7 @@ KEY_MBEDTLS_PKCS7_REQUIRED = "mbedtls_pkcs7_required"
KEY_FATFS_REQUIRED = "fatfs_required" KEY_FATFS_REQUIRED = "fatfs_required"
KEY_MBEDTLS_SHA512_REQUIRED = "mbedtls_sha512_required" KEY_MBEDTLS_SHA512_REQUIRED = "mbedtls_sha512_required"
KEY_ADC_ONESHOT_IRAM_REQUIRED = "adc_oneshot_iram_required" KEY_ADC_ONESHOT_IRAM_REQUIRED = "adc_oneshot_iram_required"
KEY_LIBC_PICOLIBC_NEWLIB_COMPAT_REQUIRED = "libc_picolibc_newlib_compat_required"
def require_vfs_select() -> None: def require_vfs_select() -> None:
@@ -1353,6 +1354,15 @@ def require_adc_oneshot_iram() -> None:
CORE.data[KEY_ESP32][KEY_ADC_ONESHOT_IRAM_REQUIRED] = True CORE.data[KEY_ESP32][KEY_ADC_ONESHOT_IRAM_REQUIRED] = True
def require_libc_picolibc_newlib_compat() -> None:
"""Keep CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY enabled on IDF 6.0+.
Call this from components that link against precompiled Newlib binaries
referencing types/symbols the shim provides (e.g. esp32-camera).
"""
CORE.data[KEY_ESP32][KEY_LIBC_PICOLIBC_NEWLIB_COMPAT_REQUIRED] = True
def _parse_idf_component(value: str) -> ConfigType: def _parse_idf_component(value: str) -> ConfigType:
"""Parse IDF component shorthand syntax like 'owner/component^version'""" """Parse IDF component shorthand syntax like 'owner/component^version'"""
# Match operator followed by version-like string (digit or *) # Match operator followed by version-like string (digit or *)
@@ -1758,6 +1768,26 @@ async def _write_arduino_libraries_sdkconfig() -> None:
add_idf_sdkconfig_option(f"CONFIG_ARDUINO_SELECTIVE_{lib}", lib in enabled_libs) add_idf_sdkconfig_option(f"CONFIG_ARDUINO_SELECTIVE_{lib}", lib in enabled_libs)
@coroutine_with_priority(CoroPriority.FINAL)
async def _set_libc_picolibc_newlib_compat() -> None:
"""Apply the PicolibC Newlib compatibility shim option on IDF 6.0+.
IDF 6.0 switched from Newlib to PicolibC; the shim is disabled by default.
Runs at FINAL priority so every require_libc_picolibc_newlib_compat() call
(default priority) is seen before the option is written. A user-supplied
sdkconfig_options value takes precedence.
"""
if idf_version() < cv.Version(6, 0, 0):
return
option = "CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY"
if option in CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS]:
return
add_idf_sdkconfig_option(
option,
CORE.data[KEY_ESP32].get(KEY_LIBC_PICOLIBC_NEWLIB_COMPAT_REQUIRED, False),
)
@coroutine_with_priority(CoroPriority.FINAL) @coroutine_with_priority(CoroPriority.FINAL)
async def _add_yaml_idf_components(components: list[ConfigType]): async def _add_yaml_idf_components(components: list[ConfigType]):
"""Add IDF components from YAML config with final priority to override code-added components.""" """Add IDF components from YAML config with final priority to override code-added components."""
@@ -2291,17 +2321,8 @@ async def to_code(config):
add_idf_sdkconfig_option("CONFIG_MBEDTLS_SHA384_C", False) add_idf_sdkconfig_option("CONFIG_MBEDTLS_SHA384_C", False)
add_idf_sdkconfig_option("CONFIG_MBEDTLS_SHA512_C", False) add_idf_sdkconfig_option("CONFIG_MBEDTLS_SHA512_C", False)
# Disable PicolibC Newlib compatibility shim on IDF 6.0+ # FINAL priority: runs after every require_libc_picolibc_newlib_compat() call
# IDF 6.0 switched from Newlib to PicolibC. The shim provides thread-local CORE.add_job(_set_libc_picolibc_newlib_compat)
# stdin/stdout/stderr and getreent() for code compiled against Newlib.
# ESPHome doesn't link against Newlib-built libraries that use stdio.
# If a component needs it (e.g. precompiled Newlib binaries), re-enable via:
# esp32:
# framework:
# sdkconfig_options:
# CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY: "y"
if idf_version() >= cv.Version(6, 0, 0):
add_idf_sdkconfig_option("CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY", False)
# Disable regi2c control functions in IRAM # Disable regi2c control functions in IRAM
# Only needed if using analog peripherals (ADC, DAC, etc.) from ISRs while cache is disabled # Only needed if using analog peripherals (ADC, DAC, etc.) from ISRs while cache is disabled
+7 -1
View File
@@ -3,7 +3,11 @@ import logging
from esphome import automation, pins from esphome import automation, pins
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import i2c from esphome.components import i2c
from esphome.components.esp32 import add_idf_component, add_idf_sdkconfig_option from esphome.components.esp32 import (
add_idf_component,
add_idf_sdkconfig_option,
require_libc_picolibc_newlib_compat,
)
from esphome.components.psram import DOMAIN as psram_domain from esphome.components.psram import DOMAIN as psram_domain
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
@@ -402,6 +406,8 @@ async def to_code(config):
add_idf_component(name="espressif/esp32-camera", ref="2.1.5") add_idf_component(name="espressif/esp32-camera", ref="2.1.5")
add_idf_sdkconfig_option("CONFIG_SCCB_HARDWARE_I2C_DRIVER_NEW", True) add_idf_sdkconfig_option("CONFIG_SCCB_HARDWARE_I2C_DRIVER_NEW", True)
add_idf_sdkconfig_option("CONFIG_SCCB_HARDWARE_I2C_DRIVER_LEGACY", False) add_idf_sdkconfig_option("CONFIG_SCCB_HARDWARE_I2C_DRIVER_LEGACY", False)
# esp32-camera 2.1.5 needs the Newlib shim on IDF 6.0+; remove when fixed upstream
require_libc_picolibc_newlib_compat()
for conf in config.get(CONF_ON_STREAM_START, []): for conf in config.get(CONF_ON_STREAM_START, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)