[esp32] Wrap vfprintf to fix printf stub on picolibc (IDF 6)

IDF 6 uses picolibc instead of newlib. In newlib, vfprintf was a thin
36-byte trampoline to _vfprintf_r, so wrapping printf/vprintf/fprintf
was sufficient to dead-code eliminate _vfprintf_r. In picolibc, vfprintf
IS the heavy implementation (~2.8 KB) and is referenced directly by SDK
components. Add vfprintf to the wrap list to intercept those references.
This commit is contained in:
J. Nick Koston
2026-03-25 12:44:27 -10:00
parent a075f63b59
commit 4a842f8e83
2 changed files with 11 additions and 5 deletions
+1 -1
View File
@@ -1587,7 +1587,7 @@ async def to_code(config):
if conf[CONF_ADVANCED][CONF_ENABLE_FULL_PRINTF]:
cg.add_define("USE_FULL_PRINTF")
else:
for symbol in ("vprintf", "printf", "fprintf"):
for symbol in ("vprintf", "printf", "fprintf", "vfprintf"):
cg.add_build_flag(f"-Wl,--wrap={symbol}")
else:
cg.add_build_flag("-DUSE_ARDUINO")
+10 -4
View File
@@ -2,10 +2,11 @@
* Linker wrap stubs for FILE*-based printf functions.
*
* ESP-IDF SDK components (gpio driver, ringbuf, log_write) reference
* fprintf(), printf(), and vprintf() which pull in newlib's _vfprintf_r
* (~11 KB). This is a separate implementation from _svfprintf_r (used by
* snprintf/vsnprintf) that handles FILE* stream I/O with buffering and
* locking.
* fprintf(), printf(), vprintf(), and vfprintf() which pull in the full
* printf implementation (~11 KB on newlib's _vfprintf_r, ~2.8 KB on
* picolibc's vfprintf). This is a separate implementation from the one
* used by snprintf/vsnprintf that handles FILE* stream I/O with buffering
* and locking.
*
* ESPHome replaces the ESP-IDF log handler via esp_log_set_vprintf_(),
* so the SDK's vprintf() path is dead code at runtime. The fprintf()
@@ -70,6 +71,11 @@ int __wrap_printf(const char *fmt, ...) {
return len;
}
int __wrap_vfprintf(FILE *stream, const char *fmt, va_list ap) {
char buf[PRINTF_BUFFER_SIZE];
return write_printf_buffer(stream, buf, vsnprintf(buf, sizeof(buf), fmt, ap));
}
int __wrap_fprintf(FILE *stream, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);