0
votes

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.

1
My make is rusty so I can't be of much actual help, but one approach you could take is to not wildcard everything up front. Be more explicit first and generalize if needed. - sweenish
So that worked but now I'm just curious why my current makefile doesn't work. Does un-generalizing count as a solution? - TheDeadCrafter

1 Answers

1
votes

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.