Migration Arduino to PlatformIO, first steps

I would like to ask for help. I wanted to migrate to PlatformIO from a working code project Arduino IDE. I managed to get to the “build” compilation without red errors, but after a few days of work and getting to zero red errors and zero problems, I was flooded with a large number of “yellow errors”, unfortunately without references to files and lines. There are only references to binary files with the extension “.o”. And I have no idea what to do next because these are my first steps in PlatformIO.

Source project : GitHub - AlexGyver/GyverControl: Универсальный контроллер для умной теплицы
My migration to PlatformIO : GitHub - Kmicic/250630-004058-nanoatmega328

Can someone help the old man learn the methodology to further cleanse this yellow madness of errors. Most of them are warnings like:

.pio\build\nanoatmega328\src\a0_main.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\nanoatmega328\src\service.cpp.o (symbol from plugin): In function `channelStatesServ':
(.text+0x0): multiple definition of `encMinim::isLeft()'

I would like at least one example of further action in migration…

Best regards…

Andrzej Kmicic

The problem is the include/encMinim.h file.

In line 14 to 52 it declares the class encMinim. That’s okay.

But then in lines 54 to 171 defines all the functions of that class. That’s not okay because it’s in the .h file. That header .h file gets included by many .cpp files, so many .cpp files will have a copy of the class definition of encMinim. Therefore, when the firmware is linked together, there will be many copies of the class and functions definitions. But there can only be one.

What you need to do is to properly factor the encMinim class into header (.h file, only declarations) and source (.cpp file, #includes header file, only definitions). This is just the way C/C++ works.

The post Header files and good practice. Harder than I thought - #2 by maxgerhardt shows how.

So, it’s easy:

  1. Create a new file src/encMinim.cpp
  2. Start it with #include "encMinim.h"
  3. Then cut out lines 54 to 171 from encMinim.h and paste it into encMinim.cpp
1 Like

On GitHub, I’ve posted a version where the libraries are linked to their repositories, and one library is located in the project’s local directory.

I did what I could, so I’m asking for help and advice.

Link to the project: https://github.com/Kmicic/GCMigrate

So, I can now compile the program without any problems. Perhaps someone can tell me what could be causing so many linking errors?

The vast majority of these errors concern time calculations, primarily the menu.cpp module and its final functions related to time calculations.

Please help me with at least one example of fixing the linking error…

Best regards,
AK

ps: I’m 75 years old, and if I were a bit younger and healthier, I would come to help you in this nasty and dirty war. Glory to Ukraine.

The “redefinition of TwoWire” error comes from the fact that you’re using the microWire library, which actually redefines the TwoWire class. This is fine and can work, but then everyone must include microWire.h and not Wire.h.

The “microDS3231” library needs a manual modification for that in the src/microDS3231.h file, or it will include Wire.h by default:

So I just moved that library from lib_deps into the lib/ folder and changed that line to use microwire instead.

The other part of the undefined references come from the fact a lot of global variables are declared in a1_data.h, but some of these variables were not defined in any .cpp file. So I created a src/a1_data.cpp and put in the missing vaiables, 39 variables were missed in total.

Finally, it still does not build, but only because of three errors

<artificial>:(.text+0x2132): undefined reference to `space(int, int)'
<artificial>:(.text+0x2180): undefined reference to `arrow(int, int)'
<artificial>:(.text+0x2180): undefined reference to `colon(int, int)'

This was the header function arrowcontrol.h declares

void arrow(int x, int y);
void space(int x, int y);
void colon(int x, int y);

but the arrowControl.cpp implements

void space(byte col, byte row) {
  lcd.setCursor(col, row);
  lcd.print(' ');
}
void colon(byte col, byte row) {
  lcd.setCursor(col, row);
  lcd.print(':');
}

And byte and int are different datatypes, so it fails to find the function. Since lcd.setCursor() takes in uint8_t (aka byte), I corrected the header file to say byte instead of int.

Which finally gives

Linking .pio\build\nanoatmega328\firmware.elf
Checking size .pio\build\nanoatmega328\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [========  ]  77.0% (used 1577 bytes from 2048 bytes)
Flash: [========= ]  86.5% (used 26572 bytes from 30720 bytes)
Building .pio\build\nanoatmega328\firmware.hex
======== [SUCCESS] Took 4.43 seconds ========

See pull request https://github.com/Kmicic/GCMigrate/pull/2.

Really, you can always use this method to resolve a “undefined reference to XXXX” error:

  • check the header file: What type is that variable being declared of? (E.g., int, byte, MicroDS3231, …)
  • use search (VSCode sidebar) to look for the definition of that variable inside a .cpp file
    • does it not exist? then it must be added
    • does it exist?
      • is it declared of the same type as in the header file?
      • is the code block for it disabled? (for example, surrounded by some #ifdef SOME_MACRO #endif block that’s deactivated)
      • is the source file it’s placed in compiled by the build system? (it must be in src/ or in a folder in lib/, but not for example in the include/ folder)