Я пытаюсь заставить систему сборки esp-idf сделать такую тривиальную вещь, как добавление внешней библиотеки в приложение. Это совершенно просто в простом CMake, но по какой-то причине это не работает в неудобной экосистеме esp-idf.
Структура проекта выглядит следующим образом:
.
├── app
│ ├── CMakeLists.txt
│ ├── components
│ │ ├── DummyLib
│ │ │ ├── CMakeLists.txt
│ │ │ ├── test.cpp
│ │ │ └── test.h
│ │ └── DummyLibComponent
│ │ └── CMakeLists.txt
│ └── main
│ ├── CMakeLists.txt
│ └── mm01.c
└── esp-idf
6 directories, 7 files
приложение/CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
set(EXTRA_COMPONENT_DIRS "components")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(app)
приложение/основной/CMakeLists.txt:
idf_component_register(SRCS "mm01.c"
INCLUDE_DIRS "."
REQUIRES
DummyLibComponent
)
приложение/основной/приложение.с:
#include <stdio.h>
#include "test.h"
void app_main(void)
{
int ret = test_component();
}
приложение/компоненты/DummyLib/CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
project(DummyLib)
add_library(${PROJECT_NAME} STATIC
test.cpp
)
target_include_directories(${PROJECT_NAME} PUBLIC
.
)
приложение/компоненты/DummyLib/test.cpp:
#include "test.h"
int test_component()
{
return 2+3;
}
приложение/компоненты/DummyLib/test.h:
int test_component();
приложение/компоненты/DummyLibComponent/CMakeLists.txt:
idf_component_register(
INCLUDE_DIRS ../DummyLib # Not sure where should it point? To the include referenced by the lib or by relative path? REQUIRES DummyLib
)
add_subdirectory(../DummyLib DummyLib)
target_link_libraries(${COMPONENT_LIB} INTERFACE DummyLib)
Дерево каталогов:
esp-idf <- здесь находится репозиторий esp-idf, которого здесь нет
app <- вот приложение, созданное с помощью команды create-project. Он строится нормально, когда не определены дополнительные компоненты.
app/components <- этот каталог настроен в «EXTRA_COMPONENT_DIRS»
app/components/DummyLib <- любая статическая библиотека, которая нормально работает в простом CMake
app/components/DummyLibComponent <- компонент, обертывающий DummyLib, чтобы я мог работать с экосистемой esp-idf.
Для этой настройки, когда я пытаюсь создать приложение с помощью idf.py build
, оно завершается с ошибкой:
idf.py build
Executing action: all (aliases: build)
Running ninja in directory <PATH_TO_PROJECT>/app/build
Executing "ninja all"...
[0/1] Re-running CMake...-- Building ESP-IDF components for target esp32s3
CMake Error at <PATH_TO_PROJECT>/esp-idf/tools/cmake/component.cmake:224 (message):
CMake Warning (dev) at build_properties.temp.cmake:8:
Syntax Warning in cmake code at column 51
Argument not separated from preceding token by whitespace.
Call Stack (most recent call first):
<PATH_TO_PROJECT>/esp-idf/tools/cmake/scripts/component_get_requirements.cmake:3 (include)
This warning is for project developers. Use -Wno-dev to suppress it.
CMake Error at
<PATH_TO_PROJECT>/app/components/DummyLib/CMakeLists.txt:2
(project):
project command is not scriptable
Call Stack (most recent call first):
<PATH_TO_PROJECT>/esp-idf/tools/cmake/scripts/component_get_requirements.cmake:106 (include)
<PATH_TO_PROJECT>/esp-idf/tools/cmake/scripts/component_get_requirements.cmake:124 (__component_get_requirements)
Что не так с этой настройкой? Что означает «команда проекта не поддерживает сценарий»? Как правильно добавить ВНЕШНЮЮ библиотеку без ее изменения?
@Tsyvarev ваше предложение решает проблему. На данный момент Ив получил DummyLib
вне каталога component
. Он компилируется, но не будет ссылаться из-за неопределенной ссылки на test_component()
. Библиотека построена. Объект содержит функцию. Библиотека отсутствует в командной строке компоновщика. Не уверен, почему. Попытался создать базовый компонент без внешней зависимости, как описано в документах, но не удалось по той же причине.
если у вас возникла новая проблема, напишите новый вопрос с минимально воспроизводимым примером этой проблемы
target_link_libraries(${COMPONENT_LIB} INTERFACE DummyLib)
— связывает с DummyLib всех пользователей компонента, но не сам компонент. Вместо этого используйте связь PUBLIC или PRIVATE.
undefined reference
появился, потому что библиотека CPP, а основное приложение, в котором была вызвана функция, — простой C. facepalm
Ошибка
команда проекта не поддерживает сценарий
означает, что данная команда (project
в вашем случае) входит в список команд проекта , которые не следует использовать в режиме сценариев CMake (cmake -P </path/to/script>
). Пока вы пишете CMakeLists.txt
, который обычно обрабатывается в режиме проекта (cmake </path/to/source/dir>
), ESP-IDF фактически имеет два прохода:
CMakeLists.txt
обрабатывается в режиме сценария, пока не вызовет определенную функцию. Этот проход необходим для сбора информации о компонентах.CMakeLists.txt
каждого компонента в режиме проекта.То есть, пока компонент не вызовет специфическую функцию ESP-IDF, он не должен использовать команды только для проекта.
Обычная функция, которая завершает режим сценариев при обработке ESP-IDF, — это CMakeLists.txt
. Но есть и другие «завершающие» функции.
Ваша библиотека idf_component_register
находится в каталоге компонента, поэтому ESP-IDF пытается прочитать ее app/components/DummyLib
в режиме скрипта. Вот почему вы получаете ошибку.
Вы можете переместить файлы библиотеки в другой каталог. Например, в CMakeLists.txt
. В этом случае вы можете настроить app/components/DummyLibComponent/src/
для использования нового местоположения библиотеки:
idf_component_register(
INCLUDE_DIRS ../DummyLib # Not sure where should it point? To the include referenced by the lib or by relative path?
)
add_subdirectory(src)
target_link_libraries(${COMPONENT_LIB} PUBLIC DummyLib)
Кроме того, вы можете создать чистый компонент CMake. Его режим сценария завершается вызовом app/components/DummyLibComponent/CMakeLists.txt
. Поэтому убедитесь, что перед этим вызовом у вас нет команды проекта:
# app/components/DummyLib/CMakeLists.txt
#
add_library(${PROJECT_NAME} STATIC
test.cpp
)
target_include_directories(${PROJECT_NAME} PUBLIC
.
)
В этом случае add_library
не нужен.
ESP-IDF рассматривает каждый подкаталог
components/
как компонент, таким образом ожидая найти вызовidf_component_register
в ихCMakeLists.txt
. Но вашcomponents/DummyLib/CMakeLists.txt
не содержит этого вызова. Если вы хотите создать некомпонентныйCMakeLists.txt
, то не помещайте его в подкаталогcomponents/
. Вы можете создать свою библиотеку, например. подapp/components/DummyLibComponent/src/
, поэтому скриптapp/components/DummyLibComponent/CMakeLists.txt
может включить его черезadd_subdirectory(src)
.