How to include Espressif vendor components and files?

I wanted to implement BLE functionality where the ESP32 acts as a client. This requires me to include the following files:

#include "bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gattc_api.h"
#include "esp_gatt_defs.h"
#include "esp_bt_main.h"
#include "esp_gatt_common_api.h"

These files are located in the Espressif vendor folder, e.g. “/amazon-freertos/vendors/espressif/esp-idf/components/bt/bluedroid/”

These results in my include statements looking like so:
#include "../../amazon-freertos/vendors/espressif/esp-idf/components/bt/include/esp_bt.h"
#include "../../amazon-freertos/vendors/espressif/esp-idf/components/bt/bluedroid/api/include/api/esp_gap_ble_api.h"

This is less than ideal and I was wondering what the correct way to link those components is?
Thanks!

Hello isnore,

Can you provide information about how your project is setup, what build system you are using, and what version of the source code you’re working with?

Thanks,
Joshua

Our project layout:
/components
----/wifi
--------/include
------------dns.h < this is the file that tries to include the common.h
--------/src
--------CMakeLists.txt
----/common
--------/include
------------common.h
--------/src
------------common.c
--------CMakeLists.txt
/src
----main.c
----CMakeLists.txt

When I go to include files from the component by writing,

#include "common/common.h"

the linker is unable to find the file and says that it doesn’t exist.

However, I know that the common component is being built since the CMake logs show the following line (which if you scroll you can see common is built):

Component names: soc log heap freertos vfs newlib esp_ringbuf driver tcpip_adapter esp_event partition_table app_update spi_flash mbedtls micro-ecc bootloader_support efuse xtensa-debug-module app_trace ethernet nvs_flash pthread smartconfig_ack wpa_supplicant espcoredump esp32 cxx common ota wifi amazon-freertos-common secure_sockets esp_http_server freertos_plus_tcp bootloader nimble bt console esp_adc_cal esptool_py expat wear_levelling sdmmc fatfs freemodbus lwip nghttp openssl spiffs ulp

This shows all of the components being compiled and on the next line it also shows the paths for each of those components - I didn’t copy & paste that for brevity.

My src/CMakeLists.txt

add_compile_options(-w)

cmake_minimum_required(VERSION 3.13)

project(freertos_examples)

add_executable(esp32_app src/main.c)

# Tell IDF build to link against this target.
set(IDF_PROJECT_EXECUTABLE esp32_app)

# Add some extra components. IDF_EXTRA_COMPONENT_DIRS is an variable used by ESP-IDF
# to collect extra components.
get_filename_component(EXTRA_COMPONENT_DIRS components ABSOLUTE)

# Add some external components to the project
set(IDF_EXTRA_COMPONENT_DIRS ${EXTRA_COMPONENT_DIRS})

# As of now there's no offical way to redefine config files outside of Amazon FreeRTOS source tree.
# This is a temporary approach to inject an include path so that this takes precedence over the
# config file directory inside Amazon FreeRTOS.
include_directories(BEFORE amazon-freertos-configs)

# Add amazon freertos as an subdirectory. AFR_BOARD tells which board to target.
set(AFR_BOARD espressif.esp32_devkitc CACHE INTERNAL "")
add_subdirectory(amazon-freertos)

target_link_libraries(esp32_app PRIVATE AFR::demo_mqtt)
target_link_libraries(esp32_app PRIVATE 3rdparty::lwip)

Wifi & Common Component CMakeLists.txt

# include paths of this components.
set(COMPONENT_ADD_INCLUDEDIRS include)

# source files of this components.
set(COMPONENT_SRCDIRS src)
# add this component, this will define a CMake library target.
register_component()

target_link_libraries(${COMPONENT_TARGET} PRIVATE AFR::wifi)
target_link_libraries(${COMPONENT_TARGET} PRIVATE 3rdparty::lwip)
target_link_libraries(${COMPONENT_TARGET} PRIVATE 3rdparty::lwip_osal)

Solutions I’ve tried:

  1. Hardcoding a relative path, e.g.
#include "../../common/include/common.h"

This does work but is less than ideal, especially with many header files.

I’ve spent quite a bit of time on this and am not sure how to actually include the files. I was hoping to get some help with this issue. Please let me know if any more information or context is required. Also, just as a final note, this is not the first time I am compiling my project. I have made other components and had them work fine, so I don’t think its a set up issue or an issue related to the CMake command I am running.

Thanks!

Compiler & CMake Info
Note: I’m using CLion

CMake Command:

/usr/local/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DAFR_ENABLE_LWIP=1 -DCMAKE_TOOLCHAIN_FILE=amazon-freertos/tools/cmake/toolchains/xtensa-esp32.cmake -GNinja /Users/vp/esp/Pebble_ESP32_Firmware

– The C compiler identification is GNU 5.2.0
– The CXX compiler identification is GNU 5.2.0

AmazonFreertos Version
I have the latest commit on the master branch
amazon-freertos @ 45bcc3a

Thank you for providing this detailed information.

You can avoid specifying the explicit path by having the header file’s include path in your compiler’s include path. In Cmake this is done by specifying a dependency on the target that defines the include paths for the header files. Espressif has a wrapper around cmake targets and calls them components. The way that you will add the dependency is different depending on if it is a Espressif component or a cmake target.

In your original question, the bluetooth related files that you want to include are defined by the Espressif “bt” component. If I’m understanding correctly, you want one of your components to depend on this “bt” component. In this case, in the CMakeLists.txt file for your component, add the following line before “register_component()”:
“set(COMPONENT_REQUIRES bt)”

In your follow up question, it sounds like you are trying to include the header files of one component that you defined in a header file of a different component that you defined. To do this, you can add a dependency in the same way as the bluetooth module, since they are both “components”.

It looks like you may have some other issues with your project such as the location of the CMakeLists.txt file that you are initially calling and how you are adding component subdirectories.

To help show what I explained and how to fix these errors, I created an example that you can run and compare with on a github branch:

It can be built in the root directory with the following command:
“cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=freertos/tools/cmake/toolchains/xtensa-esp32.cmake -GNinja”

In this example, I have created two components called “wifi” and “common”. The “wifi” component is set to depend on the “common” component and is able to include “common.h”. The “common” component is set to depend on the Espressif bluetooth component that is located at the path you described. In this example I was able to include the “esp_bt.h” header file that belongs to the bluetooth component. Here is a link to where Espressif is adding the header files as private:

I would note that the other header files that you listed are set to be private by Espressif, which means that they won’t be found even if you are correctly dependent on the bluetooth component.

For additional information on how to use the amazon-freertos github repo as a submodule with esp32, see the following link:
https://docs.aws.amazon.com/freertos/latest/userguide/getting_started_espressif.html#getting_started_espressif_cmake_project

Thanks for taking the time to make a whole git branch :slight_smile:

1) Still some linking issues

So I added the line

set(COMPONENT_REQUIRES common)

and it works! So thank you!
As a note, my include statement in wifi.h was:

#include "common.h"

and I’m wondering why it isn’t the following:

#include "common/common.h"

since I do have includes that follow that second pattern, such as:

#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"

Following this logic, I wrote,

set(COMPONENT_REQUIRES lwip)

and in my header file wrote,

#include "lwip/sockets.h"

but no luck :frowning: It doesn’t seem to link. I also tried just #include “sockets.h” but that didn’t work either. How come it works for some components such as bt but not others.

2) Implementation differences between components

This is also something that has confused me. For example, lets take the lwip component. There is one present in:

/amazon-freertos/libraries/3rdparty/lwip/src/include/lwip

and one in

/amazon-freertos/vendors/espressif/esp-idf/components/lwip

Do I have to worry about implementation differences?

Thanks!

For #include “common/common.h” to work, you would need to have the common.h header file inside of a folder named “common” and the path to the folder in your compiler’s include path.

The #include “freertos/FreeRTOS.h” statement compiles because the header file exists in a folder called “freertos” and the path to that folder is in your compiler’s include path.

For including the lwip component, you will need to build with the “AFR_ESP_LWIP” flag set to one. For example:
“cmake -S . -B build -DAFR_ESP_LWIP=1 -DCMAKE_TOOLCHAIN_FILE=freertos/tools/cmake/toolchains/xtensa-esp32.cmake -GNinja”

The lwip component is an exception because of a conditional used for choosing between the FreeRTOS+ TCP stack and the lwip stack.

You can see an example of how to use the lwip component in Archit’s response here:

1 Like

Thank you Joshua! Makes sense regarding the #include “common/common.h”.
I was able to link my own components as well as the lwip component using Archit’s response!

1 Like