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

This commit is contained in:
Jonathan Swoboda
2026-05-29 01:16:55 -04:00
committed by GitHub
parent dd961156d0
commit 091a05ccde
3 changed files with 45 additions and 13 deletions

View File

@@ -1,5 +1,8 @@
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
from esphome.const import CONF_BUFFER_SIZE, CONF_ID, CONF_TYPE
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]))
if config[CONF_TYPE] == ESP32_CAMERA_ENCODER:
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")
var = cg.new_Pvariable(
config[CONF_ID],

View File

@@ -1245,6 +1245,7 @@ KEY_MBEDTLS_PKCS7_REQUIRED = "mbedtls_pkcs7_required"
KEY_FATFS_REQUIRED = "fatfs_required"
KEY_MBEDTLS_SHA512_REQUIRED = "mbedtls_sha512_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:
@@ -1353,6 +1354,15 @@ def require_adc_oneshot_iram() -> None:
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:
"""Parse IDF component shorthand syntax like 'owner/component^version'"""
# 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)
@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)
async def _add_yaml_idf_components(components: list[ConfigType]):
"""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_SHA512_C", False)
# Disable PicolibC Newlib compatibility shim on IDF 6.0+
# IDF 6.0 switched from Newlib to PicolibC. The shim provides thread-local
# 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)
# FINAL priority: runs after every require_libc_picolibc_newlib_compat() call
CORE.add_job(_set_libc_picolibc_newlib_compat)
# Disable regi2c control functions in IRAM
# Only needed if using analog peripherals (ADC, DAC, etc.) from ISRs while cache is disabled

View File

@@ -3,7 +3,11 @@ import logging
from esphome import automation, pins
import esphome.codegen as cg
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
import esphome.config_validation as cv
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_sdkconfig_option("CONFIG_SCCB_HARDWARE_I2C_DRIVER_NEW", True)
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, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)