arkhipenko / TaskScheduler

Cooperative multitasking for Arduino, ESPx, STM32, nRF and other microcontrollers
http://playground.arduino.cc/Code/TaskScheduler
BSD 3-Clause "New" or "Revised" License
1.21k stars 221 forks source link

Compilation error when try to warp TaskScheduler's Task and execute() in a class #179

Closed keekychen closed 6 months ago

keekychen commented 6 months ago

I have below simple files structure try to wrap TaskScheduler Task and execute() ... in to a class so what I can better organize my code.

sketch_jan11a.ino
|-src
|-  |--MyScheduler.h
|-  |--MyScheduler.cpp

sketch_jan11a.ino:

#include "src/MyScheduler.h"

Scheduler runner; // Global Scheduler object
MyScheduler myScheduler(&runner); // Pass the pointer to the scheduler

void setup() {
    myScheduler.init();
}

void loop() {
    myScheduler.start();
}

MyScheduler.h:

#ifndef MYSCHEDULER_H
#define MYSCHEDULER_H

#include <Arduino.h>
#include <TaskScheduler.h>

class MyScheduler {
public:
    MyScheduler(Scheduler *scheduler); // Constructor with scheduler pointer
    void init();
    void start();

private:
    static void taskOne();
    Task t1;
    Scheduler *runner; // Pointer to the scheduler
};

#endif  // MYSCHEDULER_H

MyScheduler.cpp

#include "MyScheduler.h"

MyScheduler::MyScheduler(Scheduler *scheduler) : runner(scheduler) {}

void MyScheduler::taskOne() { /* Task 1 code */ }

void MyScheduler::init() {
    t1.set(2000, TASK_FOREVER, &taskOne);
    runner->addTask(t1);
    t1.enable();

}

void MyScheduler::start() {
    runner->execute();
}

I use Arduino IDE 2.2.1, when I compile above code, IDE will give me a

sing precompiled core: C:\Users\blah\AppData\Local\Temp\arduino\cores\arduino_avr_uno_fc01113908eeb2777ef53e904c6961f4\core.a
Linking everything together...
"C:\\Users\\blah\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-gcc" -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega328p -o "C:\\Users\\blah\\AppData\\Local\\Temp\\arduino\\sketches\\A71E5A22E32E6A3E947EF88775DC5593/sketch_jan11a.ino.elf" "C:\\Users\\blah\\AppData\\Local\\Temp\\arduino\\sketches\\A71E5A22E32E6A3E947EF88775DC5593\\sketch\\sketch_jan11a.ino.cpp.o" "C:\\Users\\blah\\AppData\\Local\\Temp\\arduino\\sketches\\A71E5A22E32E6A3E947EF88775DC5593\\sketch\\src\\MyScheduler.cpp.o" "C:\\Users\\blah\\AppData\\Local\\Temp\\arduino\\sketches\\A71E5A22E32E6A3E947EF88775DC5593/..\\..\\cores\\arduino_avr_uno_fc01113908eeb2777ef53e904c6961f4\\core.a" "-LC:\\Users\\blah\\AppData\\Local\\Temp\\arduino\\sketches\\A71E5A22E32E6A3E947EF88775DC5593" -lm
C:\Users\blah\AppData\Local\Temp\arduino\sketches\A71E5A22E32E6A3E947EF88775DC5593\sketch\src\MyScheduler.cpp.o (symbol from plugin): In function `MyScheduler::taskOne()':
(.text+0x0): multiple definition of `Task::isEnabled()'
C:\Users\blah\AppData\Local\Temp\arduino\sketches\A71E5A22E32E6A3E947EF88775DC5593\sketch\sketch_jan11a.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here
C:\Users\blah\AppData\Local\Temp\arduino\sketches\A71E5A22E32E6A3E947EF88775DC5593\sketch\src\MyScheduler.cpp.o (symbol from plugin): In function `MyScheduler::taskOne()':
(.text+0x0): multiple definition of `Task::getInterval()'

blah... omitted...

Compilation error: exit status 1

I tried many ways try to understand why it happen includes:

  1. use different board such as STM32 instead of AVR
  2. change TaskScheduler different versions from 2.6.0 to 3.7.0
  3. remove -flto flags in different hardware complier settings 4, change code structure such as move “Scheduler runner” in to inside of class definition, remove static statement, etc. 5, clean Arduino caches

no lucky.

Could someone share me why I have this problem and how to fix it? Thank you!

schlimmchen commented 6 months ago

Well... TaskScheduler is a header-only library. It comes in two parts: TaskSchedulerDeclarations.h and TaskScheduler.h. You must not include TaskScheduler.h in multiple compilation units. You did so by #includeing that file in MyScheduler.cpp and in sketch_jan11a.ino, both via MyScheduler.h.

MyScheduler.h shall #include file TaskSchedulerDeclarations.h. Then, TaskScheduler.h (which also has definitions, not just declarations) shall be #included only in file MyScheduler.cpp. Then, only a single compilation unit will have the definitions and your linker errors will go away.

arkhipenko commented 6 months ago

https://github.com/arkhipenko/TaskScheduler/tree/master/examples/Scheduler_example16_Multitab https://github.com/arkhipenko/TaskScheduler/tree/master/examples/Scheduler_example27_PlatformIO