mirror of
https://github.com/esphome/esphome.git
synced 2026-09-26 22:40:21 +00:00
Apply the same linker wrap technique used on ESP32 (PR #14362) to RP2040. ESPHome logging uses snprintf/vsnprintf, not libc printf, so the FILE*-based printf path (_vfprintf_r) is dead code at runtime. The stubs redirect printf/vprintf/fprintf through vsnprintf + fwrite, allowing the linker to GC _vfprintf_r (~8.9 KB).
72 lines
2.1 KiB
C++
72 lines
2.1 KiB
C++
/*
|
|
* Linker wrap stubs for FILE*-based printf functions.
|
|
*
|
|
* The RP2040 Arduino framework and libraries may reference printf(),
|
|
* vprintf(), and fprintf() which pull in newlib's _vfprintf_r (~8.9 KB).
|
|
* ESPHome never uses these — all logging goes through the logger component
|
|
* which uses snprintf/vsnprintf, so the libc FILE*-based printf path is
|
|
* dead code.
|
|
*
|
|
* These stubs redirect through vsnprintf() (which is already in the binary)
|
|
* and fwrite(), allowing the linker to dead-code eliminate _vfprintf_r.
|
|
*
|
|
* Saves ~8.9 KB of flash.
|
|
*/
|
|
|
|
#if defined(USE_RP2040) && !defined(USE_FULL_PRINTF)
|
|
#include <cstdarg>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
|
|
namespace esphome::rp2040 {}
|
|
|
|
static constexpr size_t PRINTF_BUFFER_SIZE = 512;
|
|
|
|
// These stubs are essentially dead code at runtime — ESPHome uses its own
|
|
// logging through snprintf/vsnprintf, not libc printf.
|
|
// The buffer overflow check is purely defensive and should never trigger.
|
|
static int write_printf_buffer(FILE *stream, char *buf, int len) {
|
|
if (len < 0) {
|
|
return len;
|
|
}
|
|
size_t write_len = len;
|
|
if (write_len >= PRINTF_BUFFER_SIZE) {
|
|
fwrite(buf, 1, PRINTF_BUFFER_SIZE - 1, stream);
|
|
abort();
|
|
}
|
|
if (fwrite(buf, 1, write_len, stream) < write_len || ferror(stream)) {
|
|
return -1;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
// NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming)
|
|
extern "C" {
|
|
|
|
int __wrap_vprintf(const char *fmt, va_list ap) {
|
|
char buf[PRINTF_BUFFER_SIZE];
|
|
return write_printf_buffer(stdout, buf, vsnprintf(buf, sizeof(buf), fmt, ap));
|
|
}
|
|
|
|
int __wrap_printf(const char *fmt, ...) {
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
int len = __wrap_vprintf(fmt, ap);
|
|
va_end(ap);
|
|
return len;
|
|
}
|
|
|
|
int __wrap_fprintf(FILE *stream, const char *fmt, ...) {
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
char buf[PRINTF_BUFFER_SIZE];
|
|
int len = write_printf_buffer(stream, buf, vsnprintf(buf, sizeof(buf), fmt, ap));
|
|
va_end(ap);
|
|
return len;
|
|
}
|
|
|
|
} // extern "C"
|
|
// NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming)
|
|
|
|
#endif // USE_RP2040 && !USE_FULL_PRINTF
|