"src/idf/secure_boot_signatures.c")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_PRIV_INCLUDEDIRS "include_bootloader")
- set(COMPONENT_REQUIRES soc) #unfortunately the header directly uses SOC registers
- set(COMPONENT_PRIV_REQUIRES spi_flash mbedtls efuse)
+ set(COMPONENT_REQUIRES mbedtls soc) #unfortunately the header directly uses SOC registers
+ set(COMPONENT_PRIV_REQUIRES spi_flash efuse)
endif()
register_component()
\ No newline at end of file
"task_wdt.c")
set(COMPONENT_ADD_INCLUDEDIRS "include")
- set(COMPONENT_REQUIRES driver esp_event efuse soc) #unfortunately rom/uart uses SOC registers directly
+ set(COMPONENT_REQUIRES app_update driver esp_event efuse pthread soc) #unfortunately rom/uart uses SOC registers directly
# driver is a public requirement because esp_sleep.h uses gpio_num_t & touch_pad_t
# app_update is added here because cpu_start.c uses esp_ota_get_app_description() function.
set(COMPONENT_PRIV_REQUIRES
app_trace app_update bootloader_support log mbedtls nvs_flash
- pthread smartconfig_ack spi_flash vfs wpa_supplicant espcoredump esp_common esp_wifi)
+ smartconfig_ack spi_flash vfs wpa_supplicant espcoredump esp_common esp_wifi)
set(COMPONENT_ADD_LDFRAGMENTS linker.lf ld/esp32_fragments.lf)
-register_config_only_component()
+set(COMPONENT_PRIV_REQUIRES bootloader)
+register_component()
string(REPLACE ";" " " ESPTOOLPY_FLASH_PROJECT_OPTIONS "${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS}")
set(ESPTOOLPY_FLASH_PROJECT_OPTIONS
"flash_ops.c"
"partition.c"
"spi_flash_rom_patch.c")
- set(COMPONENT_PRIV_REQUIRES bootloader_support app_update soc)
+ set(COMPONENT_REQUIRES app_update)
+ set(COMPONENT_PRIV_REQUIRES bootloader_support soc)
endif()
set(COMPONENT_ADD_INCLUDEDIRS include)
cmake_minimum_required(VERSION 3.5)
project(idf_as_lib C)
-# The source file main.c contains app_main() definition
-add_executable(${CMAKE_PROJECT_NAME}.elf main.c)
+if("${TARGET}" STREQUAL "esp32")
+ # Include for ESP-IDF build system functions
+ include($ENV{IDF_PATH}/tools/cmake/idf.cmake)
+ # Create idf::esp32 and idf::freertos static libraries
+ idf_build_process(esp32
+ # try and trim the build; additional components
+ # will be included as needed based on dependency tree
+ #
+ # although esptool_py does not generate static library,
+ # processing the component is needed for flashing related
+ # targets and file generation
+ COMPONENTS esp32 freertos esptool_py
+ SDKCONFIG ${CMAKE_BINARY_DIR}/sdkconfig
+ BUILD_DIR ${CMAKE_BINARY_DIR})
+else()
+ # Create stubs for esp32 and freertos, stub::esp32 and stub::freertos
+ add_subdirectory(stubs/esp32)
+ add_subdirectory(stubs/freertos)
+ add_subdirectory(stubs/spi_flash)
+endif()
-# Provides idf_import_components() and idf_link_components()
-include($ENV{IDF_PATH}/tools/cmake/idf_functions.cmake)
+set(elf_file ${CMAKE_PROJECT_NAME}.elf)
+add_executable(${elf_file} main.c)
-# Create artifacts used for flashing the project to target chip
-set(IDF_BUILD_ARTIFACTS ON)
-set(IDF_PROJECT_EXECUTABLE ${CMAKE_PROJECT_NAME}.elf)
-set(IDF_BUILD_ARTIFACTS_DIR ${CMAKE_BINARY_DIR})
+# Link the static libraries to the executable
+if("${TARGET}" STREQUAL "esp32")
+ target_link_libraries(${elf_file} idf::esp32 idf::freertos idf::spi_flash)
+ # Attach additional targets to the executable file for flashing,
+ # linker script generation, partition_table generation, etc.
+ idf_build_executable(${elf_file})
+else()
+ target_link_libraries(${elf_file} stub::esp32 stub::freertos stub::spi_flash)
+endif()
-# Trim down components included in the build. Although freertos and spi_flash are the ones needed by the application
-# itself, the bootloader and esptool_py components are also needed in order to create the artifacts to be used
-# for flashing to the target chip
-set(IDF_COMPONENTS freertos spi_flash bootloader esptool_py)
-
-# Wraps add_subdirectory() to create library targets for components, and then return them using the specified variable
-idf_import_components(components $ENV{IDF_PATH} esp-idf)
-
-# Wraps target_link_libraries() to link processed components by idf_import_components to target
-idf_link_components(${CMAKE_PROJECT_NAME}.elf "${components}")
\ No newline at end of file
+set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
\ No newline at end of file
# Using ESP-IDF in Custom CMake Projects
-This example illustrates using ESP-IDF components as libraries in custom CMake projects. This builds
-an equivalent application to the `hello_world` example under `examples/get-started/hello_world`.
+This example illustrates using ESP-IDF components as libraries in custom CMake projects. The application
+in this example can run on either host or on an ESP32, and the appropriate libraries are linked
+to the executable depending on which target is specified. If the target is an ESP32, the libraries
+created from ESP-IDF components are linked. On the other hand, stub libraries are linked if example
+is meant to be run on the host to simulate the same application behavior.
+
+The application in this example is equivalent to the `hello_world` example under `examples/get-started/hello_world`.
## Example Flow
Users looking at this example should focus on the [top-level CMakeLists.txt file](./CMakeLists.txt). This builds an
-application that can run on targets without relying on the typical ESP-IDF application template. The application itself
-follows a similar code flow to the aforementioned `hello_world` example.
+application that can run on the target without relying on the typical ESP-IDF application template.
### Output
## Building this Example
-To build this example, run the following commands from this directory:
+To build this example, the user can either run [build-esp32.sh](./build-esp32.sh) to build for the ESP32
+or run [build.sh](./build.sh) to build for the host:
```bash
-# Create a build directory, and change location to that directory.
-mkdir build; cd build
-# Invoke CMake, specifying the top-level CMakeLists.txt directory and toolchain file to use. This will generate
-# the build system files.
-cmake .. -DCMAKE_TOOLCHAIN_FILE=$IDF_PATH/tools/cmake/toolchain-esp32.cmake -DIDF_TARGET=esp32
-# Build using the generated build system files.
-cmake --build .
+# Builds the example for ESP32
+./build-esp32.sh
```
-Or, execute `build.sh` script, which contains the same commands mentioned above.
+or
-## Flashing and Running this Example
+```bash
+# Builds the example to run on host
+./build.sh
+```
-To flash this example, we will have to invoke `esptool.py` and `idf_monitor.py` manually. While still in the build directory:
+## Flashing and Running this Example
-### Flashing to target
+To flash and run the example, users can run either [run-esp32.sh](./run-esp32.sh) or [run.sh](./run.sh) depending
+on what the example was built for. In the case of ``run-esp32.sh``, the port needs to be specified:
```bash
-# Write project binaries to flash.
-esptool.py --port /dev/ttyUSB0 write_flash @flash_project_args
+# Run the example on device connected to /dev/ttyUSB1
+./run-esp32.sh /dev/ttyUSB1
```
-### Running on target
+or
```bash
-# Monitor the output of the flashed firmware.
-idf_monitor.py --port /dev/ttyUSB0 idf_as_lib.elf
+# Run the example on the host
+./run.sh
```
-Of course, you should replace the specified ports in the commands specified above to the proper one where your device
-is connected.
-
---
There is a discussion on using ESP-IDF in custom CMake projects in the programming guide under `API Guides` -> `Build System (CMake)` -> `Using ESP-IDF in Custom CMake Projects`
--- /dev/null
+#!/bin/bash
+rm -rf build && mkdir build && cd build
+cmake .. -DCMAKE_TOOLCHAIN_FILE=$IDF_PATH/tools/cmake/toolchain-esp32.cmake -DTARGET=esp32 -GNinja
+cmake --build .
\ No newline at end of file
#!/bin/bash
-#
-# Build this example, which does not use that standard IDF app template. See README.md for
-# more information about the build and how to run this example on the target once built.
-
-mkdir build; cd build
-cmake .. -DCMAKE_TOOLCHAIN_FILE=$IDF_PATH/tools/cmake/toolchain-esp32.cmake -DIDF_TARGET=esp32
+rm -rf build && mkdir build && cd build
+cmake ..
cmake --build .
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+cd build
+python $IDF_PATH/components/esptool_py/esptool/esptool.py -p $1 write_flash @flash_project_args
+python $IDF_PATH/tools/idf_monitor.py -p $1 idf_as_lib.elf
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+cd build
+./idf_as_lib.elf
\ No newline at end of file
--- /dev/null
+add_library(stub_esp32 STATIC system_api.c flash_ops.c cpu_start.c)
+target_include_directories(stub_esp32 PUBLIC .)
+add_library(stub::esp32 ALIAS stub_esp32)
+
+target_link_libraries(stub_esp32 "-u app_main")
+target_link_libraries(stub_esp32 stub::spi_flash)
\ No newline at end of file
--- /dev/null
+#include <stdbool.h>
+#include <setjmp.h>
+
+extern void app_main();
+jmp_buf buf;
+
+int main()
+{
+ setjmp(buf);
+ app_main();
+}
\ No newline at end of file
--- /dev/null
+#pragma once
+#include <stdint.h>
+
+#define CHIP_FEATURE_EMB_FLASH (1UL << 0)
+#define CHIP_FEATURE_BT (1UL << 4)
+#define CHIP_FEATURE_BLE (1UL << 5)
+
+typedef struct {
+ uint32_t features; //!< bit mask of CHIP_FEATURE_x feature flags
+ uint8_t cores; //!< number of CPU cores
+ uint8_t revision; //!< chip revision number
+} esp_chip_info_t;
+
+void esp_restart(void);
+void esp_chip_info(esp_chip_info_t* out_info);
\ No newline at end of file
--- /dev/null
+#include "esp_spi_flash.h"
+
+int spi_flash_get_chip_size()
+{
+ return (1024 * 1024 * 1024);
+}
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+#include <unistd.h>
+#include <setjmp.h>
+#include "esp_system.h"
+
+extern jmp_buf buf;
+
+void esp_restart(void)
+{
+ printf("\n");
+ sleep(1); // pause for dramatic effect
+ longjmp(buf, 0);
+}
+
+void esp_chip_info(esp_chip_info_t* out_info)
+{
+ out_info->cores = 8;
+ out_info->features = (uint32_t) -1;
+}
\ No newline at end of file
--- /dev/null
+add_library(stub_freertos STATIC task.c)
+target_include_directories(stub_freertos PUBLIC .)
+add_library(stub::freertos ALIAS stub_freertos)
\ No newline at end of file
--- /dev/null
+#pragma once
+
+#include <stdint.h>
+
+#define portTICK_PERIOD_MS 1000
+
+void vTaskDelay( const uint32_t xTicksToDelay );
\ No newline at end of file
--- /dev/null
+#include <unistd.h>
+#include "freertos/task.h"
+
+void vTaskDelay( const uint32_t xTicksToDelay )
+{
+ sleep(xTicksToDelay);
+}
\ No newline at end of file
--- /dev/null
+add_library(stub_spi_flash INTERFACE)
+target_include_directories(stub_spi_flash INTERFACE .)
+add_library(stub::spi_flash ALIAS stub_spi_flash)
\ No newline at end of file
--- /dev/null
+#pragma once
+
+#include <stddef.h>
+
+int spi_flash_get_chip_size();
\ No newline at end of file
touch ${LOG_SUSPECTED}
SDKCONFIG_DEFAULTS_CI=sdkconfig.ci
-EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name CMakeLists.txt | grep -v "/components/" | grep -v "/common_components/" | grep -v "/main/" | sort )
+EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name CMakeLists.txt | grep -v "/components/" | grep -v "/common_components/" | grep -v "/main/" | grep -v "/idf_as_lib/stubs/" | sort )
if [ $# -eq 0 ]
then
idf.py build >>${BUILDLOG} 2>&1
else
rm -rf build &&
- ./build.sh >>${BUILDLOG} 2>&1
+ ./build-esp32.sh >>${BUILDLOG} 2>&1
fi ||
{
RESULT=$?; FAILED_EXAMPLES+=" ${EXAMPLE_NAME}" ;
tools/ldgen/ldgen.py
tools/ldgen/test/test_fragments.py
tools/ldgen/test/test_generation.py
+examples/build_system/cmake/idf_as_lib/build-esp32.sh
examples/build_system/cmake/idf_as_lib/build.sh
+examples/build_system/cmake/idf_as_lib/run-esp32.sh
+examples/build_system/cmake/idf_as_lib/run.sh
examples/storage/parttool/parttool_example.py
examples/system/ota/otatool/otatool_example.py
tools/check_kconfigs.py
rm sdkconfig.defaults;
print_status "Building a project with CMake library imported and PSRAM workaround, all files compile with workaround"
+ # Test for libraries compiled within ESP-IDF
rm -rf build
echo "CONFIG_SPIRAM_SUPPORT=y" >> sdkconfig.defaults
echo "CONFIG_SPIRAM_CACHE_WORKAROUND=y" >> sdkconfig.defaults
idf.py -C $IDF_PATH/examples/build_system/cmake/import_lib -B `pwd`/build reconfigure -D SDKCONFIG_DEFAULTS="`pwd`/sdkconfig.defaults"
grep -q '"command"' build/compile_commands.json || failure "compile_commands.json missing or has no no 'commands' in it"
(grep '"command"' build/compile_commands.json | grep -v mfix-esp32-psram-cache-issue) && failure "All commands in compile_commands.json should use PSRAM cache workaround"
- rm sdkconfig.defaults
+ rm -r sdkconfig.defaults build
+ # Test for external libraries in custom CMake projects with ESP-IDF components linked
+ mkdir build && touch build/sdkconfig
+ echo "CONFIG_SPIRAM_SUPPORT=y" >> build/sdkconfig
+ echo "CONFIG_SPIRAM_CACHE_WORKAROUND=y" >> build/sdkconfig
+ # note: we just need to run cmake
+ (cd build && cmake $IDF_PATH/examples/build_system/cmake/idf_as_lib -DCMAKE_TOOLCHAIN_FILE=$IDF_PATH/tools/cmake/toolchain-esp32.cmake -DTARGET=esp32)
+ grep -q '"command"' build/compile_commands.json || failure "compile_commands.json missing or has no no 'commands' in it"
+ (grep '"command"' build/compile_commands.json | grep -v mfix-esp32-psram-cache-issue) && failure "All commands in compile_commands.json should use PSRAM cache workaround"
+ rm -r build
print_status "Make sure a full build never runs '/usr/bin/env python' or similar"
OLDPATH="$PATH"