CMake - Nested component

GreenGiant
Posts: 28
Joined: Tue Sep 10, 2019 7:22 am

CMake - Nested component

Postby GreenGiant » Fri Jan 24, 2020 11:32 am

How do I nest a component within a component, is it possible?

For example:

Code: Select all

- myProject/
             - CMakeLists.txt
             - sdkconfig
             - components/ - component1/ - CMakeLists.txt
                                         - src1.c
                                         - component1a/ - CMakeLists.txt
                                                        - src1.c
                           - component2/ - CMakeLists.txt
                                         - src1.c
                                         - include/ - component2.h
             - main/       - src1.c
                           - src2.c

             - build/
Where main, src1.c, requires component1a.

I was hoping I could do set(EXTRA_COMPONENT_DIRS component1a) in the CMakeLists.txt of component1, and then in the CMakeLists.txt for main REQUIRES component1a but I get the error Failed to resolve component 'component1a'.

I am trying to avoid having to do set(EXTRA_COMPONENT_DIRS component1/component1a) in the main CMakeLists.txt.

Thanks

GreenGiant
Posts: 28
Joined: Tue Sep 10, 2019 7:22 am

Re: CMake - Nested component

Postby GreenGiant » Fri Jan 24, 2020 11:59 am

Forgot to add, ESP-IDF v4.0 release

chegewara
Posts: 2358
Joined: Wed Jun 14, 2017 9:00 pm

Re: CMake - Nested component

Postby chegewara » Sun Jan 26, 2020 9:11 pm

For sure you can use nested components, but it is easier to use PRIV_REQUIRES.
If you still want to use nested components then try to study
https://github.com/espressif/esp-adf
where esp-idf is used as component and all its components can be considered as nested components.

electronsquare_chris
Posts: 3
Joined: Fri Oct 18, 2019 8:18 am

Re: CMake - Nested component

Postby electronsquare_chris » Wed Feb 12, 2020 5:14 pm

I'm facing the same issue in IDF4.1. I have a git submodule which is a component that includes another git submodule which is also a component. It only builds if I copy the subcomponent to the main components folder.

I use

Code: Select all

idf_component_register(SRC_DIRS "src"
                       INCLUDE_DIRS "inc"
                       PRIV_REQUIRES sub_component_name)
to include the sub_component, but I get the error:
CMake Error at /home/user_name/esp/esp-idf/tools/cmake/build.cmake:186 (message):
Failed to resolve component 'component_name'.
If I leave it out it cannot find the header file from the subcomponent.
I tried

Code: Select all

set(EXTRA_COMPONENT_DIRS "absolute_path_to_component")
In all occurences of CMakeLists.txt . But it doesn't work as documented.

A workaround would be to include the subcomponent source files and header files as part of the component. But that beats the entire purpose of working modular.

I also tried adding the file project_include.cmake to my component as decribed below:
https://docs.espressif.com/projects/esp ... he-project

Code: Select all

set(EXTRA_COMPONENT_DIRS COMPONENT_DIR/components)
This also failed.

There has to be an elegant way to let the idf toolchain work with nested components.

electronsquare_chris
Posts: 3
Joined: Fri Oct 18, 2019 8:18 am

Re: CMake - Nested component

Postby electronsquare_chris » Thu Feb 13, 2020 2:07 pm

I've looked into the adf-example, but couldn't find how it allows nesting.
I've created a very basic project to test the nested component:
https://github.com/ChrisIdema/idf_nested_components
I'd be very happy if someone can get automatic building of nested components working.

fAxxxik
Posts: 2
Joined: Wed Jul 05, 2017 7:28 am

Re: CMake - Nested component

Postby fAxxxik » Fri Mar 27, 2020 3:59 pm

Did you manage to resolve? I'm also struggling with that.

Thanks!

GreenGiant
Posts: 28
Joined: Tue Sep 10, 2019 7:22 am

Re: CMake - Nested component

Postby GreenGiant » Wed Apr 01, 2020 8:27 am

Unfortunately not no. I gave up to be honest but I will revisit shortly and take another look at the adf.

If I get it working I'll post here for you & others. Grateful if you could do the same. From the excellent replies above it sure seems possible, I am probably doing something stupid.

GreenGiant
Posts: 28
Joined: Tue Sep 10, 2019 7:22 am

Re: CMake - Nested component

Postby GreenGiant » Wed Jun 24, 2020 10:19 am

