PlatformIO Community

Can the C pre-processor handle conditionals?

I’ve added a dynamic build flag using the $PIOENV in my platformio.ini file in the hopes of adding some cross-platform portability with my pin_definitions, as seen below:

in platformio.ini:

[env:node]
platform = espressif32
board = lolin_d32_pro
framework = arduino
...
src_filter = +<node>
upload_port = /dev/cu.wchusbserial*
monitor_port = /dev/cu.wchusbserial*
upload_protocol = esptool
build_flags =
-D BUILD_ENV_NAME=$PIOENV

[env:root]
platform = espressif8266@2.2.1
board = d1_mini
framework = arduino
src_filter = +<root>
upload_port = /dev/cu.wchusbserial*
monitor_port = /dev/cu.wchusbserial*
upload_protocol = esptool
build_flags =
-D BUILD_ENV_NAME=$PIOENV

in pin_definitions.h:

#if BUILD_ENV_NAME == root
  #ifdef ESP32
    #define RX_PIN -1
    #define TX_PIN -1
    ....
  #elif ESP8266
    #define RX_PIN D4
    #define TX_PIN D3
    ...
  #endif
#elif BUILD_ENV_NAME == node
  #ifdef ESP32
    #define RX_PIN 1
    #define TX_PIN 2
    ...
  #elif ESP8266
    #define RX_PIN D4
    #define TX_PIN D3
    ...
  #endif
#endif

But the preprocessor conditionals doesn’t seem to work. I’ve tried defining new symbols and equating to those and those didn’t work as well, nor did comparing against chars / strings – can someone tell me what data type is the symbol exactly comparing against? Because somehow BUILD_ENV_NAME == node (is this a string literal?) compiles.

I’ve worked around by defining each environment explicitly with IS_ROOT and IS_NODE, but would love to know how I can work with $PIO_ENV. Thanks in advance!

I don’t think you’ll have any luck doing it that way, as this Stack Overflow thread suggests that the ISO-C11 preprocessor does not support string comparison… or more specifically… support for a string comparision is hit and miss, and can vary from compiler to compiler. If you instead allocate a single character, or a number to each environment, that will work.

2 Likes

This. Just do the conditionals with comparisons to numbers and you’re good.

#define BUILD_TYPE_NODE 1 
#define BUILD_TYPE_ROOT 2

#ifndef BUILD_TYPE
#error "Must define BUILD_TYPE..."
#endif

#if BUILD_TYPE == BUILD_TYPE_NODE 
...
#endif

and then just

build_flags = -D BUILD_TYPE=1

in the specific environment in the platformio.ini (you can have multiple, so e.g. a root and node environment)

2 Likes

Ok, so the gotcha is that I have to name my environments to single characters. A little weird, and would definitely classify as a magic number. I see the elegance of @maxgerhardt 's answer untangling some of the aforementioned semantic problems and a guard to catch undefined build flags. It’s close to what I’m doing now by polluting the macro space with IS_FOO but better. I definitely don’t fancy my environments called 1, 2 and so on — very unidiomatic and a step backwards. I’ll definitely reconsider the use of dynamic build flags and just define them manually. Thanks again for clearing this up!

I appreciate both your answers and wish I can submit both as solutions

1 Like

I prefer Max’s answer, as he showed the code example of what I was thinking. Thanks for trying though! :wink: