Scott Eklund
Scott Eklund

Reputation: 43

How to build multiple configurations of an ESP-IDF application

I have one ESP-IDF application and two hardware boards. I use a preprocessor definition to control which hardware board version to build. For now, I'm modifying the config in the sdkconfig file via menuconfig. But I would like to build both versions at once from a script, or build only one specific config without the manual process of menuconfig.

I have a header that looks like this, and works when HW_VER is set correctly:

#if HW_VER == 2
#define BTN_GPIO 9
#elif HW_VER == 3
#define BTN_GPIO 10
#endif

And from the a script I would like to build each by selecting a value for HW_VER, for example:

idf.py build -DHW_VER=2
idf.py build -DHW_VER=3

The idf.py build command runs cmake and ninja. I'm new to cmake, so perhaps there is a natural way to do this?

I would also like to build release and debug builds, turn on/off memory debugging etc. from the command line.

I've tried idf.py build -DHW_VER=2 but I've learned that these vars are only sent to cmake and not to the preprocessor. The HW_VER macro remains undefined.

Using add_definitions() in my CMakeLists.txt can set HW_VER, but doesn't help me make different builds from the same files.

Using a config variable like CONFIG_HW_VER in the sdkconfig works to control builds using menuconfig but I don't see a way to automate this.

I've considered modifying the configuration variable, CONFIG_HW_VER in the sdkconfig file programmatically, but this file is under source control, and it is auto generated by menuconfig, so that doesn't seem wise.

Similarly I can modify the CMakeLists.txt file programmatically, but that file is also under source control, and isn't a trivial format.

Upvotes: 4

Views: 2736

Answers (1)

Tarmo
Tarmo

Reputation: 4780

I use two ways to feed custom configurations into an ESP IDF project.

Firstly, the light weight stuff like preprocessor definitions from the environment are quite simple. You have to configure CMakeLists.txt file (the one in project root) to pass variable values from environment into the build process. For example, to create something equivalent to preprocessor definitions -DMY_NUMBER=123 and -DMY_STRING="abc" add this somewhere before the "project" line:

add_compile_definitions(MY_NUMBER=$ENV{MY_NUMBER})
add_compile_definitions(MY_STRING=\"$ENV{MY_STRING}\")
...
project(myproject)

Assuming you're working in Bash, build with:

$ MY_NUMBER=123 MY_STRING="abc" idf.py build 

or (for a slightly more "sticky" enviroment):

$ export MY_NUMBER=123 MY_STRING="abc"
$ idf.py build

You can use cmake to add more advanced logic, e.g. setting default values in case the environment doesn't set anything.

Secondly, the more powerful configuration tool for ESP IDF is the menuconfig target and sdkconfig file. As you've already noticed, playing with sdkconfig directly is not so easy. In my projects I consider this a generated temporary file and I never commit it to git. Instead I delete it. When sdkconfig is missing, idf.py will take file sdkconfig.defaults, copy it into sdkconfig and work with this. That is your best mechanism for supporting different hardware configurations - no sdkconfig and instead different variants of sdkconfig.defaults for each hardware you wish to support.

As an example, assume you have two different HW versions described in sdkconfig.defaults.hw_ver1 and sdkconfig.defaults.hw_ver2 and you wish to build for HW ver2 configuration:

$ rm sdkconfig && cp sdkconfig.defaults.hw_ver2 sdkconfig.defaults
$ idf.py reconfigure

Now you can build for this configuration like you usually would:

$ idf.py build

When you wish to build for the other FW configuration, re-execute the previous commands with sdkconfig.defaults.hw_ver1

All this is rather thoroughly documented in the Build System documentation, so feel free to dig in.

Upvotes: 3

Related Questions