# Using ESP-IDF as a Library

In the usual project, idf_project_default configures everything and builds the application from the `main` component. A standard CMake project can instead drive the ESP-IDF build itself with the lower-level API: it initializes the build system, bundles the required ESP-IDF components into a single library with idf_build_library, and links that library into its own executable. This is useful for integrating ESP-IDF into an existing CMake project, or for building host and target binaries from the same sources. The idf_as_lib example shows the complete pattern.

## Driving the Build

The project's `CMakeLists.txt` includes `idf.cmake`, runs `project()`, and creates its own executable, then uses the lower-level API to attach ESP-IDF to it:

CMakeLists.txt

    cmake_minimum_required(VERSION 3.22)
    include($ENV{IDF_PATH}/tools/cmakev2/idf.cmake)
    project(my_app C CXX ASM)

    add_executable(my_app.elf main.c)

    # Initialize the build system and bundle the needed components.
    idf_project_init()
    idf_build_library(idf_components COMPONENTS spi_flash esp_system)

    # Apply the include paths, definitions, and options that ESP-IDF
    # normally adds, then link the bundled library.
    idf_build_get_property(include_directories INCLUDE_DIRECTORIES GENERATOR_EXPRESSION)
    target_include_directories(my_app.elf PRIVATE "${include_directories}")
    idf_build_get_property(compile_definitions COMPILE_DEFINITIONS GENERATOR_EXPRESSION)
    target_compile_definitions(my_app.elf PRIVATE "${compile_definitions}")
    idf_build_get_compile_options(compile_options)
    target_compile_options(my_app.elf PRIVATE "${compile_options}")

    target_link_libraries(my_app.elf PRIVATE idf_components)

The key functions are:

idf_project_init

  Initialize the build system after `project()`: discover components, generate the configuration, and set up the compile and link options. It must be called before the functions below.

idf_build_library

  Bundle the listed components and their transitive dependencies into a single interface library, here named `idf_components`. Linking this library into an executable brings in the components' code, include paths, and linker options.

idf_build_get_property and idf_build_get_compile_options

  Read the global include directories, compile definitions, and compile options that ESP-IDF applies to its components, so that the same settings can be applied to the project's own executable.

## Generating the Binary and Flash Targets

To produce a flashable image and the usual targets, add them explicitly after linking:

    idf_build_binary(my_app.elf
                     OUTPUT_FILE "${CMAKE_BINARY_DIR}/my_app.bin"
                     TARGET my_app_binary)
    idf_flash_binary(my_app_binary TARGET app-flash NAME "app" FLASH)
    idf_check_binary_size(my_app_binary)
    idf_build_generate_metadata(BINARY my_app_binary)
    idf_build_generate_flasher_args()
    add_custom_target(app ALL DEPENDS my_app_binary)

idf_build_binary generates the binary image from the ELF, idf_flash_binary adds the flash target, and idf_build_generate_metadata writes `project_description.json` for tooling. These are the steps that idf_project_default performs automatically.

## Building for Host and Target

Because the ESP-IDF parts are explicit, the same project can also build a plain host executable. `idf.py` sets the ESP_PLATFORM variable, so the ESP-IDF specific code can be guarded with it:

    if(ESP_PLATFORM)
        include($ENV{IDF_PATH}/tools/cmakev2/idf.cmake)
    endif()

    project(my_app C CXX ASM)
    add_executable(my_app.elf main.c)

    if(ESP_PLATFORM)
        # idf_project_init(), idf_build_library(), and the rest go here.
    endif()

Without `ESP_PLATFORM`, the same `CMakeLists.txt` builds an ordinary host executable with no ESP-IDF dependency. Guard the ESP-IDF API calls in the source with `#ifdef ESP_PLATFORM` as well. The idf_as_lib example builds both ways from a single `main.c`.

Note

A project that builds a single library this way uses the IMMEDIATE optional-requires mode by default. To get the same minimal, v1-like component set as idf_project_default, set the mode to DEFERRED after idf_project_init. See The Behavior of idf_component_optional_requires has Changed.

Was this page helpful?

- Thank you! We received your feedback.
- If you have any comments, fill in Espressif Documentation Feedback Form.

- We value your feedback.
- Let us know how we can improve this page by filling in Espressif Documentation Feedback Form.