Multiple files issue resulting in Multiple Definitions

Hi,

I am working on a project that is making use of the NTPClient library to get the current date. I am working on a NodeMCU ESP32, so have connected it to the WiFi. When testing the library out, I worked with one file and everything went well. I was able to extract and print the current date. Now, I am trying to implement the same thing into my project, however, I am running into an issue where the library is being defined multiple times. I can't seem to figure out where to place the definitions and initialisations. I have 5 files. Here is my project structure:

  • cros.ino :
    This file is the one I upload to the chip. It includes 3 other files.
#include "cros_core.h"
#include "cros_constants.h"
#include "cros_types.h"

I define a class that has been created in cros_core.h:

CCrowboxCore g_crOSCore;

And within the setup() function, I call:
g_crOSCore.Setup();
Which has the logic of the program.

  • cros_core.h :
    This file is defines everything and also sets up a class. The definitions I have included for example are:
#include <ESP32Servo.h>
#include <WiFi.h> 
#include <FirebaseESP32.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

In this file, I also then try to initialise the NTPClient, as I would have done if everything were in one file:

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);

There is also a class set up here which looks something like:

class CCrowboxCore
{
public:
    CCrowboxCore();
    void Setup();
    void Loop();

public:
    void DebugPrint( const char *pString );
    void ReportSystemError( cros_error_code_t errorCode );
    
    //--------------------------------------
    // Public Accessor methods
    //--------------------------------------
    cros_time_t GetUptimeSeconds();
    bool        IsABirdOnThePerch();
    cros_time_t HowLongHasBirdBeenHere();
    cros_time_t HowLongHasBirdBeenGone();

And more...

  • cros_core.cpp :
    In here, I have the code for the program. In the setup() function of this class, I begin the NTPClient:
timeClient.begin();
timeClient.setTimeOffset(3600);

I then make use of the timeClient in the class loop() function.

The error I am getting from this is:

sketch\cros_core.cpp.o:(.bss.timeClient+0x0): multiple definition of `timeClient'
sketch\cros.ino.cpp.o:(.bss.timeClient+0x0): first defined here
sketch\cros_core.cpp.o:(.bss.ntpUDP+0x0): multiple definition of `ntpUDP'
sketch\cros.ino.cpp.o:(.bss.ntpUDP+0x0): first defined here
collect2.exe: error: ld returned 1 exit status

Where should I be defining and initialising:

#include <NTPClient.h>
#include <WiFiUdp.h>

And

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);

Appreciate the help!

Post the entire error message.

Also, post a complete code, preferably an MRE.

Trying to mentally piece together all your incomplete snippets into a coherent picture is more effort than I'm willing to expend.

Hi! The only left out line is:

Error compiling for board DOIT ESP32 DEVKIT V1.

You scrolled all the way up to the top of the error message window? That's not much info to go on. Good luck to you.

Yes. Do you know how I might get a more detailed error message?

Not sure if you missed it in the post but this was the error message:

sketch\cros_core.cpp.o:(.bss.timeClient+0x0): multiple definition of `timeClient'
sketch\cros.ino.cpp.o:(.bss.timeClient+0x0): first defined here
sketch\cros_core.cpp.o:(.bss.ntpUDP+0x0): multiple definition of `ntpUDP'
sketch\cros.ino.cpp.o:(.bss.ntpUDP+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
Error compiling for board DOIT ESP32 DEVKIT V1.

I fixed the issue by moving:

#include <NTPClient.h>
#include <WiFiUdp.h>

And

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);

To the .cpp file instead of the .h file.

That's the problem. You can't define global variables in a .h file that is included in two places:

  1. cros.ino
  2. cros_core.cpp

To fix it, change cros_core.h to contain:

extern WiFiUDP ntpUDP;
extern NTPClient timeClient(ntpUDP);

Then pick EITHER cros.ino or cros_core.cpp to define the two globals. The 'extern' declaration will let both source files use the global objects but you can only define them in one.

1 Like

That makes a lot of sense, thank you!