#defines across source files

I have experienced several times that when I define a value in one file, it is not defined in another file anymore.

main.cpp

#define MAX_BUFFER_SIZE 1000

include <header1.h>
include <header2.h>

in header1.h

#ifndef MAX_BUFFER_SIZE 
  #error "MAX_BUFFER_SIZE not defined"
#endif

And then pio will stop due to this error.
Anyone has experienced this also? And how to solve it?
Using PIO Core 4.0.3 with Visual studio code

In your .cpp file: Is #define ... before all includes? My guess is that you have additional includes, which in turn include header1.h early before MAX_BUFFER_SIZE is defined.

Please show complete code. include <header1.h> won’t compile. It’s supposed to be #include <header1.h>. And add the full error message as well as it shows in detail from which lines and files the header file was included.

1 Like

Hi thanks for your answer.
You’re right about the #include, the code was just to illustrate what I meant.

Yes, the #define is before all includes. Because I added the #error myself, this is the error where the compiler stops on. If I leave the #error out it compiles but with the later definition.

The point is, the #define is before the #include. How is it possible that in the #include, the #define is not defined anymore?

I will try to put together a full example to share.

It’s not possible. More likely there is a bug in your setup somewhere. Provide a complete, reproducible example and we can help you.

All right. What is needed exactly from my setup?

Create a small projects that works and provide:

  • platformio.ini
  • All .h, .c and .cpp files in include and src (and lib if you are using it)
  • Version of PlatformIO, VisualStudio Code and operation system

It should be sufficient information such that we can setup the same project and reproduce the problem.

All right, thank you in advance.
Here it is.

Edit
Please use the defines build

A reference to a GitHub project is good thing. Before I test it, I have a few questions:

  • I can’t see no define of MAX_BUFFER_SIZE. Is NON_BLOCKING_RECONNECT the relevant define instead?
  • Is it on purpose that NON_BLOCKING_RECONNECT is defined both in main.h and main.cpp?
  • Which file tests the defined macro?

No it is MQTT_MAX_PACKET_SIZE in main.h

It is tested in pubsubclient.h.

So without testing the code:

  • If main.cpp is compiled, the definition of MQTT_MAX_PACKET_SIZE in main.h will be effective in PubSubClient.h.
  • However, PubSubClient.h is included by other files as well, e.g. PubSubClient.cpp. So if PubSubClient.cpp is compiled, main.h is not part of the compilation and the definition is not effective.
  • I haven’t seen the error message, but I guess you’ll find that it’s a message from compiling PubSubClient.cpp and is not related to main.cpp.

To proceed:

  • Remove the definition from main.cpp.
  • Instead add the following lines to platformio.ini:
build_flags =
    -D MQTT_MAX_PACKET_SIZE=256
3 Likes

You’re right! This does the trick.

Is there a way to do this without using the build flags?
I always thought that what I defined would be global to all files that are compiled after the define.

In C/C++, each .c and .cpp file is compiled separately from all other .c and .cpp. Header files are shared but only if they are directly or indirectly included in all relevant .c and .cpp files.

In your case, you are dealing with a library that you don’t want to modify. So you cannot include an additional header file. So build flags are the right way to go.

The situation is different if the library has a built-in configuration system that is designed to include a modifiable header file. The ESP-IDF framework has such an approach that extends to all libraries built for the framework. It even comes with a simple graphical tool for configuring the possible values. It has its share of disadvantages however.

In my experience, build flags are simple, straightforward and well integrated into PlatformIO. As long as their number is moderate, it’s my preferred solution.

Ok clear. Thanks for your help. I thought I knew C programming after doing it for 20 years but today I have learned a basic concept again.

One more question came up. What happens if in this example the build flag would not be used, and the define is set twice with different values. Which of the two would be used finally?

In the main.cpp code, the value from main.h would be used. In PubSubClient.cpp, the default value from PubSubClient.h would be used.

If the values are different, you could end up with a nasty bug, e.g. one module creating a message of 256 bytes and the other module copying the message into a buffer of 128 bytes, thereby overwriting other variables…

1 Like

Please, could you explain the statement? I’m facing the same problem than the op but I have no scape/workaround as define an env var. That “indirect inclusion” doesn’t work for me.
In my case, it’s a rather large library (I’m trying to convert a big project that only uses ino files) and it’s not feasible to go full include in multiple files.

I see that you’re more experienced than me. Can you please take a look into an already made library that I’m used to?
The part that I’n interested into is the macros relative to serial output.
In MyConfig.h@163 there’s a macro for serial speed.
This header is included in the main library file (entry point)@43 that it has to be included in your sketch file.
This macro is later consumed in a source file at hal/architecture/ESP8266/MyHwESP8266.cpp@25 . This later source file doesn’t have any direct reference to the config header, but it’s been proved that it works.

Now, I’ve tried to reproduce this library, to test the issue, only including the minimum code for debug prints, but compiler complains about all the defines at the ESP8266 level.
And I tried putting an include in the MyHwESP8266.cpp to the header config file (very ugly as it’s four folder sublevels below) and the result is that as the compiler also doesn’t recognize the macro of the include guard defined before, it breaks with multiple definition errors.

I have the impression that I’m doing something terribly wrong, but I don’t know what.

I’m afraid I don’t understand how I can help you.

Do you have problems getting your code to work? If so:

  • What are you trying to achieve?
  • Where are you stuck?
  • What do you expect to happen?
  • What happens instead?
  • Do you have log output or error messages?

Or are you interested in the compilation process for C/C++ programs?