Instances of object from 3rd party library in multiple cpp files

Hi there,

I started a project in Arduino IDE and switched to platformIO because I had problems to achieve a clean structure in Arduino IDE.
I’m using several 3rd party libraries which are available in the Arduino library manager.
For example “neotimer”. I installed it in platformIO and this worked.
But now I have a problem I do not understand.

I have a main.cpp, which includes some header files, also I have added some cpp files:

main.cpp:

#include <Arduino.h>
#include "Any1.h"
#include "Any2.h"

void setup() {
    Function1();
    Function3();
}

void loop() {
    Function2();
    Function4();
}

Any1.cpp:

#include <Arduino.h>
#include <Neotimer.h>
#include "Any1.h"
#include "Any2.h"

Neotimer MyTimer1 = Neotimer();

void Function1 ( void )
{
    MyTimer1.set(100);
    MyTimer1.start();
}

void Function2 ( void )
{
    if (MyTimer1.done())
    {
        MyTimer1.reset();
    }
}

Any2.cpp:

#include <Arduino.h>
#include <Neotimer.h>
#include "Any1.h"
#include "Any2.h"

Neotimer MyTimer2 = Neotimer();

void Function3 ( void )
{
    MyTimer2.set(100);
    MyTimer2.start();
}

void Function4 ( void )
{
    if (MyTimer2.done())
    {
        MyTimer2.reset();
    }
}

Any1.h:

#ifndef ANY1_H
#define ANY1_H

void Function1 ( void );
void Function2 ( void );

#endif

Any2.h:

#ifndef ANY2_H
#define ANY2_H

void Function3 ( void );
void Function4 ( void );

#endif

Don’t wonder if this makes sense, this is just a simple sample to show my problem.

The problem is now, that the compiler fails, and I have absolutelty no idea why:

Building in release mode
Compiling .pio\build\esp32dev\src\main.cpp.o
Archiving .pio\build\esp32dev\libFrameworkArduino.a
Linking .pio\build\esp32dev\firmware.elf
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::Neotimer()':
D:\users\xxxx\Documents\PlatformIO\Projects\DebuggingProject/.pio\libdeps\esp32dev\Neotimer\src/Neotimer.h:48: multiple definition of `Neotimer::Neotimer()'
.pio\build\esp32dev\src\Any1.cpp.o:D:\users\xxxx\Documents\PlatformIO\Projects\DebuggingProject/.pio\libdeps\esp32dev\Neotimer\src/Neotimer.h:48: first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::Neotimer()':
Any2.cpp:(.text._ZN8NeotimerC2Ev+0x0): multiple definition of `Neotimer::Neotimer()'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8NeotimerC2Ev+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::Neotimer(long)':
Any2.cpp:(.text._ZN8NeotimerC2El+0x0): multiple definition of `Neotimer::Neotimer(long)'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8NeotimerC2El+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::Neotimer(long)':
Any2.cpp:(.text._ZN8NeotimerC2El+0x0): multiple definition of `Neotimer::Neotimer(long)'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8NeotimerC2El+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::~Neotimer()':
Any2.cpp:(.text._ZN8NeotimerD2Ev+0x0): multiple definition of `Neotimer::~Neotimer()'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8NeotimerD2Ev+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::~Neotimer()':
Any2.cpp:(.text._ZN8NeotimerD2Ev+0x0): multiple definition of `Neotimer::~Neotimer()'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8NeotimerD2Ev+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::init()':
Any2.cpp:(.text._ZN8Neotimer4initEv+0x0): multiple definition of `Neotimer::init()'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer4initEv+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::repeatReset()':
Any2.cpp:(.text._ZN8Neotimer11repeatResetEv+0x0): multiple definition of `Neotimer::repeatReset()'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer11repeatResetEv+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::done()':
Any2.cpp:(.text._ZN8Neotimer4doneEv+0x0): multiple definition of `Neotimer::done()'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer4doneEv+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::set(long)':
Any2.cpp:(.text._ZN8Neotimer3setEl+0x0): multiple definition of `Neotimer::set(long)'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer3setEl+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::get()':
Any2.cpp:(.text._ZN8Neotimer3getEv+0x0): multiple definition of `Neotimer::get()'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer3getEv+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::stop()':
Any2.cpp:(.text._ZN8Neotimer4stopEv+0x0): multiple definition of `Neotimer::stop()'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer4stopEv+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::reset()':
Any2.cpp:(.text._ZN8Neotimer5resetEv+0x0): multiple definition of `Neotimer::reset()'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer5resetEv+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::repeat()':
Any2.cpp:(.text._ZN8Neotimer6repeatEv+0x0): multiple definition of `Neotimer::repeat()'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer6repeatEv+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::repeat(int)':
Any2.cpp:(.text._ZN8Neotimer6repeatEi+0x0): multiple definition of `Neotimer::repeat(int)'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer6repeatEi+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::repeat(int, long)':
Any2.cpp:(.text._ZN8Neotimer6repeatEil+0x0): multiple definition of `Neotimer::repeat(int, long)'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer6repeatEil+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::start()':
Any2.cpp:(.text._ZN8Neotimer5startEv+0x0): multiple definition of `Neotimer::start()'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer5startEv+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::debounce(bool)':
Any2.cpp:(.text._ZN8Neotimer8debounceEb+0x0): multiple definition of `Neotimer::debounce(bool)'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer8debounceEb+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::restart()':
Any2.cpp:(.text._ZN8Neotimer7restartEv+0x0): multiple definition of `Neotimer::restart()'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer7restartEv+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::waiting()':
Any2.cpp:(.text._ZN8Neotimer7waitingEv+0x0): multiple definition of `Neotimer::waiting()'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer7waitingEv+0x0): first defined here
.pio\build\esp32dev\src\Any2.cpp.o: In function `Neotimer::started()':
Any2.cpp:(.text._ZN8Neotimer7startedEv+0x0): multiple definition of `Neotimer::started()'
.pio\build\esp32dev\src\Any1.cpp.o:Any1.cpp:(.text._ZN8Neotimer7startedEv+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\esp32dev\firmware.elf] Error 1

Can anyone give me a hint what I’m doing wrong?
Is this Neotimer library not able to be used in 2 cpps at the same time?

The problem is not with your code, but with the library. It seems the

is a header-only library that directly puts the implementation in the header file. Thus if you include it from Any2.cpp and Any1.cpp, you’ve duplicated the implemntation and the compiler says

etc. The library expects that only one .cpp file ever includes the header.

As one can see, this exact issue has been raised with the library author, who did nothing about it: move methods definitions to a cpp file · Issue #12 · jrullan/neotimer · GitHub

But someone else has got a fork of it which fixes the problem: Move definitions to cpp file by teosibileau · Pull Request #15 · jrullan/neotimer · GitHub

Thus you should do the following:

  • edit your platformio.ini to remove the old neotimer declaration in lib_deps (or remove the folder from lib/ if you’ve installed the library that way) and replace it with
# fixed version of neotimer in that branch
lib_deps =
   https://github.com/teosibileau/neotimer.git#move_definitions_to_cpp_file

then remove the .pio folder of the project and rebuild the project. If git (Git - Downloads) is properly installed on your system, it should pull the new library version from there and the fixed version should compile :slight_smile:

(Alternative: Remove library declaration from lib_deps, download fixed version from https://github.com/teosibileau/neotimer/archive/move_definitions_to_cpp_file.zip and just put that in the lib/ folder).

1 Like

Thank you so much for your help. I wonder how I could not find this on Google :man_facepalming:
However, I’m struggling with using this neotimer any longer as it seems not to be well supported.
I found the “RBD Timer” Library which could do something very similar. I think I will try this one instead.