So had to revisit this.

The stuff in the ADF doesn't allude to much, perhaps I am not seeing it?

If I use:

Code: Select all

set(EXTRA_COMPONENT_DIRS foo)
Does that overwrite what I previously set in the root of my project, or does it append to it?

Also, the documentation uses

Code: Select all

idf_component_register()
whereas the ADF uses

Code: Select all

register_component()
Documentation: https://docs.espressif.com/projects/esp ... cmakelists
ADF example: https://github.com/espressif/esp-adf/bl ... eLists.txt

What's the difference, is one newer so we should be using that?

ESP_Angus
Posts: 2344
Joined: Sun May 08, 2016 4:11 am

Re: CMake - Nested component

Postby ESP_Angus » Wed Jun 24, 2020 11:48 pm

GreenGiant wrote:
Wed Jun 24, 2020 10:19 am
So had to revisit this.

The stuff in the ADF doesn't allude to much, perhaps I am not seeing it?

If I use:

Code: Select all

set(EXTRA_COMPONENT_DIRS foo)
Does that overwrite what I previously set in the root of my project, or does it append to it?
If you put this line in the component CMakeLists.txt then it will probably be ignored.

I don't think there is a supported way to nest components, one of the first things the build does is to enumerate all the component directories for the project and use this information to build the graph of component dependencies, etc.

I can suggest three ways to solve this problem, from the simplest to the most complex:

1 (Simplest)

I know you said this is what you were trying to avoid, but for the layout shown in the first post then this is still by far the simplest method. Add the following line in the top-level project CMakeLists.txt file:

Code: Select all

set(EXTRA_COMPONENT_DIRS components/ components/component1)
The build system will find the components component1, component1a, component2.

I understand this breaks the principle of encapsulation (to make component1 responsible for everything it contains), but I wanted to mention it in case anyone else reads this post and wonders what the very simplest approach is.

Another equally simple method would be to register all of component1a's sources and directories inside component1's CMakeLists.txt file, but I assume this is also what you're trying to avoid. :)

2

It is possible to use CMake nested directories inside a single component.

Here's an example in esp-idf master branch. We have a component esp_system, and the top-level CMakeLists.txt file includes a subdirectory named port:
https://github.com/espressif/esp-idf/bl ... eLists.txt

The "port" subdirectory has its own CMakeLists.txt file. Note that this is not an ESP-IDF component any more, so it's not possible to use idf_component_register() here. But it is possible to add source files and include directories to the top-level component using CMake commands (the component target name is available in the COMPONENT_LIB variable):
https://github.com/espressif/esp-idf/bl ... eLists.txt

The port/CMakeLists.txt file adds a deeper subdirectory, whose name depends on the target chip. So for esp32 it's this file:
https://github.com/espressif/esp-idf/bl ... eLists.txt

Note that even though there are 3 CMakeLists.txt files here, there is only one ESP-IDF "component" and one CMake library target. But all of the files in the 3 directories are encapsulated in the respective CMakeLists.txt files.

2 (Most Complex)

It's possible to do even more CMake wizardry, for example the ESP-IDF mbedTLS component uses add_subdirectory() to include the mbedTLS upstream CMakeLists.txt file (which has no ESP-IDF specific contents), and then manually adds those mbedTLS CMake library targets to the mbedTLS component:
https://github.com/espressif/esp-idf/bl ... ts.txt#L59

(This option requires some deep CMake spelunking so I'd recommend skipping it unless you're really sure it's what you need.)

...

Are any of those methods useful for you, or is it important that component1 and component1a are independent IDF components in the build system? If you can explain a bit more about your exact use case then we might be able to suggest another way to support it.
GreenGiant wrote:
Wed Jun 24, 2020 10:19 am
Also, the documentation uses

Code: Select all

idf_component_register()
whereas the ADF uses

Code: Select all

register_component()
[...]
What's the difference, is one newer so we should be using that?
ESP-ADF is still based on ESP-IDF V3.3 and the "register_component()" function with the various variables was used in the CMake support released in V3.x.

In ESP-IDF V4.0 we introduced idf_component_register() which is more "CMake like" and also more powerful. The "register_component()" syntax is still supported for backwards compatibility, but if your project only targets ESP-IDF V4.0 and newer then I would recommend using idf_component_register().

Who is online

Users browsing this forum: Bing [Bot] and 66 guests