killdaclick
killdaclick

Reputation: 731

ESP-IDF add external library / component: "project command is not scriptable"

I'm trying to force the esp-idf build system to make such trivial thing as adding external library to the application. It is completely straightforward in plain CMake but for some reason it is not working in esp-idf awkward ecosystem.

The project structure is like below:

.
├── 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

app/CMakeLists.txt:


cmake_minimum_required(VERSION 3.16)

set(EXTRA_COMPONENT_DIRS "components")

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(app)

app/main/CMakeLists.txt:



idf_component_register(SRCS "mm01.c"
    INCLUDE_DIRS "."
    REQUIRES
        DummyLibComponent
)

app/main/app.c:



#include <stdio.h>
#include "test.h"

void app_main(void)
{
    int ret = test_component();
}

app/components/DummyLib/CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)                                                                                                          
project(DummyLib)
add_library(${PROJECT_NAME} STATIC
    test.cpp
)
target_include_directories(${PROJECT_NAME} PUBLIC
    .
)

app/components/DummyLib/test.cpp:

#include "test.h"

int test_component()
{
    return 2+3;
}

app/components/DummyLib/test.h:

int test_component();

app/components/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)

Directory tree:

esp-idf <- here goes the esp-idf repo which is not included here

app <- here is the application created using the 'create-project' command. It builds normally when no additional components are defined.

app/components <- this directory is setup in 'EXTRA_COMPONENT_DIRS'

app/components/DummyLib <- any static library that works normally in plain CMake

app/components/DummyLibComponent <- a component that wraps the DummyLib to make i work with the esp-idf ecosystem

For this setup when I try to build the app using idf.py build it fails with that errors:

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)


What is wrong with this setup? What does 'poject command is not scriptable' mean? What is the proper way to add EXTERNAL library without modifying it?

Upvotes: 1

Views: 2484

Answers (1)

Tsyvarev
Tsyvarev

Reputation: 65860

The error

project command is not scriptable

means that given command (project in your case) is from the list of project commands, which shouldn't be used in the scripting mode of CMake (cmake -P </path/to/script>). While you write the CMakeLists.txt which is normally processed in project mode (cmake </path/to/source/dir>), ESP-IDF actually has two passes:

  1. Firstly ESP-IDF iterates over all components directories, every component's CMakeLists.txt is processed in the scripting mode, until it calls a specific function. This pass is needed for collect information about components.
  2. Then ESP-IDF processes every components' CMakeLists.txt in project mode.

That is, until a component' CMakeLists.txt calls a ESP-IDF specific function, it shouldn't use project-only commands.

The usual function which terminates scripting mode in ESP-IDF processing is idf_component_register. But there are other "terminating" functions.

Your library app/components/DummyLib is located in the component's directory, so ESP-IDF tries read its CMakeLists.txt in a scripting mode. This is why you get the error.

You could move the library files into some other directory. E.g., into app/components/DummyLibComponent/src/. In that case you may adjust app/components/DummyLibComponent/CMakeLists.txt to use new location of the library:

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)

Alternatively, you may create pure CMake component. Its scripting mode is terminated by add_library call. So make sure you have no project command before that call:

# app/components/DummyLib/CMakeLists.txt
# 
add_library(${PROJECT_NAME} STATIC
    test.cpp
)
target_include_directories(${PROJECT_NAME} PUBLIC
    .
)

In that case app/components/DummyLibComponent/CMakeLists.txt is not needed.

Upvotes: 3

Related Questions