mirror of
https://github.com/espressif/esp-idf.git
synced 2026-08-18 06:35:35 +03:00
Link-time optimization (LTO) lets the compiler inline and optimize across translation units. ESP-IDF relies heavily on linker-script placement rules that match object files by name, which LTO does not preserve, so LTO cannot be enabled for the whole framework. This change adds two opt-in options that side-step that conflict: - CONFIG_COMPILER_LTO_LINKTIME tells the linker to perform LTO on any object files that carry LTO information (compiled with -flto). On its own this is safe: users can add -flto to specific components (e.g. their own libraries) to shrink them, without affecting components that use linker fragments. - CONFIG_COMPILER_LTO_COMPILETIME automatically compiles most components with -flto. A component is excluded when it has its own linker fragments, when it opts out via the NO_LTO component property, or when its object code is placed by *another* component's linker fragment (matched by archive name). The last case is handled by tools/cmake/lto.cmake, which scans linker fragments for explicit "archive: libNAME.a" placement and excludes those components. Without it, functions that must run from IRAM while the flash cache is disabled (e.g. the spi_flash / GDMA HAL routines, placed in IRAM by spi_flash/esp_driver_dma fragments) would be moved to flash by LTO and the device would panic with a cache error at run time. Both options are disabled for the bootloader and ESP-TEE builds, which depend on object-file-name based placement. LTO is also gated off for Clang (needs LLD, IDF-8286) and host builds. LTO works together with CONFIG_APP_REPRODUCIBLE_BUILD, but needs extra flags: LTO defers code generation and most debug-info emission from compile time to link time, where the reproducible-build path remapping (applied to compile_options only) does not take effect. When both options are enabled, three extra flags keep the .elf, .bin and .map byte-identical across build directories (verified on esp32 / GCC 16.1): - the -f*-prefix-map options are passed to the linker as well, so the LTO code generator remaps DW_AT_comp_dir (otherwise the build dir leaks into .debug_str, and cascades into esp_app_desc_t.app_elf_sha256 in the .bin); - -save-temps makes lto-wrapper use stable LTRANS object names in the build dir instead of random $TMPDIR paths that leak into the .map; - -frandom-seed=1 makes LTO GIMPLE bytecode objects byte-identical (a shared seed was verified not to collide, including for C++ file-local static variables and anonymous namespaces promoted by LTO). The gcc-ar / gcc-ranlib wrappers are selected in the GCC toolchain file so that the LTO plugin is loaded when creating and indexing static archives; plain ar/ranlib do not record LTO symbols in the archive index. Note: LTO, like other inlining, can also increase binary size. Enable it together with CONFIG_COMPILER_OPTIMIZATION_SIZE to get a code-size benefit. Related: IDF-71, IDF-8286 Closes https://github.com/espressif/esp-idf/issues/18741 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>