esp-idf: CMake FetchContent fails when called before idf_component_register (IDFGH-8469)

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

IDF version.

ESP-IDF v5.1-dev-992-gaf28c1fa21

Operating System used.

Linux

How did you build your project?

Command line with idf.py

If you are using Windows, please specify command line type.

No response

What is the expected behavior?

For some reason using the CMake FetchContent module before registering a component fails spectacularly.

include(FetchContent)  
FetchContent_Declare(...)

file(GLOB_RECURSE SOURCES *.c *.cpp)
idf_component_register(SRCS  ${SOURCES} ...)

What is the actual behavior?

CMake errors out. See “Build or installation Logs.” for further details.

Steps to reproduce.

1.) Create new project from hello_world example 2.) Copy/paste any FetchContent_Declare call before idf_component_register, e.g:

      include(FetchContent)
      FetchContent_Declare(
        fmt
        GIT_REPOSITORY https://github.com/fmtlib/fmt.git
        GIT_TAG 9.1.0
        GIT_PROGRESS TRUE)
      FetchContent_MakeAvailable(fmt)

Build or installation Logs.

CMake Error at /home/vinci/esp/esp-idf/tools/cmake/component.cmake:224 (message):
  CMake Warning (dev) at build_properties.temp.cmake:8:

    Syntax Warning in cmake code at column 47

  

    Argument not separated from preceding token by whitespace.

  Call Stack (most recent call first):

    /home/vinci/esp/esp-idf/tools/cmake/scripts/component_get_requirements.cmake:3 (include)

  This warning is for project developers.  Use -Wno-dev to suppress it.

  

  fatal: not a git repository (or any parent up to mount point /)

  Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).

  CMake Error at /usr/share/cmake/Modules/FetchContent.cmake:1149
  (define_property):

    define_property command is not scriptable

  Call Stack (most recent call first):

    /usr/share/cmake/Modules/FetchContent.cmake:1300:EVAL:1 (__FetchContent_declareDetails)
    /usr/share/cmake/Modules/FetchContent.cmake:1300 (cmake_language)
    /home/vinci/Develop/VSCode/hello_world/main/CMakeLists.txt:2 (FetchContent_Declare)
    /home/vinci/esp/esp-idf/tools/cmake/scripts/component_get_requirements.cmake:106 (include)
    /home/vinci/esp/esp-idf/tools/cmake/scripts/component_get_requirements.cmake:124 (__component_get_requirements)

More Information.

No response

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Comments: 17 (16 by maintainers)

Most upvoted comments

Thank you for the detailed explanation. Unfortunately, this only confirms my assumption that ESP-IDF is generally working against CMake and not with it. The reason people use CMake in the first place is because everybody else does so. “CMake has a beautiful syntax and is a pleasure to work with” is a sentence nobody ever has nor ever will say… By introducing the concept of components ESP-IDF basically takes the one and only thing away from CMake it excels at. Maybe I’m missing something, but currently I really can’t see the point of it all?

/edit Is there any way to add e.g. mdns as component without using either the component manager nor manually downloading it?

@higaski I understand your sentiment, and I agree that it would be better if ESP-IDF started off with a more idiomatic CMake build system. I think this has been discussed extensively back in the day when IDF CMake-based build system was introduced in https://www.esp32.com/viewtopic.php?f=13&t=5559 and in follow-up topics on the forum.

The main reason for having 2-stage processing is to support Kconfig based project configuration. To allow component CMakeLists files to use Kconfig options, configuration processing step has to occur before the component libraries are added to the project using add_subdirectory(). In order to generate the configuration, we need to know the list of components which will participate in the build and contribute their Kconfig files. Since we don’t want to place the burden on the user to list all the used components in the project CMakeLists.txt file, we need to figure out the list of components by expanding their requirements.

I’m sure you know this, but for others who might stumble on this ticket I’ll note that it is still possible to write a library which works with normal CMake and IDF (and Zephyr) at the same time. LVGL is one such example: https://github.com/lvgl/lvgl/blob/master/CMakeLists.txt

Hi @higaski, The issue likely happens because component CMakeLists files are evaluated twice during the build process. First, they are evaluated early during the build in CMake script mode to extract component requirements (REQUIRES and PRIV_REQUIRES arguments of idf_component_register). Evaluation stops after encountering the call to idf_component_register() or a return(). Once the list of components has been determined component CMakeLists files are evaluated again, this time using the normal add_subdirectory call. I think you need to make sure the additional logic in your component CMakeLists file doesn’t run during the first evaluation. You can do this either by moving FetchContent after idf_component_register or by wrapping the additional logic into if(NOT CMAKE_BUILD_EARLY_EXPANSION) ... endif().

By the way, there is an example of adding an external library which could be helpful: https://github.com/espressif/esp-idf/blob/master/examples/build_system/cmake/import_lib/components/tinyxml2/CMakeLists.txt