Undefined reference to

Hi, I’m programming an ESP32 under the Arduino framework.

I have a simple class structure formed by the main class and another class named ConfigWebServer:
image

I have created an instance to said class by using in main:

ConfigWebServer ws(server);

When I compile I get the following error:

.pio\build\nodemcu-32s\src\ConfigWebServer.cpp.o: .literal._ZN15ConfigWebServer9processorERK6String+0x10): undefined reference to `ConfigWebServer::ledState’
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\nodemcu-32s\firmware.elf] Error 1

This is the content of ConfigWebServer.h

#include "arduino.h"

#ifndef AsyncWebServer

#include <ESPAsyncWebServer.h>

#endif

#include <SPIFFS.h>

class ConfigWebServer{

public:

    ConfigWebServer(AsyncWebServer server);

    

private:

    static String processor(const String& var);

    static String ledState;

};

And ConfigWebServer.cpp:
#include “ConfigWebServer.h”

ConfigWebServer::ConfigWebServer(AsyncWebServer server)

{

    if(!SPIFFS.begin(true)){

    Serial.println("An Error has occurred while mounting SPIFFS");

  }

    // Route for root / web page

    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)

              { request->send(SPIFFS, "/index.html", String(), false, processor); });

    // Route to load style.css file

    server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request)

              { request->send(SPIFFS, "/style.css", "text/css"); });

    // Route to set GPIO to HIGH

    server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request)

              {

                  request->send(SPIFFS, "/index.html", String(), false, processor);

              });

    // Route to set GPIO to LOW

    server.on("/off", HTTP_GET, [](AsyncWebServerRequest *request)

              {

                  request->send(SPIFFS, "/index.html", String(), false, processor);

              });

    server.on("/test.js", HTTP_GET, [](AsyncWebServerRequest *request){

        request->send(SPIFFS, "/test.js", "text/javascript");

        });

    server.begin();

}

String ConfigWebServer::processor(const String &var)

{

    Serial.print("the var is: ");

    Serial.println(var);

    if (var == "TACSSUP")

    {

        ledState = "36";

        Serial.print(ledState);

        return ledState;

    }

    else if (var == "TACSINF")

    {

        ledState = "31";

        Serial.print(ledState);

        return ledState;

    }

    else if (var == "TSETACS")

    {

        ledState = "40";

        Serial.print(ledState);

        return ledState;

    }

    else if (var == "ACSMODE")

    {

        ledState = "AUTO";

        Serial.print(ledState);

        return ledState;

    }

    return String();

}

As you can see ledState is declared on the .h file and anywhere else.

Where in the ConfigWebServer.cpp file is the needed

String ConfigWebServer::ledState;

definition of the declared static variable? (see also e.g. this C++ tutorial).

1 Like

Because I pass the method processor

as an Argument on the constructor:

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
       { request->send(SPIFFS, "/index.html", String(), false, processor); });

And so if the method is static then the variable needs to be static.

Maybe I could obtain the instance of the object ConfigWebServer.cpp and use it to pass the method processor (I don’t know how to do it yet). Would this be a better option?

However, I still don’t understand why the compiler doesn’t like my static variable

If you declare a class-static variable, then you must define it as above. Have you tried that?

1 Like

This means that if I want to access the variable ledState from inside the class I still have to reference it like ConfigWebServer::ledState ?

So in the end the method would look like this:

String ConfigWebServer::processor(const String &var)

{

    Serial.print("the var is: ");

    Serial.println(var);

    if (var == "TACSSUP")

    {

        ConfigWebServer::ledState = "36";

        Serial.print(ConfigWebServer::ledState);

        return ConfigWebServer::ledState;

    }

    else if (var == "TACSINF")

    {

        ConfigWebServer::ledState = "31";

        Serial.print(ConfigWebServer::ledState);

        return ConfigWebServer::ledState;

    }

    else if (var == "TSETACS")

    {

        ConfigWebServer::ledState = "40";

        Serial.print(ConfigWebServer::ledState);

        return ConfigWebServer::ledState;

    }

    else if (var == "ACSMODE")

    {

        ConfigWebServer::ledState = "AUTO";

        Serial.print(ConfigWebServer::ledState);

        return ConfigWebServer::ledState;

    }

    return String();

}

The variable declaration was already correct:

class ConfigWebServer{

public:

    ConfigWebServer(AsyncWebServer server);

   
private:

    static String processor(const String& var);

    static String ledState;

};

I still get the same error. So I supose I’m not undertanding you correctly:

.pio\build\nodemcu-32s\src\ConfigWebServer.cpp.o:(.literal._ZN15ConfigWebServer9processorERK6String+0x10): undefined reference to `ConfigWebServer::ledState’
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\nodemcu-32s\firmware.elf] Error 1

No, you can still reference the variable as ConfigWebServer::ledState it is just that you have to define the variable.

ConfigWebServer.cpp

#include "ConfigWebServer.h" 

//actually define class-static variable
String ConfigWebServer::ledState;

//all of the rest of the code and functions
1 Like

It compiles :slight_smile:
But as I understand it if I put it outside the class declaration:

#include "arduino.h"

#ifndef AsyncWebServer

#include <ESPAsyncWebServer.h>

#endif

#include <SPIFFS.h>

static String ledState;

class ConfigWebServer{

    

public:

    ConfigWebServer(AsyncWebServer server);

    

private:

    static String processor(const String& var);

   
};

Then it is not a class variable right?. I can access the varaible without pointing to ConfigWebServer::

You shouldn’t put a variable definition like that in a header file, otherwise it will easily lead to multiple definition errors if multiple .c/.cpp files include that header. Global variable definitions and declarations would use extern String ledState; in the header and String ledState in the cpp file.

If you want a global variable that is however only global to the file and not accross files, then yes, you can do

static String ledState;

in the .cpp file and then reference the variable with just ledState.

static within a class context has a different meaning, that of "this variable exists not per-object-instanciation of that class, but is a singular variable of the class that can be be accessed via the class name (in this case, ConfigWebServer::ledState)

1 Like

That I understand (in my young ages I started coding with C#) what I didn’t know is that a static variable has to be declared in the .cpp file.

Thank you very much :slight_smile: