feat(cmakev2): Added import_lib_direct example for cmakev2

This commit adds a new example at
examples/build_system/cmakev2/features/import_lib_direct to
demonstrate the cmakev2 ability to integrate with external CMake
projects easily.
This commit is contained in:
Sudeep Mohanty
2026-01-27 13:22:44 +01:00
parent fa57ea1a10
commit c735d9beb9
4 changed files with 194 additions and 0 deletions
@@ -0,0 +1,11 @@
# This example demonstrates a cmakev2 capability of importing an external
# C library via FetchContent, built by its own CMake, and linked directly
# to an IDF component without any IDF component wrapper for the library.
cmake_minimum_required(VERSION 3.22)
include($ENV{IDF_PATH}/tools/cmakev2/idf.cmake)
project(import_lib_direct C CXX ASM)
idf_project_default()
@@ -0,0 +1,61 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- |
# Import External C Library Directly (cmakev2)
This example demonstrates importing an external C library that is a pure CMake project. It is downloaded at configure time, built by its own CMake, and linked directly to the IDF app without wrapping it as an IDF component.
## Overview
In Build System v1, integrating third-party CMake libraries required wrapping them as IDF components (see the `import_lib` example). With cmakev2, CMake's `FetchContent` module can be used to fetch and build an external CMake library (lwjson) and link the library to an IDF component using `target_link_libraries`.
This example uses [lwjson](https://github.com/MaJerle/lwjson), a lightweight JSON parser for embedded systems.
## Project Structure
```
import_lib_direct/
├── CMakeLists.txt # Initialize the IDF project
├── README.md
└── main/
├── CMakeLists.txt # FetchContent for lwjson, register component, link
└── main.c # Uses lwjson API
```
## How It Works
1. The **main component's CMakeLists.txt** uses `FetchContent_Declare()` and `FetchContent_MakeAvailable()` to download and build lwjson at configure time. The fetched sources land in `./build/_deps/`.
2. After registering the main omponent with `idf_component_register`, it links the fetched library:
```cmake
target_link_libraries(${COMPONENT_LIB} PUBLIC lwjson)
```
3. **main.c** uses the lwjson API (`lwjson_init`, `lwjson_parse`, `lwjson_find`, etc.) to parse a sample JSON string and print device name, cores, features, and specs.
## How to Use
Build and flash the example:
```bash
idf.py set-target <target>
idf.py build
idf.py flash monitor
```
## Expected Output
```
I (275) import_lib_direct: lwjson library imported directly (downloaded, built, linked) without IDF component wrapper
I (275) import_lib_direct: Parsing JSON string...
I (285) import_lib_direct: Device name: ESP32
I (285) import_lib_direct: Number of cores: 2
I (285) import_lib_direct: Features:
I (295) import_lib_direct: - WiFi
I (295) import_lib_direct: - Bluetooth
I (295) import_lib_direct: - GPIO
I (305) import_lib_direct: Specifications:
I (305) import_lib_direct: Flash: 4MB
I (305) import_lib_direct: RAM: 520KB
I (315) import_lib_direct: Example complete!
```
@@ -0,0 +1,15 @@
# Fetch the external lwjson library at configure time.
include(FetchContent)
fetchcontent_declare(
lwjson
GIT_REPOSITORY https://github.com/MaJerle/lwjson.git
GIT_TAG v1.8.1
GIT_SHALLOW TRUE
)
fetchcontent_makeavailable(lwjson)
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")
# Link the fetched lwjson library to this component
target_link_libraries(${COMPONENT_LIB} PUBLIC lwjson)
@@ -0,0 +1,107 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/*
* This example demonstrates importing an external C library (lwjson)
* via FetchContent, built by its own CMake, and linked directly to this IDF component
* without any IDF component wrapper.
*/
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "lwjson/lwjson.h"
static const char *TAG = "import_lib_direct";
#define LWJSON_TOKENS 64
/* Sample JSON string to parse */
static const char *sample_json =
"{"
" \"name\": \"ESP32\","
" \"cores\": 2,"
" \"features\": [\"WiFi\", \"Bluetooth\", \"GPIO\"],"
" \"specs\": {"
" \"flash\": \"4MB\","
" \"ram\": \"520KB\""
" }"
"}";
void app_main(void)
{
ESP_LOGI(TAG, "lwjson library imported directly (downloaded, built, linked) without IDF component wrapper");
static lwjson_token_t tokens[LWJSON_TOKENS];
lwjson_t lwobj;
if (lwjson_init(&lwobj, tokens, LWJSON_TOKENS) != lwjsonOK) {
ESP_LOGE(TAG, "lwjson_init failed");
return;
}
if (lwjson_parse(&lwobj, sample_json) != lwjsonOK) {
ESP_LOGE(TAG, "lwjson_parse failed");
lwjson_free(&lwobj);
return;
}
ESP_LOGI(TAG, "Parsing JSON string...");
const lwjson_token_t *name_t = lwjson_find(&lwobj, "name");
if (name_t != NULL) {
size_t len;
const char *s = lwjson_get_val_string(name_t, &len);
if (s != NULL) {
ESP_LOGI(TAG, "Device name: %.*s", (int)len, s);
}
}
const lwjson_token_t *cores_t = lwjson_find(&lwobj, "cores");
if (cores_t != NULL && cores_t->type == LWJSON_TYPE_NUM_INT) {
ESP_LOGI(TAG, "Number of cores: %lld", (long long)lwjson_get_val_int(cores_t));
}
const lwjson_token_t *features_t = lwjson_find(&lwobj, "features");
if (features_t != NULL && features_t->type == LWJSON_TYPE_ARRAY) {
ESP_LOGI(TAG, "Features:");
const lwjson_token_t *child = lwjson_get_first_child(features_t);
while (child != NULL) {
if (child->type == LWJSON_TYPE_STRING) {
size_t len;
const char *s = lwjson_get_val_string(child, &len);
if (s != NULL) {
ESP_LOGI(TAG, " - %.*s", (int)len, s);
}
}
child = child->next;
}
}
const lwjson_token_t *flash_t = lwjson_find(&lwobj, "specs.flash");
const lwjson_token_t *ram_t = lwjson_find(&lwobj, "specs.ram");
if (flash_t != NULL || ram_t != NULL) {
ESP_LOGI(TAG, "Specifications:");
if (flash_t != NULL) {
size_t len;
const char *s = lwjson_get_val_string(flash_t, &len);
if (s != NULL) {
ESP_LOGI(TAG, " Flash: %.*s", (int)len, s);
}
}
if (ram_t != NULL) {
size_t len;
const char *s = lwjson_get_val_string(ram_t, &len);
if (s != NULL) {
ESP_LOGI(TAG, " RAM: %.*s", (int)len, s);
}
}
}
lwjson_free(&lwobj);
ESP_LOGI(TAG, "Example complete!");
}