A new PlatformIO user coding wrong, getting multiple definition & first defined here errors

Very sorry if this is the wrong group or posted incorrectly first post on this community.

There is so many discussions about this subject I have become totally confused.
I have taken this from a much larger programme and stripped it down to its bare elements, that still exhibits the same problem I’m experiencing. First is a quick picture showing the programme structure

Main.cpp

#include <Arduino.h>
#include <TaskScheduler.h>
#include <Wire.h>
#include <SPI.h>
#include "Power.h"
void setup() {
currentoldA=0;
currentoldB=0;
voltageold=0;
}
void loop() {
  
  Power();
  delay(2000);
}

Power.cpp

#include <Arduino.h>
#include "Power.h"
void Power(){
  
  shuntvoltage_A = 0;
  busvoltage_A = 0;
  current_mA_A = 0;
  loadvoltage_A = 0;
  power_mW_A = 0;
  shuntvoltage_B = 0;
  busvoltage_B = 0;
  current_mA_B = 0;
  loadvoltage_B = 0;
  power_mW_B = 0;
  for(int i=0;i<=9;i++){
    shuntvoltage_A = shuntvoltage_A + ina219_A.getShuntVoltage_mV();
    busvoltage_A = busvoltage_A + ina219_A.getBusVoltage_V();
    current_mA_A = current_mA_A + ina219_A.getCurrent_mA();
    power_mW_A = power_mW_A + ina219_A.getPower_mW();
    loadvoltage_A = busvoltage_A + (shuntvoltage_A / 1000);
  }
  
  for(int i=0;i<=9;i++){
    shuntvoltage_B = shuntvoltage_B + ina219_B.getShuntVoltage_mV();
    busvoltage_B = busvoltage_B + ina219_B.getBusVoltage_V();
    current_mA_B = current_mA_B + ina219_B.getCurrent_mA();
    power_mW_B = power_mW_B + ina219_B.getPower_mW();
    loadvoltage_B = busvoltage_B + (shuntvoltage_B / 1000);
  }
  shuntvoltage_A = shuntvoltage_A /10;
  busvoltage_A = busvoltage_A /10;
  current_mA_A = current_mA_A /10;
  power_mW_A = power_mW_A /10;
  loadvoltage_A = loadvoltage_A /10;
  shuntvoltage_B = shuntvoltage_B /10;
  busvoltage_B = busvoltage_B /10;
  current_mA_B = current_mA_B /10;
  power_mW_B = power_mW_B /10;
  loadvoltage_B = loadvoltage_B /10;
  currentoldA=currentoldA+current_mA_A;
  currentoldB=currentoldB+current_mA_B;
  voltageold=voltageold+busvoltage_A;
  if(Thing_Flag>=60){
    currentoldA=currentoldA/60;
    currentoldB=currentoldB/60;
    voltageold=voltageold/60;
  //thingspeak1();
  Thing_Flag=0;
  }
  Thing_Flag++;
  Serial.print("Bus Voltage_A:   "); Serial.print(busvoltage_A); Serial.println(" V");
  Serial.print("Shunt Voltage_A: "); Serial.print(shuntvoltage_A); Serial.println(" mV");
  Serial.print("Load Voltage_A:  "); Serial.print(loadvoltage_A); Serial.println(" V");
  Serial.print("Current_A:       "); Serial.print(current_mA_A); Serial.println(" mA");
  Serial.print("Power_A:         "); Serial.print(power_mW_A); Serial.println(" mW");
  Serial.println("");
  Serial.print("Bus Voltage_B:   "); Serial.print(busvoltage_B); Serial.println(" V");
  Serial.print("Shunt Voltage_B: "); Serial.print(shuntvoltage_B); Serial.println(" mV");
  Serial.print("Load Voltage_B:  "); Serial.print(loadvoltage_B); Serial.println(" V");
  Serial.print("Current_B:       "); Serial.print(current_mA_B); Serial.println(" mA");
  Serial.print("Power_B:         "); Serial.print(power_mW_B); Serial.println(" mW");
  Serial.println("");
  
}

Power.h

#ifndef POWER_H
#define POWER_H
#include <Arduino.h>
#include <Adafruit_INA219.h>
Adafruit_INA219 ina219_A;
Adafruit_INA219 ina219_B(0x41);
void Power();
extern float currentoldA;
extern float currentoldB;
extern float voltageold;
float shuntvoltage_A = 0;
float busvoltage_A = 0;
float current_mA_A = 0;
float loadvoltage_A = 0;
float power_mW_A = 0;
float shuntvoltage_B = 0;
float busvoltage_B = 0;
float current_mA_B = 0;
float loadvoltage_B = 0;
float power_mW_B = 0;
int Thing_Flag=0;
#endif

And this is the error I keep receiving

Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32dev.html
PLATFORM: Espressif 32 1.12.2 > Espressif ESP32 Dev Module
HARDWARE: ESP32 240MHz, 320KB RAM, 4MB Flash
DEBUG: Current (esp-prog) External (esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
PACKAGES:
 - framework-arduinoespressif32 3.10004.200129 (1.0.4)
 - tool-esptoolpy 1.20600.0 (2.6.0)
 - tool-openocd-esp32 1.1000.20190708 (10.0)
 - toolchain-xtensa32 2.50200.80 (5.2.0)
LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 34 compatible libraries
Scanning dependencies...
Dependency Graph
|-- <Adafruit INA219> 1.0.9
|   |-- <Adafruit NeoPixel> 1.4.0
|   |-- <Adafruit GFX Library> 1.8.3
|   |   |-- <Adafruit BusIO> 1.3.0
|   |   |   |-- <SPI> 1.0
|   |   |   |-- <Wire> 1.0.1
|   |   |-- <SPI> 1.0
|   |   |-- <Wire> 1.0.1
|   |-- <Adafruit SSD1306> 2.2.1
|   |   |-- <Adafruit GFX Library> 1.8.3
|   |   |   |-- <Adafruit BusIO> 1.3.0
|   |   |   |   |-- <SPI> 1.0
|   |   |   |   |-- <Wire> 1.0.1
|   |   |   |-- <SPI> 1.0
|   |   |   |-- <Wire> 1.0.1
|   |   |-- <SPI> 1.0
|   |   |-- <Wire> 1.0.1
|   |-- <Adafruit BusIO> 1.3.0
|   |   |-- <SPI> 1.0
|   |   |-- <Wire> 1.0.1
|   |-- <Wire> 1.0.1
|-- <TaskScheduler> 3.1.6
|-- <Libray>
|   |-- <Adafruit INA219> 1.0.9
|   |   |-- <Adafruit NeoPixel> 1.4.0
|   |   |-- <Adafruit GFX Library> 1.8.3
|   |   |   |-- <Adafruit BusIO> 1.3.0
|   |   |   |   |-- <SPI> 1.0
|   |   |   |   |-- <Wire> 1.0.1
|   |   |   |-- <SPI> 1.0
|   |   |   |-- <Wire> 1.0.1
|   |   |-- <Adafruit SSD1306> 2.2.1
|   |   |   |-- <Adafruit GFX Library> 1.8.3
|   |   |   |   |-- <Adafruit BusIO> 1.3.0
|   |   |   |   |   |-- <SPI> 1.0
|   |   |   |   |   |-- <Wire> 1.0.1
|   |   |   |   |-- <SPI> 1.0
|   |   |   |   |-- <Wire> 1.0.1
|   |   |   |-- <SPI> 1.0
|   |   |   |-- <Wire> 1.0.1
|   |   |-- <Adafruit BusIO> 1.3.0
|   |   |   |-- <SPI> 1.0
|   |   |   |-- <Wire> 1.0.1
|   |   |-- <Wire> 1.0.1
|-- <SPI> 1.0
|-- <Wire> 1.0.1
Building in release mode
Compiling .pio\build\esp32dev\src\main.cpp.o
Linking .pio\build\esp32dev\firmware.elf
.pio\build\esp32dev\src\main.cpp.o:(.bss.ina219_A+0x0): multiple definition of `ina219_A'
.pio\build\esp32dev\src\Power.cpp.o:(.bss.ina219_A+0x0): first defined here
.pio\build\esp32dev\src\main.cpp.o:(.bss.ina219_B+0x0): multiple definition of `ina219_B'
.pio\build\esp32dev\src\Power.cpp.o:(.bss.ina219_B+0x0): first defined here
.pio\build\esp32dev\src\main.cpp.o:(.bss.Thing_Flag+0x0): multiple definition of `Thing_Flag'
.pio\build\esp32dev\src\Power.cpp.o:(.bss.Thing_Flag+0x0): first defined here
.pio\build\esp32dev\src\main.cpp.o:(.bss.power_mW_B+0x0): multiple definition of `power_mW_B'
.pio\build\esp32dev\src\Power.cpp.o:(.bss.power_mW_B+0x0): first defined here
.pio\build\esp32dev\src\main.cpp.o:(.bss.loadvoltage_B+0x0): multiple definition of `loadvoltage_B'
.pio\build\esp32dev\src\Power.cpp.o:(.bss.loadvoltage_B+0x0): first defined here
.pio\build\esp32dev\src\main.cpp.o:(.bss.current_mA_B+0x0): multiple definition of `current_mA_B'
.pio\build\esp32dev\src\Power.cpp.o:(.bss.current_mA_B+0x0): first defined here
.pio\build\esp32dev\src\main.cpp.o:(.bss.busvoltage_B+0x0): multiple definition of `busvoltage_B'
.pio\build\esp32dev\src\Power.cpp.o:(.bss.busvoltage_B+0x0): first defined here
.pio\build\esp32dev\src\main.cpp.o:(.bss.shuntvoltage_B+0x0): multiple definition of `shuntvoltage_B'
.pio\build\esp32dev\src\Power.cpp.o:(.bss.shuntvoltage_B+0x0): first defined here
.pio\build\esp32dev\src\main.cpp.o:(.bss.power_mW_A+0x0): multiple definition of `power_mW_A'
.pio\build\esp32dev\src\Power.cpp.o:(.bss.power_mW_A+0x0): first defined here
.pio\build\esp32dev\src\main.cpp.o:(.bss.loadvoltage_A+0x0): multiple definition of `loadvoltage_A'
.pio\build\esp32dev\src\Power.cpp.o:(.bss.loadvoltage_A+0x0): first defined here
.pio\build\esp32dev\src\main.cpp.o:(.bss.current_mA_A+0x0): multiple definition of `current_mA_A'
.pio\build\esp32dev\src\Power.cpp.o:(.bss.current_mA_A+0x0): first defined here
.pio\build\esp32dev\src\main.cpp.o:(.bss.busvoltage_A+0x0): multiple definition of `busvoltage_A'
.pio\build\esp32dev\src\Power.cpp.o:(.bss.busvoltage_A+0x0): first defined here
.pio\build\esp32dev\src\main.cpp.o:(.bss.shuntvoltage_A+0x0): multiple definition of `shuntvoltage_A'
.pio\build\esp32dev\src\Power.cpp.o:(.bss.shuntvoltage_A+0x0): first defined here
.pio\build\esp32dev\src\Power.cpp.o:(.literal._Z5Powerv+0x3c): undefined reference to `currentoldA'
.pio\build\esp32dev\src\Power.cpp.o:(.literal._Z5Powerv+0x40): undefined reference to `currentoldB'
.pio\build\esp32dev\src\Power.cpp.o:(.literal._Z5Powerv+0x44): undefined reference to `voltageold'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\esp32dev\firmware.elf] Error 1

Please can somebody show me the error of my ways.
Please remember very new to this, getting very old,

Duplicate of the general mistake of not properly declaring global variables / duplicating them:

Let’s first go through the multiple definitions of ... errors.

Remember, an #include <Header.h> statement is a fancy way of saying "copy-paste the content of that file at this place.

You write in your Power.h:

float shuntvoltage_A = 0;

and then in main.cpp:

#include "Power.h"

and also in Power.cpp:

#include "Power.h"

When the GCC preprocessor expands the #include .. directives, what do you end up with? Right, a main.cpp and Power.cpp which will both have the content

float shuntvoltage_A = 0;

in them. This is a global variable declaration and there can only be one global variable of a specific name. Since both main.cpp and Power.cpp define that global variable through your include file, the compiler gives you a multiple definition of error.

The solution is that in your header file, you only declare the existence of a global variable of some name and type, but don’t define it. This is done with a statement

extern float shuntvoltage_A;

meaning "compiler, I’m declaring here an external global variable of type float with the name shutvoltage_A. The defininition of the variable has then to be done at only 1 place (e.g. in the Power.cpp), e.g. with the code

float shutvoltage_A = 0;

in one place / compilation unit, e.g. any one cpp file.

For the undefined reference to 'currentoldA' you do the same type of error but in reverse: Your Power.h declares

extern float currentoldA;

but there is no definition statement like

float currentoldA = <some initial value>; 

to be found. Thus you have declared the existence of the variable but haven’t brought in actual existence by defining it, and you get a undefined reference error.

The correct code for Power.h would be:

#ifndef POWER_H
#define POWER_H

#include <Arduino.h>
#include <Adafruit_INA219.h>

/* global objects */
extern Adafruit_INA219 ina219_A;
extern Adafruit_INA219 ina219_B;

/* global functions */
void Power();

/* global float vars */
extern float currentoldA;
extern float currentoldB;
extern float voltageold;
extern float shuntvoltage_A;
extern float busvoltage_A;
extern float current_mA_A;
extern float loadvoltage_A;
extern float power_mW_A;
extern float shuntvoltage_B;
extern float busvoltage_B;
extern float current_mA_B;
extern float loadvoltage_B;
extern float power_mW_B;
extern int Thing_Flag;
#endif

and for Power.cpp:

#include <Arduino.h>
#include "Power.h"

/* define / construct global objects here */
Adafruit_INA219 ina219_A;
Adafruit_INA219 ina219_B(0x41);

/* define global float vars */
float currentoldA = 0;
float currentoldB = 0;
float voltageold = 0;
float shuntvoltage_A = 0;
float busvoltage_A = 0;
float current_mA_A = 0;
float loadvoltage_A = 0;
float power_mW_A = 0;
float shuntvoltage_B = 0;
float busvoltage_B = 0;
float current_mA_B = 0;
float loadvoltage_B = 0;
float power_mW_B = 0;
int Thing_Flag = 0;

/* implement declared function */
void Power()
{
    shuntvoltage_A = 0;
    busvoltage_A = 0;
    current_mA_A = 0;
    loadvoltage_A = 0;
    power_mW_A = 0;
    shuntvoltage_B = 0;
    busvoltage_B = 0;
    current_mA_B = 0;
    loadvoltage_B = 0;
    power_mW_B = 0;
    for (int i = 0; i <= 9; i++) {
        shuntvoltage_A = shuntvoltage_A + ina219_A.getShuntVoltage_mV();
        busvoltage_A = busvoltage_A + ina219_A.getBusVoltage_V();
        current_mA_A = current_mA_A + ina219_A.getCurrent_mA();
        power_mW_A = power_mW_A + ina219_A.getPower_mW();
        loadvoltage_A = busvoltage_A + (shuntvoltage_A / 1000);
    }

    for (int i = 0; i <= 9; i++) {
        shuntvoltage_B = shuntvoltage_B + ina219_B.getShuntVoltage_mV();
        busvoltage_B = busvoltage_B + ina219_B.getBusVoltage_V();
        current_mA_B = current_mA_B + ina219_B.getCurrent_mA();
        power_mW_B = power_mW_B + ina219_B.getPower_mW();
        loadvoltage_B = busvoltage_B + (shuntvoltage_B / 1000);
    }
    shuntvoltage_A = shuntvoltage_A / 10;
    busvoltage_A = busvoltage_A / 10;
    current_mA_A = current_mA_A / 10;
    power_mW_A = power_mW_A / 10;
    loadvoltage_A = loadvoltage_A / 10;
    shuntvoltage_B = shuntvoltage_B / 10;
    busvoltage_B = busvoltage_B / 10;
    current_mA_B = current_mA_B / 10;
    power_mW_B = power_mW_B / 10;
    loadvoltage_B = loadvoltage_B / 10;
    currentoldA = currentoldA + current_mA_A;
    currentoldB = currentoldB + current_mA_B;
    voltageold = voltageold + busvoltage_A;
    if (Thing_Flag >= 60) {
        currentoldA = currentoldA / 60;
        currentoldB = currentoldB / 60;
        voltageold = voltageold / 60;
        //thingspeak1();
        Thing_Flag = 0;
    }
    Thing_Flag++;
    Serial.print("Bus Voltage_A:   ");
    Serial.print(busvoltage_A);
    Serial.println(" V");
    Serial.print("Shunt Voltage_A: ");
    Serial.print(shuntvoltage_A);
    Serial.println(" mV");
    Serial.print("Load Voltage_A:  ");
    Serial.print(loadvoltage_A);
    Serial.println(" V");
    Serial.print("Current_A:       ");
    Serial.print(current_mA_A);
    Serial.println(" mA");
    Serial.print("Power_A:         ");
    Serial.print(power_mW_A);
    Serial.println(" mW");
    Serial.println("");
    Serial.print("Bus Voltage_B:   ");
    Serial.print(busvoltage_B);
    Serial.println(" V");
    Serial.print("Shunt Voltage_B: ");
    Serial.print(shuntvoltage_B);
    Serial.println(" mV");
    Serial.print("Load Voltage_B:  ");
    Serial.print(loadvoltage_B);
    Serial.println(" V");
    Serial.print("Current_B:       ");
    Serial.print(current_mA_B);
    Serial.println(" mA");
    Serial.print("Power_B:         ");
    Serial.print(power_mW_B);
    Serial.println(" mW");
    Serial.println("");
}

main.cpp can stay the same.

1 Like

Thank you for your very fast reply and I thought so much easy to understand explanation, but unfortunately I’m still receiving the same sort of errors but now in a different place.
I don’t know how you made the code I posted so nice but I hope you can understand this:

Power.h

#ifndef POWER_H
#define POWER_H
#include <Arduino.h>
#include <Adafruit_INA219.h>
Adafruit_INA219 ina219_A;
Adafruit_INA219 ina219_B(0x41);
extern Adafruit_INA219 ina219_A;
extern Adafruit_INA219 ina219_B;
void Power();
extern float currentoldA;
extern float currentoldB;
extern float voltageold;
extern float shuntvoltage_A = 0;
extern float busvoltage_A = 0;
extern float current_mA_A = 0;
extern float loadvoltage_A = 0;
extern float power_mW_A = 0;
extern float shuntvoltage_B = 0;
extern float busvoltage_B = 0;
extern float current_mA_B = 0;
extern float loadvoltage_B = 0;
extern float power_mW_B = 0;
extern int Thing_Flag=0;
#endif

Power.cpp

#include <Arduino.h>
#include "Power.h"
Adafruit_INA219 ina219_A;
Adafruit_INA219 ina219_B(0x41);
/* define global float vars */
float currentoldA = 0;
float currentoldB = 0;
float voltageold = 0;
float shuntvoltage_A = 0;
float busvoltage_A = 0;
float current_mA_A = 0;
float loadvoltage_A = 0;
float power_mW_A = 0;
float shuntvoltage_B = 0;
float busvoltage_B = 0;
float current_mA_B = 0;
float loadvoltage_B = 0;
float power_mW_B = 0;
int Thing_Flag = 0;
void Power(){
  
  shuntvoltage_A = 0;
  busvoltage_A = 0;
  current_mA_A = 0;
  loadvoltage_A = 0;
  power_mW_A = 0;
  shuntvoltage_B = 0;
  busvoltage_B = 0;
  current_mA_B = 0;
  loadvoltage_B = 0;
  power_mW_B = 0;
  for(int i=0;i<=9;i++){
    shuntvoltage_A = shuntvoltage_A + ina219_A.getShuntVoltage_mV();
    busvoltage_A = busvoltage_A + ina219_A.getBusVoltage_V();
    current_mA_A = current_mA_A + ina219_A.getCurrent_mA();
    power_mW_A = power_mW_A + ina219_A.getPower_mW();
    loadvoltage_A = busvoltage_A + (shuntvoltage_A / 1000);
  }
  
  for(int i=0;i<=9;i++){
    shuntvoltage_B = shuntvoltage_B + ina219_B.getShuntVoltage_mV();
    busvoltage_B = busvoltage_B + ina219_B.getBusVoltage_V();
    current_mA_B = current_mA_B + ina219_B.getCurrent_mA();
    power_mW_B = power_mW_B + ina219_B.getPower_mW();
    loadvoltage_B = busvoltage_B + (shuntvoltage_B / 1000);
  }
  shuntvoltage_A = shuntvoltage_A /10;
  busvoltage_A = busvoltage_A /10;
  current_mA_A = current_mA_A /10;
  power_mW_A = power_mW_A /10;
  loadvoltage_A = loadvoltage_A /10;
  shuntvoltage_B = shuntvoltage_B /10;
  busvoltage_B = busvoltage_B /10;
  current_mA_B = current_mA_B /10;
  power_mW_B = power_mW_B /10;
  loadvoltage_B = loadvoltage_B /10;
  currentoldA=currentoldA+current_mA_A;
  currentoldB=currentoldB+current_mA_B;
  voltageold=voltageold+busvoltage_A;
  if(Thing_Flag>=60){
    currentoldA=currentoldA/60;
    currentoldB=currentoldB/60;
    voltageold=voltageold/60;
  //thingspeak1();
  Thing_Flag=0;
  }
  Thing_Flag++;
  Serial.print("Bus Voltage_A:   "); Serial.print(busvoltage_A); Serial.println(" V");
  Serial.print("Shunt Voltage_A: "); Serial.print(shuntvoltage_A); Serial.println(" mV");
  Serial.print("Load Voltage_A:  "); Serial.print(loadvoltage_A); Serial.println(" V");
  Serial.print("Current_A:       "); Serial.print(current_mA_A); Serial.println(" mA");
  Serial.print("Power_A:         "); Serial.print(power_mW_A); Serial.println(" mW");
  Serial.println("");
  Serial.print("Bus Voltage_B:   "); Serial.print(busvoltage_B); Serial.println(" V");
  Serial.print("Shunt Voltage_B: "); Serial.print(shuntvoltage_B); Serial.println(" mV");
  Serial.print("Load Voltage_B:  "); Serial.print(loadvoltage_B); Serial.println(" V");
  Serial.print("Current_B:       "); Serial.print(current_mA_B); Serial.println(" mA");
  Serial.print("Power_B:         "); Serial.print(power_mW_B); Serial.println(" mW");
  Serial.println("");
  
}

And the error messages I’m now receiving:

Please can you show me where I’ve gone wrong? You made it look so easy.

You didn’t properly adapt the code that was given above. E.g. there’s a double definition/decleration in Power.h now with

The first two lines must be removed.

Also you have = 0; at the end of every extern definition for the floats. You cannot initialize a variable in an extern declaration – that’s what the definition in Power.cpp is for. Revisit these lines:

must be just

extern float shuntvoltage_A; 
extern float busvoltage_A;
..

etc.

Rest looks okay, just Power.h is broken.

1 Like

Well thank you sir. It is now compiling with no errors!!!
Thank you ever so much for taking the time to be so courteous with your reply.
I hope I won’t have to trouble you again but please don’t hold your breath.

Have a very good evening and a super weekend (if you’re allowed out in your part of the world)

1 Like

Hi, there are a better way:
in the Power.h file you just need to use ‘inline’ before the global variable/objects, like:

//global vars
inline float shuntvoltage_A = 0;

//global objects
inline Adafruit_INA219 ina219_A;
inline Adafruit_INA219 ina219_B(0x41);

with that you can declare and define the variable/object in the .h file, so isn’t neccesary to do the definition in the .cpp file.

read more: C++ Global variable declaration - Stack Overflow

also, if is compiling fine, but compiler show some warnings I recommend to configure your platformio.ini file to compile with a newer version of C++, like that:

build_unflags = -std=gnu++11 ;Old version
build_flags = -std=gnu++2a  ;Use new version

You can read this:

I just open this account to share this solution, because I had the same problem as meathome2017, so I hope this can be helpfull to someone in the future :smile: