NeuroAgent

ESP-IDF: Add External Library Dependency Guide

Learn how to properly configure external libraries like esp-nimble-cpp as dependencies in ESP-IDF projects. Fix CMake issues and resolve class recognition problems.

How to include an external library as a module dependency in an ESP-IDF project?

I’m new to C++, CMake, and ESP-IDF development. My project follows Expressif’s standard structure. I want to include a C++ BLE library (esp-nimble-cpp) from GitHub in my project. According to the library’s instructions, I should extract it into a component folder, which I’ve done. My project structure now looks like this:

- myProject/
        - CMakeLists.txt
        - sdkconfig
        - components/ 
          - component1/ 
            - CMakeLists.txt
            - Kconfig
            - src1.c
          - component2/ 
            - CMakeLists.txt
            - Kconfig
            - src1.c
            - include/ 
              - component2.h
          - esp-nimble-cpp-release-2.3/
            - CMakeLists.txt
            - Kconfig
            - src/
            - ... (other files and directories included in esp-nimble-cpp)
        - main/ 
          - CMakeLists.txt
          - src1.c
          - src2.c
        - build/

One of my components (component2) depends on esp-nimble-cpp. In VSCode, I’ve added #include "NimBLEDevice.h" and it seems to find the header file. However, classes defined in esp-nimble-cpp are not recognized.

I’ve tried adding REQUIRES esp-nimble-cpp-release-2.3 to the CMakeLists.txt in component2 (and variations of this), but it can’t find the library. What’s the correct way to configure this dependency in ESP-IDF?

NeuroAgent

To include an external library as a module dependency in ESP-IDF, you need to properly configure the CMakeLists.txt files in both your component and the external library component, using the REQUIRES directive correctly and ensuring the library’s build system is properly integrated. The issue you’re experiencing where headers are found but classes aren’t recognized typically indicates a CMake configuration problem rather than a missing include path.

Contents

Understanding ESP-IDF Component Dependencies

ESP-IDF uses a component-based architecture where each piece of functionality is organized as a self-contained component in the components/ directory. The framework automatically discovers and builds all components found in this directory, but explicit dependencies must be declared for proper compilation and linking.

The key insight is that ESP-IDF’s build system treats each component in the components/ folder as an independent module that can depend on other components within the same project. When you place esp-nimble-cpp-release-2.3 in your components/ directory, ESP-IDF recognizes it as a component, but you need to properly declare the dependency relationship in your CMakeLists.txt files.

Correct CMakeLists.txt Configuration

For your specific case, you need to modify the CMakeLists.txt file in component2 to properly declare the dependency on the esp-nimble-cpp component. Here’s the correct approach:

cmake
# In component2/CMakeLists.txt
idf_component_register(
    SRCS "src1.c"
    INCLUDE_DIRS "include"
    REQUIRES esp-nimble-cpp-release-2.3
)

However, the issue might be that the component name in the REQUIRES directive must match the component’s directory name exactly. In your case, the component directory is esp-nimble-cpp-release-2.3, so REQUIRES esp-nimble-cpp-release-2.3 should work. If it’s not being found, there might be an issue with how the external library’s CMakeLists.txt is configured.

According to Espressif’s documentation on porting external libraries, external libraries need proper CMakeLists.txt configuration to work as ESP-IDF components. The esp-nimble-cpp library should already have this configuration since it’s designed for ESP-IDF.

Alternative Methods for External Libraries

If the REQUIRES approach isn’t working, you have several alternative methods to include external libraries:

Method 1: Using idf_component_register with INCLUDE_DIRS and REQUIRES

Ensure both components are properly configured:

cmake
# In esp-nimble-cpp-release-2.3/CMakeLists.txt
idf_component_register(
    SRCS "src/*.cpp"  # Adjust path to actual source files
    INCLUDE_DIRS "include"
)

# In component2/CMakeLists.txt
idf_component_register(
    SRCS "src1.c"
    INCLUDE_DIRS "include"
    REQUIRES esp-nimble-cpp-release-2.3
)

Method 2: Manual Configuration

If the automatic discovery doesn’t work, you can manually configure the dependency:

cmake
# In component2/CMakeLists.txt
idf_component_register(
    SRCS "src1.c"
    INCLUDE_DIRS "include"
    INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../esp-nimble-cpp-release-2.3/include"
    REQUIRES esp-nimble-cpp-release-2.3
)

Method 3: Using CMake’s find_package

For more complex libraries, you might need to use CMake’s package finding mechanism:

cmake
# In component2/CMakeLists.txt
find_package(esp-nimble-cpp REQUIRED)

idf_component_register(
    SRCS "src1.c"
    INCLUDE_DIRS "include"
    INCLUDE_DIRS "${ESP_NIMBLE_CPP_INCLUDE_DIRS}"
    LIBRARIES "${ESP_NIMBLE_CPP_LIBRARIES}"
)

Troubleshooting Your esp-nimble-cpp Integration

Since you mentioned that #include "NimBLEDevice.h" works but classes aren’t recognized, here are specific troubleshooting steps:

1. Verify Component Name Matching

The component name in REQUIRES must exactly match the directory name. In your case:

  • Directory name: esp-nimble-cpp-release-2.3
  • Required in CMakeLists.txt: REQUIRES esp-nimble-cpp-release-2.3

2. Check External Library’s CMakeLists.txt

Ensure the esp-nimble-cpp library has a proper CMakeLists.txt file that registers it as a component. It should look something like this:

cmake
idf_component_register(
    SRCS "src/*.cpp"
    INCLUDE_DIRS "include"
    REQUIRES nvs_flash esp_bt)

3. Verify Include Paths

Even though the header is found, the include paths might not be complete. Check if you need additional include directories:

cmake
# In component2/CMakeLists.txt
idf_component_register(
    SRCS "src1.c"
    INCLUDE_DIRS "include"
    INCLUDE_DIRS "../esp-nimble-cpp-release-2.3/include"
    REQUIRES esp-nimble-cpp-release-2.3
)

4. Check for Linking Issues

The header might be found but the library might not be linked. Add explicit linking if needed:

cmake
# In component2/CMakeLists.txt
idf_component_register(
    SRCS "src1.c"
    INCLUDE_DIRS "include"
    REQUIRES esp-nimble-cpp-release-2.3
    LDFRAMES -lnimble_cpp  # Adjust based on actual library name
)

Best Practices for Component Dependencies

When working with external libraries in ESP-IDF:

  1. Use Component Naming Convention: Keep component names descriptive but consistent. Avoid spaces and special characters.

  2. Verify Library Compatibility: Ensure the external library is compatible with your ESP-IDF version. Some libraries might require specific ESP-IDF versions.

  3. Check Library Documentation: Many ESP-IDF-compatible libraries have specific integration instructions. Follow those first.

  4. Test Incrementally: Add dependencies one at a time and verify each step works before adding more.

  5. Clean Build: After making configuration changes, clean your build directory (rm -rf build) and rebuild.

  6. Use ESP-IDF’s Component Manager: For popular libraries, check if they’re available through ESP-IDF’s component manager with idf.py component install.

For your specific case with esp-nimble-cpp, if the standard approaches don’t work, you might want to check if there are any specific integration requirements or examples in the library’s documentation or GitHub repository. Some libraries require additional configuration or might have specific build flags that need to be set.

Sources

  1. Porting a library to an ESP-IDF component · Developer Portal
  2. ESP-IDF Programming Guide - Component System
  3. ESPHome custom component integration examples

Conclusion

To successfully include the esp-nimble-cpp library as a dependency in your ESP-IDF project, ensure you have the correct CMakeLists.txt configuration with the exact component name in the REQUIRES directive, verify the external library’s build configuration, and check for any additional include paths or linking requirements needed. The ESP-IDF component system is powerful but requires precise configuration to work correctly with external dependencies. Start with the basic REQUIRES approach, and if that doesn’t work, explore alternative methods like manual include path configuration or find_package usage.