Link-time undefined reference to a class object (revisiting...)

This issue eludes me … once again. Undefined reference to a class object.

It is similar to one we looked at earlier, but the answer does not seem to be similar to the prior solution… https://cplusplus.com/forum/general/284834/

I apologize for my denseness on this matter.

I have created a class to manage an ADC converter chip. That class is declared in ADS1216.h

ADS1216.h
1
2
3
4
5
6
7
8
9
10
class ADS1216_PD
{
public:
    // Constructors
    ADS1216_PD(int cs, int drdy);
    ADS1216_PD(SPIClass *s, int cs, int drdy);

   ...
   void setMux(ADS1216_MUX muxSetting);
 };


The functions are defined in ADS1216.cpp:

ADS1216.cpp
1
2
3
4
5
6
7
8
/* Constructors */
ADS1216_PD::ADS1216_PD(int cs, int drdy) : _spi{&SPI}, csPin{cs}, drdyPin{drdy} {}
ADS1216_PD::ADS1216_PD(SPIClass *s, int cs, int drdy) : _spi{s}, csPin{cs}, drdyPin{drdy} {}
...
void ADS1216_PD::setMux(ADS1216_MUX muxSetting)
{
    writeRegister(ADS1216_MUX_REG, muxSetting);
}



In main(), which lives in main.cpp, I call initialize(), which lives in initialize.cpp and initialize() creates the myADC object.

initialize.cpp
1
2
3
4
5
6
     #include "SPI.h"

void initialize(void)
{
    ADS1216_PD myADC = ADS1216_PD(PIN_ADC_CS_BAR, PIN_ADC_DRDY_BAR);
}


(Also in initialize I read and write some of the ADC registers, using other class functions not shown here, to confirm it is working)
Now back in main(), after initialize completes, I go to call one of the myADC object functions.

main.cpp
1
2
3
4
5
6
7
8
9
10
#include <ADS1216.h>
extern ADS1216_PD myADC;

void setup()
{
  
  initialize();

  myADC.setMux(ADS1216_MUX_AIN3_AINCOM);
}


(Of course lots of other code is not shown here…) But it compiles fine and at link time throws this error:

1
2
3
4
c:/users/peted/.platformio/packages/toolchain-xtensa-esp32s3/bin/../lib/gcc/xtensa-esp32s3-elf/8.4.0/../../../../xtensa-esp32s3-elf/bin/ld.exe: .pio/build/esp32-s3-devkitc-1/src/main.cpp.o:(.literal._Z5setupv+0x0): 
undefined reference to `myADC'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\esp32-s3-devkitc-1\firmware.elf] Error 1 


Commenting out the setMux call in main() and it compiles and runs fine.

What is odd is that this structure seems identical to another program I have linking just fine which used the ADS1220_WE library defining a similar object the same way. What am I missing here? (I have tried extern statements in several places to no avail). THANK YOU.


Last edited on
The fact that you call a function initialize() and you show a snippet of a file named initialize.cpp suggests that initialize.cpp contains a function named initialize. Also, the indentation of that code snippet suggests the same.

If the creation of myADC is local to the initialize() function, then it is out of scope in main.cpp and cannot be used as a global.

More details on initialize.cpp (and possibly main.cpp) would be helpful.
myADC has to be defined at global scope in the compilation unit in which it is defined.
Dou4g,
You are of course correct. In my zeal to create as brief a summary as possible, I left out the void initialize line... I have since corrected that above.

Seeplus,
Yes, exactly. But how to I get myADC into global scope? For example, in initialize I also start some oneWire stuff and have no issue with accessing that globally. Please be patient with me here. I am really trying to grasp and internalize this.

Thanks,
Pete
I have since corrected that above.


Ah. That explains it.

1
2
3
4
5
6
    #include "SPI.h"

void initialize(void)
{
    ADS1216_PD myADC = ADS1216_PD(PIN_ADC_CS_BAR, PIN_ADC_DRDY_BAR);
}


myAdc is local scope and only exists within initialize(). You need something like:

1
2
3
4
5
6
7
    #include "SPI.h"

ADS1216_PD myADC = ADS1216_PD(PIN_ADC_CS_BAR, PIN_ADC_DRDY_BAR);

void initialize(void)
{
}


where myADC is now at global scope so extern in the other file can now find it.
Last edited on
If you really want it global and you really don't want to create it until you call initialize (and I would carefully reconsider both of these givens--particularly the first), you could make myADC a pointer.

1
2
3
4
5
6
ADS1216_PD* myADC = null;

void initialize(void)
{
    myADC = new ADS1216_PD(PIN_ADC_CS_BAR, PIN_ADC_DRDY_BAR);
}


Of course, the call to setMutex would then be
 
    myADC->setMux(ADS1216_MUX_AIN3_AINCOM);


Edit: O yeah, a smart pointer rather than a raw pointer would probably be better, but I didn't want to get into that.
Last edited on
and then a delete at the end of the program...
You could make myADC a pointer

Or a function-local static variable (Meyers' Singleton)

1
2
3
4
5
ADS1216_PD& get_myADC(void)
{
   static ADS1216_PD myADC(PIN_ADC_CS_BAR, PIN_ADC_DRDY_BAR);
   return myADC;
}
Last edited on
Registered users can post here. Sign in or register to post.