TheDeadCrafter
TheDeadCrafter

Reputation: 25

Undefined reference error on linking - Makefile and includes configured

I have two sources file, main.cpp & functions.cpp, and a header filed main.h, and finally a Makefile:

main.cpp

#include "main.h"

int main()
{
    Application game;

    game.update();
    game.draw();
}

functions.cpp

#include "main.h"

Application::Application()
{
    window = SDL_CreateWindow("SDL GAME", 
            SDL_WINDOWPOS_CENTERED, 
            SDL_WINDOWPOS_CENTERED, 
            SCREEN_WIDTH, 
            SCREEN_HEIGHT, 0);

    if(!window)
    {
        printf("Error: %s\n", SDL_GetError());
    }

    windowSurface = SDL_GetWindowSurface(window);

    if(!windowSurface)
    {
        printf("Error: %s\n", SDL_GetError());
    }
}

Application::~Application()
{
    SDL_FreeSurface(windowSurface);
    SDL_DestroyWindow(window);
}

void Application::update()
{
    bool quit = false;
    while(!quit)
    {
        SDL_Event e;
        while(SDL_PollEvent(&e) > 0) //Event queue
        {
            switch(e.type)
            { //Add events here
                case SDL_QUIT:
                    quit = true;
                    break;
            }
        }
        //DRAW
        Application::draw();
        //STOP DRAW
        SDL_UpdateWindowSurface(window);
    }
}

void Application::draw()
{
    SDL_UpdateWindowSurface(window);
}

main.h

#pragma once

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <stdio.h>
#include <string>

const int SCREEN_WIDTH = 500;
const int SCREEN_HEIGHT = 500;




class Application
{
    public:
        Application();
        ~Application();

        void update();
        void draw();

    private:
        SDL_Window *window = NULL;
        SDL_Surface *windowSurface = NULL;
        SDL_Event event;
};

Makefile

.PHONY = all clean

CC = g++

SRCS:= $(wildcard src/*.cpp) # Succesfully grabs all source files
BINS := $(SRCS:%.cpp=%)

LINKERFLAG = -lSDL2 -Isrc


all: ${BINS}

%: %.cpp
    ${CC} ${LINKERFLAG} $< -o [email protected]

%.o: %.cpp
    ${CC} -o $<.o

clean:
    rm -rvf *.o ${BINS}

The error

g++ -lSDL2 -Isrc src/main.cpp -o src/main.o /usr/lib64/gcc/x86_64-suse-linux/10/../../../../x86_64-suse-linux/bin/ld: /tmp/ccp2ZmwE.o: in function main': main.cpp:(.text+0x11): undefined reference to Application::Application()' /usr/lib64/gcc/x86_64-suse-linux/10/../../../../x86_64-suse-linux/bin/ld: main.cpp:(.text+0x1d): undefined reference to Application::update()' /usr/lib64/gcc/x86_64-suse-linux/10/../../../../x86_64-suse-linux/bin/ld: main.cpp:(.text+0x29): undefined reference to Application::draw()' /usr/lib64/gcc/x86_64-suse-linux/10/../../../../x86_64-suse-linux/bin/ld: main.cpp:(.text+0x35): undefined reference to Application::~Application()' /usr/lib64/gcc/x86_64-suse-linux/10/../../../../x86_64-suse-linux/bin/ld: main.cpp:(.text+0x4b): undefined reference to Application::~Application()'


What I have tried: using -c to compile all then running again without to link, no success. I'm coming to c++ and Make from a python background so it is fairly new to me. What I think is happening is it's trying to link main.cpp before compiling functions.cpp, but I don't know how to go about that figuring that out.

Upvotes: 0

Views: 1071

Answers (1)

Beta
Beta

Reputation: 99084

Suppose you have a self-contained source file, foo.cpp.

You could build the executable foo in one step:

g++ foo.cpp -o foo

Or you could build the object file, then build the executable from that:

g++ -c foo.cpp -o foo.o
g++ foo.o -o foo

Now suppose you have two source files, main.cpp and functions.cpp. The code in main.cpp calls a function defined in functions.cpp. If you carelessly try to build the executable from only one file:

g++ main.cpp -o app

the compiler will complain that your code calls a function that has no definition. This is what your makefile does, when it tries to build main:

%: %.cpp
    ${CC} ${LINKERFLAG} $< -o [email protected]

The usual way in a case like this is to build the object files first, then link them:

g++ -c main.cpp -o main.o
g++ -c functions.cpp -o functions.o
g++ main.o functions.o -o name_of_executable

You can do that with a makefile that looks like this:

$(EXEC_NAME): main.o functions.o
    ${CC} ${LINKERFLAG} $^ -o $@

%.o: %.cpp
    ${CC} -c $< -o $@

There are some more refinements to make (and you don't even have to write that second rule, Make already knows it), but that should be enough to get you started.

Upvotes: 1

Related Questions