diff --git a/idf_component_examples/Hello_External_Libs/.gitignore b/idf_component_examples/Hello_External_Libs/.gitignore new file mode 100644 index 00000000000..b44f9082cb3 --- /dev/null +++ b/idf_component_examples/Hello_External_Libs/.gitignore @@ -0,0 +1,7 @@ +build +.cache +components +managed_components +dependencies.lock +sdkconfig +sdkconfig.old diff --git a/idf_component_examples/Hello_External_Libs/CMakeLists.txt b/idf_component_examples/Hello_External_Libs/CMakeLists.txt new file mode 100644 index 00000000000..5d65f458600 --- /dev/null +++ b/idf_component_examples/Hello_External_Libs/CMakeLists.txt @@ -0,0 +1,18 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.17) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(Hello_External_Libs) + +# Download BufferUtils library +include(FetchContent) +FetchContent_Populate(BufferUtils + URL https://github.com/bakercp/BufferUtils/archive/refs/tags/3.0.0.zip + SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/components/BufferUtils +) + +# Convert the Arduino libraries that are missing 'CMakeLists.txt' into IDF components +convert_arduino_libraries_to_components() diff --git a/idf_component_examples/Hello_External_Libs/README.md b/idf_component_examples/Hello_External_Libs/README.md new file mode 100644 index 00000000000..f666805dd8a --- /dev/null +++ b/idf_component_examples/Hello_External_Libs/README.md @@ -0,0 +1,63 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | + +# _Hello world example_ + +This is the simplest buildable example made to be used as a template for new projects running Arduino-esp32 as an ESP-IDF component. +See [Arduino-esp32](https://components.espressif.com/components/espressif/arduino-esp32) in ESP Registry. + +## How to use example + +To create a ESP-IDF project from this example with the latest release of Arduino-esp32, you can simply run command: `idf.py create-project-from-example "espressif/arduino-esp32:hello_world"`. +ESP-IDF will download all dependencies needed from the component registry and setup the project for you. + +If you want to use cloned Arduino-esp32 repository, you can build this example directly. +Go to the example folder `arduino-esp32/idf_component_examples/Hello_world`. +First you need to comment line 6 `pre_release: true` in examples `/main/idf_component.yml`. +Then just run command: `idf.py build`. + +## Example folder contents + +The project **Hello_world** contains one source file in C++ language [main.cpp](main/main.cpp). The file is located in folder [main](main). + +ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt` +files that provide set of directives and instructions describing the project's source files and targets +(executable, library, or both). + +Below is short explanation of remaining files in the project folder. + +``` +├── CMakeLists.txt +├── main +│   ├── CMakeLists.txt +│ ├── idf_component.yml +│   └── main.cpp +└── README.md This is the file you are currently reading +``` + +## How to add Arduino libraries + +In the project create folder `components/` and clone the library there. +In the library folder create new CMakeLists.txt file, add lines shown below to the file and edit the SRCS to match the library source files. + +``` +idf_component_register(SRCS "user_library.cpp" "another_source.c" + INCLUDE_DIRS "." + REQUIRES arduino-esp32 + ) +``` + +Below is structure of the project folder with the Arduino libraries. + +``` +├── CMakeLists.txt +├── components +│   ├── user_library +│   │   ├── CMakeLists.txt This needs to be added +│   │   ├── ... +├── main +│   ├── CMakeLists.txt +│ ├── idf_component.yml +│   └── main.cpp +└── README.md This is the file you are currently reading +``` diff --git a/idf_component_examples/Hello_External_Libs/main/CMakeLists.txt b/idf_component_examples/Hello_External_Libs/main/CMakeLists.txt new file mode 100644 index 00000000000..9eb7ec47a07 --- /dev/null +++ b/idf_component_examples/Hello_External_Libs/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.cpp" + INCLUDE_DIRS ".") diff --git a/idf_component_examples/Hello_External_Libs/main/idf_component.yml b/idf_component_examples/Hello_External_Libs/main/idf_component.yml new file mode 100644 index 00000000000..f955824767c --- /dev/null +++ b/idf_component_examples/Hello_External_Libs/main/idf_component.yml @@ -0,0 +1,6 @@ +## IDF Component Manager Manifest File +dependencies: + espressif/arduino-esp32: + version: "*" + override_path: "../../../" + pre_release: true diff --git a/idf_component_examples/Hello_External_Libs/main/main.cpp b/idf_component_examples/Hello_External_Libs/main/main.cpp new file mode 100644 index 00000000000..60c84683479 --- /dev/null +++ b/idf_component_examples/Hello_External_Libs/main/main.cpp @@ -0,0 +1,15 @@ +#include "Arduino.h" +#include "CircularBuffer.h" + +void setup() { + Serial.begin(115200); + + uint8_t data[10]; + CircularBuffer buffer(data, sizeof(data)); + buffer.put(1); +} + +void loop() { + Serial.println("Hello world!"); + delay(1000); +} diff --git a/idf_component_examples/Hello_External_Libs/sdkconfig.defaults b/idf_component_examples/Hello_External_Libs/sdkconfig.defaults new file mode 100644 index 00000000000..bb723653f8a --- /dev/null +++ b/idf_component_examples/Hello_External_Libs/sdkconfig.defaults @@ -0,0 +1,12 @@ +# +# Arduino ESP32 +# +CONFIG_AUTOSTART_ARDUINO=y +# end of Arduino ESP32 + +# +# FREERTOS +# +CONFIG_FREERTOS_HZ=1000 +# end of FREERTOS +# end of Component config diff --git a/project_include.cmake b/project_include.cmake new file mode 100644 index 00000000000..4ad1023498b --- /dev/null +++ b/project_include.cmake @@ -0,0 +1,130 @@ +function(convert_arduino_libraries_to_components) + # Base directory for libraries relative to the project root + set(libs_dir_abs "${CMAKE_SOURCE_DIR}/components") + + if(NOT IS_DIRECTORY "${libs_dir_abs}") + message(FATAL_ERROR "The components dir (${libs_dir_abs}) is not a valid directory.") + return() + endif() + + # Get the name of the arduino component. It is the same as the name of the current directory. + get_filename_component(arduino_component_name ${CMAKE_CURRENT_FUNCTION_LIST_DIR} NAME) + message(STATUS "Arduino component name: ${arduino_component_name}") + + # Try to figure out the main component name or skip it + if(IS_DIRECTORY "${CMAKE_SOURCE_DIR}/main") + set(main_component_name "main") + elseif(IS_DIRECTORY "${CMAKE_SOURCE_DIR}/src") + set(main_component_name "src") + else() + set(main_component_name "") + endif() + message(STATUS "Main component name: ${main_component_name}") + + file(GLOB children RELATIVE ${libs_dir_abs} ${libs_dir_abs}/*) + foreach(child ${children}) + set(child_dir "${libs_dir_abs}/${child}") + set(properties_file "${child_dir}/library.properties") + set(src_dir "${child_dir}/src") + set(utility_dir "${child_dir}/utility") + set(component_cmakelist "${child_dir}/CMakeLists.txt") + + # Skip .DS_Store, files and folders that do not already contain CMakeLists.txt + if(NOT "${child}" STREQUAL ".DS_Store" AND IS_DIRECTORY "${child_dir}" AND NOT EXISTS "${component_cmakelist}") + # Require library.properties + if(EXISTS "${properties_file}") + # If we have src folder, then handle the new library structure + if(IS_DIRECTORY "${src_dir}") + message(STATUS "Processing 1.5+ compatible library '${child}' in '${libs_dir_abs}'") + # Read properties + set(ldflags "") + set(precompiled "") + file(STRINGS "${properties_file}" properties) + foreach(property ${properties}) + string(REGEX MATCH "ldflags=(.*)" _ ${property}) + if(CMAKE_MATCH_COUNT GREATER 0) + set(ldflags "${CMAKE_MATCH_1}") + endif() + string(REGEX MATCH "precompiled=(.*)" _ ${property}) + if(CMAKE_MATCH_COUNT GREATER 0) + set(precompiled "${CMAKE_MATCH_1}") + endif() + endforeach() + + # Start CMakeLists.txt generation + file(WRITE ${component_cmakelist} "idf_component_register(") + + # Sources are not compiled only if precompiled=full and precompiled library for our target exists + if(NOT precompiled STREQUAL "full" OR NOT EXISTS "${src_dir}/${IDF_TARGET}/lib${child}.a") + file(APPEND ${component_cmakelist} "SRCS ") + file(GLOB_RECURSE src_files "${src_dir}/*.c" "${src_dir}/*.cpp") + foreach(src_file ${src_files}) + string(REPLACE "${child_dir}/" "" src_file "${src_file}") + file(APPEND ${component_cmakelist} "\"${src_file}\" ") + endforeach() + endif() + # Add src folder to includes + file(APPEND ${component_cmakelist} "INCLUDE_DIRS \"src\" ") + + # Add component requires + file(APPEND ${component_cmakelist} "PRIV_REQUIRES ${arduino_component_name} ${main_component_name})\n") + + # Add any custom LD_FLAGS, if defined + if(NOT "${ldflags}" STREQUAL "") + file(APPEND ${component_cmakelist} "target_link_libraries(\${COMPONENT_TARGET} INTERFACE \"${ldflags}\")\n") + endif() + + # If this lib has precompiled libs and they match our target, get them + if((precompiled STREQUAL "true" OR precompiled STREQUAL "full") AND IS_DIRECTORY "${src_dir}/${IDF_TARGET}") + file(GLOB_RECURSE lib_files "${src_dir}/${IDF_TARGET}/lib*.a") + foreach(lib_file ${lib_files}) + string(REPLACE "${child_dir}/" "" lib_file "${lib_file}") + file(APPEND ${component_cmakelist} "set_property(TARGET \${COMPONENT_TARGET} APPEND_STRING PROPERTY INTERFACE_LINK_LIBRARIES \"${lib_file}\")\n") + endforeach() + endif() + + # We do not have 'src' folder. Import a flat structure (1.0 style) + else() + message(STATUS "Processing 1.0 compatible library '${child}' in '${libs_dir_abs}'") + file(WRITE ${component_cmakelist} "idf_component_register(SRCS ") + + # Add sources from the root folder + file(GLOB src_files "${child_dir}/*.c" "${child_dir}/*.cpp") + foreach(src_file ${src_files}) + string(REPLACE "${child_dir}/" "" src_file "${src_file}") + file(APPEND ${component_cmakelist} "\"${src_file}\" ") + endforeach() + + # Add sources from the utility folder if it exists + if(IS_DIRECTORY "${utility_dir}") + file(GLOB utility_files "${utility_dir}/*.c" "${utility_dir}/*.cpp") + foreach(utility_file ${utility_files}) + string(REPLACE "${child_dir}/" "" utility_file "${utility_file}") + file(APPEND ${component_cmakelist} "\"${utility_file}\" ") + endforeach() + endif() + + # Add root folder to includes + file(APPEND ${component_cmakelist} "INCLUDE_DIRS \".\" ") + + # Add the utility folder to includes if it exists + if(IS_DIRECTORY "${utility_dir}") + file(APPEND ${component_cmakelist} "\"utility\" ") + endif() + + # Require arduino and main components to suceed in compilation + file(APPEND ${component_cmakelist} "PRIV_REQUIRES ${arduino_component_name} ${main_component_name})\n") + endif() + + message(STATUS "Created IDF component for ${child}") + + # Include the component's CMakeLists.txt to execute it + # add_subdirectory("${child_dir}") # Using this method produces the following error: 'Called idf_component_register from a non-component directory.' + # list(APPEND EXTRA_COMPONENT_DIRS ${child_dir}) # Using this method does not help + + else() + message(STATUS "Skipped ${child}: Required 'library.properties' not found") + endif() + endif() + endforeach() +endfunction()