Linker errors about multiple definitions, are they from use of #define inside include guard?

I’m finishing up porting my project from Arduino to PlatformIO. I’m getting linker errors about certain functions having multiple definitions. It reminds me of what happens when you don’t use an include guard in your header files, except I’ve double checked and I’m using them in every header file. I am however defining several preprocessor constants inside the include guards and I’m wondering if that’s allowed. Can you tell me if this is ok?

#ifndef whatever_h
#define whatever_h

//some vars
//some funcs
#define const1
#define const2

#endif

Or is it that once you open a #define/#endif pair that you can’t put other #defines inside of it without breaking the include guard? Thank you!!!

Hi, @jordanapplewhite. There are a lot of reasons for this error.
Could you provide a little bit more information? The output log or maybe download link for your project?

I would love to but it’s for a company so I can’t share it at the moment :frowning:
But to the original question there should be no problem defining a constant with the preprocessor inside a standard include guard as per C++ standards?

I will attempt to make a different version with the sensitive parts removed for troubleshooting. After the linker errors it is saying “Unable to execute: platformio” so I’m wondering if this is because platformio is not in my path somehow. It seems to work when I compile and upload the Blink project though…

Include guard and simple constant defines are a standard approach, so they shouldn’t cause any linker problem. Probably global variables "//some vars" in header file might be the main culprit.

1 Like

Do you use PlatformIO IDE or classic PlatformIO CLI? If CLI, how did you install it?

Yes! Good call! Upon further examination of the error log all the multiple definition errors are variables that exist in headers, not function decalarations. How do we handle this in C++? I have many, many global variables and I am moving to PlatformIO from Arduino so that I can provide proper encapsulation for all the modules. I assumed that the include guard would prevent multiple definition errors on global variables but this is not the case? Thanks so much for your suggestions.

@ivankravets I use PlatformIO IDE on Windows 10. I could not find it in my PATH but I just found the Terminal button inside PlatformIO IDE and it works from there, so I believe that error is a consequence of my multiple definition errors. Thanks to you both for helping me with this! I will be glad to help others on the forum once I get up to speed.

@valeros from your suggestion I believe this is the culprit. I need to declare AutoPlayTimer in the header because other modules reference it and call its methods. In order to declare it I need to provide the argument to the constructor. In order to provide the argument to the constructer I need to include the “config.h” file which has many project specific global variables such as SHUFFLE_INTERVAL, and the variables in “config.h” are the ones triggering the linker errors. So what is the better way to manage this? Thank you for your help!

#ifndef AUTOPLAY_H
#define AUTOPLAY_H

  #include <myTimer.h>
  #include "config.h"
  Timer AutoPlayTimer(SHUFFLE_INTERVAL);

  //some func declarations

#endif

If I get you right, here is what I propose:
If you want to keep Timer AutoPlayTimer in your header file, you should only declare object by adding the extern keyword (this keyword is required to distinguish the declaration from the definition) in the .h file, something like this:

extern Timer AutoPlayTimer;

Then define this object once in any source file:

Timer AutoPlayTimer(SHUFFLE_INTERVAL);

Thus, every source file with global include should have an access to this object.

2 Likes

PlatformIO IDE has built-in the latest PlatformIO CLI. PlatformIO CLI is not installed globally when you install PlatformIO IDE. You have to option to use PlatformIO CLI (if you really need it):

  1. To use PlatformIO Terminal from IDE (recommended)
  2. To Menu: PlatformIO > Install Shell Commands and use system Terminal.
1 Like

@valeros Excellent, I did not understand the extern keyword before now but that makes perfect sense. I likely have to do this in several places. I will make those changes and report back! Thank you so much!!!

p.s. I plan on open sourcing my lib for the community once all work is done and the sensitive info is removed.

@ivankravets Just a heads up on my computer with Windows 10 when I choose PlatformIO > Install Shell Commands there is no confirmation of that action from Atom and the platformio command is not recognized in either CMD or Powershell. It works fine from the Terminal within the IDE. It’s not required for me at the moment because I am only using the IDE but if you’d like me to test this further I can start a new forum thread or whatever you like. Thank you! :slight_smile: