Setting variables in code using build_flags

Hey folks,

I’m using platformio.org to build a new project and I want to insert my WiFi SSID/Password via build flags.

My customised init function looks like this:

DeviceSetup(DEVICE_NAME, WIFI_SSID,WIFI_PASSWORD,MQTT_SERVER,MQTT_PORT)

And my build flags are as follows:

-DDEVICE_NAME=“MyDevice”
-DWIFI_PASSWORD=“MyWiFiPassword”
-DWIFI_SSID=“MyWiFiNetwork”
-DMQTT_SERVER=“192.168.1.8
-DMQTT_PORT=1883

When I compile the code, I get two errors:

MyDevice was not declared in this scope

and that there are too many decimal points in the MQTT_SERVER variable

This is the first time I’ve used Build Flags to customise my code, what am I missing here?

You could just write a small application/sketch to Serial.println() each of your variables when uploaded and running, but if you can’t or don’t want to, then just compiling the following source code will display your variable values at compile time.

#define ST(A) #A
#define STR(A) ST(A)

#ifdef DEVICE_NAME
#pragma message STR(DEVICE_NAME)
#endif

#ifdef WIFI_PASSWORD
#pragma message STR(WIFI_PASSWORD)
#endif

#ifdef WIFI_SSID
#pragma message STR(WIFI_SSID)
#endif

#ifdef MQTT_SERVER
#pragma message STR(MQTT_SERVER)
#endif

#ifdef MQTT_PORT
#pragma message STR(MQTT_PORT)
#endif

int main() {
	return 0;
}

This is my platformio.ini file for the above test:

[env:uno]
platform = atmelavr
board = uno

; Commented out as I don't want to compile the whole
; Arduino core just to get the variables listed!
;framework = arduino

build_flags =
    -DDEVICE_NAME="MyDevice"
    -DWIFI_PASSWORD="ThisIsReallyABadIdea!"
    -DWIFI_SSID="MyWifiNetwork"
    -DMQTT_SERVER="192.168.1.8"
    -DMQTT_PORT=1883

You do have the various defines indented by 4 spaces or one TAB character, don’t you? You should, if not.

This is the output from pio run:

Compiling .pio/build/uno/src/main.o
src/main.cpp:5:32: note: #pragma message: MyDevice
 #pragma message STR(DEVICE_NAME)
                                ^
src/main.cpp:1:16: note: in definition of macro 'ST'
 #define ST(A) #A
                ^
src/main.cpp:5:17: note: in expansion of macro 'STR'
 #pragma message STR(DEVICE_NAME)
                 ^
src/main.cpp:9:34: note: #pragma message: ThisIsReallyABadIdea!
 #pragma message STR(WIFI_PASSWORD)
                                  ^
src/main.cpp:1:16: note: in definition of macro 'ST'
 #define ST(A) #A
                ^
src/main.cpp:9:17: note: in expansion of macro 'STR'
 #pragma message STR(WIFI_PASSWORD)
                 ^
src/main.cpp:13:30: note: #pragma message: MyWifiNetwork
 #pragma message STR(WIFI_SSID)
                              ^
src/main.cpp:1:16: note: in definition of macro 'ST'
 #define ST(A) #A
                ^
src/main.cpp:13:17: note: in expansion of macro 'STR'
 #pragma message STR(WIFI_SSID)
                 ^
src/main.cpp:17:32: note: #pragma message: 192.168.1.8
 #pragma message STR(MQTT_SERVER)
                                ^
src/main.cpp:1:16: note: in definition of macro 'ST'
 #define ST(A) #A
                ^
src/main.cpp:17:17: note: in expansion of macro 'STR'
 #pragma message STR(MQTT_SERVER)
                 ^
src/main.cpp:21:30: note: #pragma message: 1883
 #pragma message STR(MQTT_PORT)
                              ^
src/main.cpp:1:16: note: in definition of macro 'ST'
 #define ST(A) #A
                ^
src/main.cpp:21:17: note: in expansion of macro 'STR'
 #pragma message STR(MQTT_PORT)
                 ^

And with the cruft removed:

src/main.cpp:5:32: note: #pragma message: MyDevice
 #pragma message STR(DEVICE_NAME)

src/main.cpp:9:34: note: #pragma message: ThisIsReallyABadIdea!
 #pragma message STR(WIFI_PASSWORD)

src/main.cpp:13:30: note: #pragma message: MyWifiNetwork
 #pragma message STR(WIFI_SSID)

src/main.cpp:17:32: note: #pragma message: 192.168.1.8
 #pragma message STR(MQTT_SERVER)

src/main.cpp:21:30: note: #pragma message: 1883
 #pragma message STR(MQTT_PORT)

So, in my test, it’s working fine.

It might be helpful to post your full platformio.ini file and your code. Please wrap the code in three of these ` (backtick) characters, as follows:

```
Your code goes here...
```

That way, we can see indentation and so on, which makes reading code far easier.

Cheers,
Norm.

Thanks.

As I say, I’m new to this, what do the #define STR(A) lines mean?

I see them in other posts here, and they seem to be important, but I can’t find anything saying what they do and why they’re needed!

I don’t have these lines in my code, so I’m guessing this is part of the issue!

This is correct. By writing -DDEVICE_NAME="MyDevice" your C/C++ code sees this as the value MyDevice and not "MyDevice" (string), so you need to stringify it yourself there or escape the quotes in the build flags properly as seen in the docs.

They are just there to “stringify” the variables passed. Your problem is most likely a coding one (sorry!) however:

#define ST(A) #A

This code “stringifies” it’s one parameter. Whatever is passed as A will effectively be replaced by "A" - basically A with double quotes, making it a string. However, this doesn’t expand macros. So if A happened to be a macro parameter, it would not be expanded into whatever was defined.

In other words, passing your DEVICE_NAME macro, would result in nothing more than just “DEVICE_NAME” but not what DEVICE_NAME was defined to be.

#define STR(A) ST(A)

This macro takes a macro, expands it, and then passes it to the ST macro to be stringified.

So for:

-DDEVICE_NAME "MyDevice"

NOTE Quotes are removed when it gets to the C++ pre-processor.

ST(DEVICE_NAME) results in “DEVICE_NAME”.
STR(DEVICE_NAME) results in a call to ST(MyDevice) which results in “MyDevice”, which the `#pragma message" command can then display on the output channel.

The GNU docs at Stringification - The C Preprocessor state that:

If you want to stringify the result of expansion of a macro argument, you have to use two levels of macros.

#define xstr(s) str(s) #define str(s) #s #define foo 4 str (foo) ==> “foo” xstr (foo) ==> xstr (4) ==> str (4) ==> “4”

s is stringified when it is used in str , so it is not macro-expanded first. But s is an ordinary argument to xstr , so it is completely macro-expanded before xstr itself is expanded (see Argument Prescan). Therefore, by the time str gets to its argument, it has already been macro-expanded.

The fact that these two short macros are missing from your code is not the cause of your problems.

HTH

Cheers,
Norm.

Fantastic, thank you.

I’ll have another crack at this later on and let you know what happens!

Thanks folks, this worked a treat and the code now compiles without issue.

I’ll flash it to a device shortly.

Yup, uploaded it to a device, it works perfectly, thanks! :slight_smile:

It was the missing #define STR(A) ST(A) bits that I needed!