From db33ccc5c1fce1664acf8b9515e71900acfee6e1 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Fri, 23 Jan 2026 16:42:20 +0100 Subject: [PATCH] feat(cmakev2): Added idf_as_lib example for cmakev2 This commit updates the examples/build_system/cmake/idf_as_lib example for the new build system and adds the newly created example at examples/build_system/cmakev2/features/idf_as_lib. --- examples/build_system/cmakev2/README.md | 20 ++++++ .../features/idf_as_lib/CMakeLists.txt | 55 ++++++++++++++ .../cmakev2/features/idf_as_lib/README.md | 55 ++++++++++++++ .../cmakev2/features/idf_as_lib/main.c | 71 +++++++++++++++++++ 4 files changed, 201 insertions(+) create mode 100644 examples/build_system/cmakev2/features/idf_as_lib/CMakeLists.txt create mode 100644 examples/build_system/cmakev2/features/idf_as_lib/README.md create mode 100644 examples/build_system/cmakev2/features/idf_as_lib/main.c diff --git a/examples/build_system/cmakev2/README.md b/examples/build_system/cmakev2/README.md index f9533c21467..4d74aefea50 100644 --- a/examples/build_system/cmakev2/README.md +++ b/examples/build_system/cmakev2/README.md @@ -77,6 +77,26 @@ LED blinking example with Kconfig configuration and Component Manager integratio ## Build System Features Examples +### idf_as_lib +**Location:** [idf_as_lib/](./features/idf_as_lib/) + +Demonstrates using ESP-IDF components as a library in external projects. + +```cmake +idf_build_library(idf_lib COMPONENTS spi_flash) +target_link_libraries(external_app idf_lib) +``` + +**Key Concepts:** `idf_build_library()`, external project integration + +**When to use:** When integrating ESP-IDF components into non-IDF build systems or existing CMake projects. + +**Build Note:** This example uses direct CMake commands, not `idf.py`: +```bash +cmake -G Ninja -B build -DCMAKE_TOOLCHAIN_FILE=... +ninja -C build +``` + These examples demonstrate the build system capabilities and some `cmakev2` specific features. ## Build System v2 API Quick Reference diff --git a/examples/build_system/cmakev2/features/idf_as_lib/CMakeLists.txt b/examples/build_system/cmakev2/features/idf_as_lib/CMakeLists.txt new file mode 100644 index 00000000000..b31fb1ce48c --- /dev/null +++ b/examples/build_system/cmakev2/features/idf_as_lib/CMakeLists.txt @@ -0,0 +1,55 @@ +# A standard CMake project that uses ESP-IDF as a library. +# When ESP_PLATFORM is set (idf.py invocation), IDF components are bundled +# into a single library and linked into the executable. Without it the +# project builds a plain host executable with no IDF dependency. + +cmake_minimum_required(VERSION 3.22) + +if(ESP_PLATFORM) + include($ENV{IDF_PATH}/tools/cmakev2/idf.cmake) +endif() + +project(idf_as_lib C CXX ASM) + +# Single source file for both builds. IDF code paths inside main.c are +# guarded by #ifdef ESP_PLATFORM. +add_executable(${CMAKE_PROJECT_NAME}.elf main.c) + +if(ESP_PLATFORM) + # Initialise the IDF build system and bundle the required components + # into a single linkable library. + idf_project_init() + + # Create ESP-IDF library with specified components. + idf_build_library(idf_components COMPONENTS spi_flash esp_system) + + # Apply IDF build properties to the custom executable so it receives + # include paths, compile definitions, and compile options that IDF normally adds. + idf_build_get_property(include_directories INCLUDE_DIRECTORIES GENERATOR_EXPRESSION) + target_include_directories(${CMAKE_PROJECT_NAME}.elf PRIVATE "${include_directories}") + + idf_build_get_property(compile_definitions COMPILE_DEFINITIONS GENERATOR_EXPRESSION) + target_compile_definitions(${CMAKE_PROJECT_NAME}.elf PRIVATE "${compile_definitions}") + + idf_build_get_compile_options(compile_options) + target_compile_options(${CMAKE_PROJECT_NAME}.elf PRIVATE "${compile_options}") + + # Link the bundled IDF library. This brings in component headers, + # sdkconfig includes, and all necessary linker options. + target_link_libraries(${CMAKE_PROJECT_NAME}.elf PRIVATE idf_components) + + # Binary and flash targets + idf_build_binary(${CMAKE_PROJECT_NAME}.elf + OUTPUT_FILE "${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.bin" + TARGET ${CMAKE_PROJECT_NAME}_binary) + + idf_flash_binary(${CMAKE_PROJECT_NAME}_binary + TARGET app-flash + NAME "app" + FLASH) + + idf_check_binary_size(${CMAKE_PROJECT_NAME}_binary) + idf_build_generate_metadata(BINARY ${CMAKE_PROJECT_NAME}_binary) + idf_build_generate_flasher_args() + add_custom_target(app ALL DEPENDS ${CMAKE_PROJECT_NAME}_binary) +endif() diff --git a/examples/build_system/cmakev2/features/idf_as_lib/README.md b/examples/build_system/cmakev2/features/idf_as_lib/README.md new file mode 100644 index 00000000000..65ef54393f3 --- /dev/null +++ b/examples/build_system/cmakev2/features/idf_as_lib/README.md @@ -0,0 +1,55 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | + +# ESP-IDF as a Library in a Standard CMake Project + +This example demonstrates how to use ESP-IDF as a library inside a standard CMake project. The same source files produce either a plain host executable or an ESP-IDF firmware image depending on how the project is invoked. + +## How it works + +When `idf.py` is used it sets the `ESP_PLATFORM` CMake variable before invoking CMake. A single project-level CMakeLists.txt checks for this variable: if set, it initialises the IDF build system, bundles the required IDF components into one linkable library via `idf_build_library`, compiles the application sources, links them against that library, and produces the final binary and flash targets. Without `ESP_PLATFORM` the same file produces a minimal host executable with no IDF dependency. + +`main.c` is the only source file. All IDF API calls inside it are guarded by `#ifdef ESP_PLATFORM`, so the same file compiles cleanly for both targets. On ESP it defines `app_main`; on the host it defines a plain `main`. + +## Project Layout + +``` +idf_as_lib/ +├── CMakeLists.txt ← Single file: host + ESP build logic +├── main.c ← One file, two entry points (host & ESP) +└── sdkconfig ← ESP-IDF configuration +``` + +## How to build the host app + +``` +cmake -B build-host . +cmake --build build-host +./build-host/idf_as_lib.elf +``` + +### Expected output + +``` +Hello from host build +Run with idf.py set-target && idf.py build for ESP build. +``` + +## How to build the ESP-IDF app + +``` +idf.py set-target +idf.py build flash monitor +``` + +### Expected output + +``` +Hello from ESP-IDF build +idf_lib initialized (IDF as library) +This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, silicon revision v3.0, 2MB external flash +Minimum free heap size: 303764 bytes +Restarting in 10... +... +Restarting now. +``` \ No newline at end of file diff --git a/examples/build_system/cmakev2/features/idf_as_lib/main.c b/examples/build_system/cmakev2/features/idf_as_lib/main.c new file mode 100644 index 00000000000..a76cef8f3bc --- /dev/null +++ b/examples/build_system/cmakev2/features/idf_as_lib/main.c @@ -0,0 +1,71 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + * + * Single source file for both host and ESP-IDF builds. + * - Host: plain main(), no IDF dependency. + * - ESP-IDF: app_main(), uses IDF APIs guarded by ESP_PLATFORM. + */ + +#include +#include + +#ifdef ESP_PLATFORM +#include "esp_chip_info.h" +#include "esp_flash.h" +#include "esp_system.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#endif + +#ifdef ESP_PLATFORM +void app_main(void) +#else +int main(void) +#endif +{ + printf("Hello from %s build\n", +#ifdef ESP_PLATFORM + "ESP-IDF" +#else + "host" +#endif + ); + +#ifdef ESP_PLATFORM + /* --- chip info --------------------------------------------------------- */ + esp_chip_info_t chip_info; + uint32_t flash_size; + esp_chip_info(&chip_info); + + printf("This is %s chip with %d CPU core(s), WiFi%s%s, ", + CONFIG_IDF_TARGET, + chip_info.cores, + (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "", + (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : ""); + + unsigned major_rev = chip_info.revision / 100; + unsigned minor_rev = chip_info.revision % 100; + printf("silicon revision v%d.%d, ", major_rev, minor_rev); + + if (esp_flash_get_size(NULL, &flash_size) == ESP_OK) { + printf("%" PRIu32 " MB %s flash\n", flash_size / (1024 * 1024), + (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external"); + } + + printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size()); + + /* --- countdown and restart -------------------------------------------- */ + for (int i = 10; i >= 0; i--) { + printf("Restarting in %d...\n", i); + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + printf("Restarting now.\n"); + fflush(stdout); + esp_restart(); +#else + printf("Run with idf.py set-target && idf.py build for ESP-IDF build.\n"); + return 0; +#endif +}