Collect2.exe: error: ld returned 1 exit status : cannot find how to solve it

Hello,

I’m new user of PlatformIO (comming from Notepadd++ and Arduino IDE). On one of my project, I’m trying to split my code into 2 cpp files: I’m trying to moove the functions dedicated to deal with my MAX31865 ADC into a dedicated cpp file.
When I try to build the code, I’ve the following errors:
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\feather32u4\firmware.elf] Error 1
I’ve read some topic on the forum about this error, in particular:

But I wasn’t able to find where is the error in my code.

Here is how my files are organized:
image

The max31865.h code:

#ifndef max31865_h
#define max35865_h

#include <Arduino.h>
#include <SPI.h>

/************************** MAX31865 Parameter ***********************************/

#define REGISTER_CONFIG 0x0 // MAX31865 Configuration register adress
#define REGISTER_RTD 0x01   // MAX31865 RTD MSBs register adress
#define REGISTER_FAULT 0x07 // MAX31865 fault register adress
#define RTD_A 3.9083e-3     // Callendar-Van Dusen coefficient values used in equation to convert resistance value into temperature
#define RTD_B -5.775e-7     // Callendar-Van Dusen coefficient values used in equation to convert resistance value into temperature

/*MAX31865 global variables*/

int max31865CS = 0;          // CS Pin for MAX31865
byte configInit = 0b0;       // The config byte that will be send to MAX31865 at init. The config bit is determined in max31865Init() function depending on RTD wires number and filter frequency
byte configVbias = 0b0;      // Config byte that will be send to MAX31865 to enable Vbias. The config byte is determined in max31865Init() function, based on configInit byte
byte config1Shot = 0b0;      // Config byte that will be send to MAX31865 to enable 1-shot. The config byte is determined in max31865Init() function, based on configInit & configVbias bytes
byte configFaultClear = 0b0; // Config byte that will clear fault register. The config byte is determined in max31865Init() function, based on configInit byte
float refResistor = 0;       // Reference resistor value for calculation of current RTD resistance value
float RTDnominal = 0;        // Nominal 0-degrees-C resistance of the RTD for convertion of RTD resistance value into temperature

/*MAX31865 function prototype*/

bool max31865Init(int cs = 23, int wire = 3, int freq = 50, float ref = 4300, float rtd = 1000);
void max31865ReadRTD(word *rtd, bool *fault);
void max31865Calc(float data, float *rt, float *temp, float *R);
void max31865Write(byte adress, byte *data);
void max31865Read8(byte adress, byte *data);
void max31865Read16(byte adress, word *data);

#endif

The include section of max31865.cpp:

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

The include section of main.cpp:

#include <Arduino.h>
#include <SPI.h>
#include <TinyLoRa.h>
#include "max31865.h"

The “TinyLoRa” librairie is only used in the main.cpp code. And it required SPI library (Lora module of the board is also on SPI bus).

The platformio.ini file:

[env:feather32u4]
platform = atmelavr
board = feather32u4
framework = arduino

lib_deps =
# RECOMMENDED
# Accept new functionality in a backwards compatible manner and patches
adafruit/TinyLoRa @ ^1.4.0

monitor_speed=9600

The code was working good when everythings was in the main.cpp file. I face this build error since I splid the code into two cpp files.

Have you an idea where can be the error ?

Thank for your help !

Math

No, that’s just the final “aww linking failed :(” message, the actual error messages are above that, e.g. “multiple definition of…” / “undefined reference to…”. However even if you didn’t give us the actual error message, we can figure out the problem from your code…

Not indented correctly.

lib_deps =
   adafruit/TinyLoRa @ ^1.4.0

Oh no. No defining global variables within a header file if there are multiple users of the header file. You need to refactor it so that the header file only has

extern int max31865CS;  // CS Pin for MAX31865

and the max31865.cpp file has

int max31865CS = 0; 

This otherwise leads to “multiple definition of…” linker errors.

This has been discussed at e.g. A new PlatformIO user coding wrong, getting multiple definition & first defined here errors - #2 by maxgerhardt.

1 Like

Hello,

Thanks a lot for your answer.

it’ indented correctly in my .ini file. Just loose the indent when copy/past into the post.

Ok with the detailled explaination of the post linked, I understand my mistake. Thank a lot for the clear explaination !
I have edited my max31865.h and mac31865.cpp files and it build correctly now.

Also the globals variable below the comment /MAX31865 global variables/ of max61865.h file are only used by the functions of max31865.cpp file. So finaly, I can keep only their definition in the max31865.cpp file (and remove the declaring from max31865.h file) ?
What the best practice ? Is there a good reason to keep the declaring in the max31865.h file in this case ?

Thank

Math

Hi All
I have been chasing my tail all day with this error. I have fixed a few of the variables defintions thanks to all the suggestins above and looked at “A new PlatformIO user coding wrong, getting multiple definition & first defined here errors - #2 by maxgerhardt.”

Here is my error:

Linking .pio\build\portenta_h7_m7\firmware.elf
.pio\build\portenta_h7_m7\src\main.cpp.o:(.bss.Breakout+0x0): multiple definition of `Breakout'
.pio\build\portenta_h7_m7\src\BuckosLib_PH7_v001.cpp.o:(.bss.Breakout+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\portenta_h7_m7\firmware.elf] Error 1
======================================================= [FAILED] Took 6.23 seconds =======================================================

 *  The terminal process "C:\Users\bucko\.platformio\penv\Scripts\platformio.exe 'run'" terminated with exit code: 1. 
 *  Terminal will be reused by tasks, press any key to close it.

“multiple definition of `Breakout’” Breakout is from <Arduino_PortentaBreakout.h>

Here is my structure
Screenshot 2023-04-19 165250

here is my “BuckosLib_PH7_v001.h”

/*  BUCKOS HEADER FILE   BuckosLib_PH7_v001
    Header file for      BuckosLib_PH7_v001.cpp

    Vaersion:   001
    Date:       19 Apr 2023

*/

#pragma once

#ifndef BUCKOSLIB_PHY_V001_H
#define BUCKOSLIB_PHY_V001_H

#include <Arduino.h>
#include <Arduino_PortentaBreakout.h>
#include <LiquidCrystal.h>
#include <ArduinoBLE.h>

// initialize the library by associating any needed LCD interface pin
    // with the arduino pin number it is connected to
    extern int  rs,  en,  d4,  d5,  d6 ,  d7; 
    //const int 
    


// Declare Functions
    void flashF3 (int LedF3,int  FlashCount,int DelayTime);
    void PrintToLCD (String Message, String YesNo, int Line =1);
    void IntLCD();

    #endif

Here is my “BuckosLib_PH7_v001.cpp”

#include <Arduino.h>
#include <Arduino_PortentaBreakout.h>
#include <LiquidCrystal.h>
#include <ArduinoBLE.h>
#include "BuckosLib_PH7_v001.h"

int rs = GPIO_0, en = GPIO_1;
int d4 = GPIO_5, d5 = GPIO_4, d6 = GPIO_3, d7 = GPIO_2;

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// Functions
void flashF3 (int LedF3,int  FlashCount,int DelayTime) 
      {
        digitalWrite(LedF3, HIGH);
        lcd.setBacklight(HIGH);
        //lcd.set
        delay(DelayTime * 2);
        for(int i=1; i <= FlashCount; i++ ) {
          digitalWrite(LedF3, LOW); // On
          lcd.setBacklight(LOW);
          delay(DelayTime);
          digitalWrite(LedF3, HIGH); //off
          lcd.setBacklight(HIGH);
          delay(DelayTime);

        }
      }

void PrintToLCD (String Message, String YesNo, int Line)
  {
    if (YesNo == "Yes") {
      lcd.clear();
    }
    
    if (Line ==1) {
      lcd.setCursor(0,0);
    } else {
      lcd.setCursor(0,1);
    }
    lcd.print(Message);
  } 

void IntLCD() {

  Serial.begin(9600);
  //while (!Serial);   // Uncomment to wait for serial port to connect.

  // Set LED pin to output mode

  lcd.begin(16, 2);
  lcd.clear();
  lcd.display();

  }

Correct. The library screwed this one up since it does a definition in the header file whereas it should have done a declaration.

With

you cannot use this header file in two different .cpp pfiles.

I’ve attempted a fix in GitHub - maxgerhardt/Arduino_PortentaBreakout. So just change your platformio.ini’s lib_deps expression to use the https://github.com/maxgerhardt/Arduino_PortentaBreakout/archive/refs/heads/main.zip instead.

1 Like

Thanks but it seems to have opened a hole new load of duplications.

Building in release mode
Linking .pio\build\portenta_h7_m7\firmware.elf
.pio\build\portenta_h7_m7\lib7ae\libArduino_PortentaBreakout@src-0dc1dc0ab87f83b559d6be659b916447.a(RTC.cpp.o): In function `HWClock::getTime()':
RTC.cpp:(.text._ZN7HWClock7getTimeEv+0x0): multiple definition of `HWClock::getTime()'
.pio\build\portenta_h7_m7\libff4\libArduino_PortentaBreakout.a(RTC.cpp.o):RTC.cpp:(.text._ZN7HWClock7getTimeEv+0x0): first defined here    
.pio\build\portenta_h7_m7\lib7ae\libArduino_PortentaBreakout@src-0dc1dc0ab87f83b559d6be659b916447.a(RTC.cpp.o): In function `HWClock::setTime(Timestamp)':
RTC.cpp:(.text._ZN7HWClock7setTimeE9Timestamp+0x0): multiple definition of `HWClock::setTime(Timestamp)'
.pio\build\portenta_h7_m7\libff4\libArduino_PortentaBreakout.a(RTC.cpp.o):RTC.cpp:(.text._ZN7HWClock7setTimeE9Timestamp+0x0): first defined here
.pio\build\portenta_h7_m7\lib7ae\libArduino_PortentaBreakout@src-0dc1dc0ab87f83b559d6be659b916447.a(RTC.cpp.o): In function `HWClock::HWClock()':
RTC.cpp:(.text._ZN7HWClockC2Ev+0x0): multiple definition of `HWClock::HWClock()'
.pio\build\portenta_h7_m7\libff4\libArduino_PortentaBreakout.a(RTC.cpp.o):RTC.cpp:(.text._ZN7HWClockC2Ev+0x0): first defined here
.pio\build\portenta_h7_m7\lib7ae\libArduino_PortentaBreakout@src-0dc1dc0ab87f83b559d6be659b916447.a(RTC.cpp.o): In function `HWClock::HWClock()':
RTC.cpp:(.text._ZN7HWClockC2Ev+0x0): multiple definition of `HWClock::HWClock()'
.pio\build\portenta_h7_m7\libff4\libArduino_PortentaBreakout.a(RTC.cpp.o):RTC.cpp:(.text._ZN7HWClockC2Ev+0x0): first defined here
.pio\build\portenta_h7_m7\lib7ae\libArduino_PortentaBreakout@src-0dc1dc0ab87f83b559d6be659b916447.a(RTC.cpp.o):(.rodata._ZTV7HWClock+0x0): multiple definition of `vtable for HWClock'
.pio\build\portenta_h7_m7\libff4\libArduino_PortentaBreakout.a(RTC.cpp.o):(.rodata._ZTV7HWClock+0x0): first defined here
.pio\build\portenta_h7_m7\lib7ae\libArduino_PortentaBreakout@src-0dc1dc0ab87f83b559d6be659b916447.a(Timestamp.cpp.o): In function `Timestamp::minute()':
Timestamp.cpp:(.text._ZN9Timestamp6minuteEv+0x0): multiple definition of `Timestamp::minute()'
.pio\build\portenta_h7_m7\libff4\libArduino_PortentaBreakout.a(Timestamp.cpp.o):Timestamp.cpp:(.text._ZN9Timestamp6minuteEv+0x0): first defined here
.pio\build\portenta_h7_m7\lib7ae\libArduino_PortentaBreakout@src-0dc1dc0ab87f83b559d6be659b916447.a(Timestamp.cpp.o): In function `Timestamp::hour()':
Timestamp.cpp:(.text._ZN9Timestamp4hourEv+0x0): multiple definition of `Timestamp::hour()'
.pio\build\portenta_h7_m7\libff4\libArduino_PortentaBreakout.a(Timestamp.cpp.o):Timestamp.cpp:(.text._ZN9Timestamp4hourEv+0x0): first defined here
.pio\build\portenta_h7_m7\lib7ae\libArduino_PortentaBreakout@src-0dc1dc0ab87f83b559d6be659b916447.a(Timestamp.cpp.o): In function `Timestamp::day()':
Timestamp.cpp:(.text._ZN9Timestamp3dayEv+0x0): multiple definition of `Timestamp::day()'
.pio\build\portenta_h7_m7\libff4\libArduino_PortentaBreakout.a(Timestamp.cpp.o):Timestamp.cpp:(.text._ZN9Timestamp3dayEv+0x0): first defined here
.pio\build\portenta_h7_m7\lib7ae\libArduino_PortentaBreakout@src-0dc1dc0ab87f83b559d6be659b916447.a(Timestamp.cpp.o): In function `Timestamp::month()':
Timestamp.cpp:(.text._ZN9Timestamp5monthEv+0x0): multiple definition of `Timestamp::month()'
.pio\build\portenta_h7_m7\libff4\libArduino_PortentaBreakout.a(Timestamp.cpp.o):Timestamp.cpp:(.text._ZN9Timestamp5monthEv+0x0): first defined here
.pio\build\portenta_h7_m7\lib7ae\libArduino_PortentaBreakout@src-0dc1dc0ab87f83b559d6be659b916447.a(Timestamp.cpp.o): In function `Timestamp::year()':
Timestamp.cpp:(.text._ZN9Timestamp4yearEv+0x0): multiple definition of `Timestamp::year()'
.pio\build\portenta_h7_m7\libff4\libArduino_PortentaBreakout.a(Timestamp.cpp.o):Timestamp.cpp:(.text._ZN9Timestamp4yearEv+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\portenta_h7_m7\firmware.elf] Error 1

I assum i have editted the plantformio correctly.ini

[env:portenta_h7_m7]
platform = ststm32
board = portenta_h7_m7
framework = arduino
lib_deps =
arduino-libraries/ArduinoBLE@^1.3.4
arduino-libraries/Arduino_PortentaBreakout @ ^1.0.1
fmalpartida/LiquidCrystal @ ^1.5.0
https://github.com/maxgerhardt/Arduino_PortentaBreakout/archive/refs/heads/main.zip
include_dir = C:\Users\bucko\OneDrive\aElectronics\Projects\BuckosLearning-PH7\include

Sorry, it good now.

Suffix successfully added to file
====================================================== [SUCCESS] Took 72.12 seconds ======================================================
 *  Terminal will be reused by tasks, press any key to close it. 

I forgot to save platformio.ini it was conflicting with the old PortentaBreakout.h

Cheers

Yeah you’ll have to delete the old arduino-libraries/Arduino_PortentaBreakout @ ^1.0.1 and delete the .pio fodler for a clean build.

So it was just the extern keyword that fixed it.

extern BreakoutCarrierClass Breakout;

No. One part is declaring the object to be extern in the header. That avoids “multiple references”. But, then one .cpp file has to be created in which the object is actually created / defined. Otherwise the object won’t exist at all and it’s an undefined reference. See both latest commits at

Great to hear it’s working now. I’ll file a pull request.

Ok, im looking at the .cpp now. i can see that you mean. Cheers

PR open at

so when it’s merged and a new version is released you can revert back to the latest official version.

1 Like