Asil
Asil

Reputation: 874

C++ undefined reference in Makefile

I created my Makefile for a simple program but it returns undefined reference for class functions constantly:

g++ -c src/main.cpp -o lib/main.o
g++ -c src/functions.cpp -o lib/functions.o
g++ -c src/Circular.cpp -o lib/Circular.o
g++ lib/main.o -o bin/app.exe
c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: lib/main.o:main.cpp:(.text+0x20): undefined reference to `Circular::Circular()'
collect2.exe: error: ld returned 1 exit status
make.exe: *** [app.exe] Error 1

Here is my Makefile:

app.exe: lib/main.o lib/Circular.o lib/functions.o
g++ lib/main.o -o bin/app.exe

lib/functions.o: src/functions.cpp
g++ -c src/functions.cpp -o lib/functions.o

lib/Circular.o: src/Circular.cpp
g++ -c src/Circular.cpp -o lib/Circular.o

lib/main.o: src/main.cpp
g++ -c src/main.cpp -o lib/main.o

Here is a short snippet of main.cpp:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <string>


#include "../include/Circular.h"
#include "../include/functions.h"

using namespace std;

int main(int argc, const char * argv[]) {

     Circular item;
     return 0;
 }

Circular.h:

#include "node.h"


class Circular
{
    public:
        Circular();
        
        node *start;
        node *last;
        int counter;
}

Circular.cpp:

#include "../include/Circular.h"
#include <iostream>

using namespace std;


Circular::Circular()
{
    start = NULL;
    last = NULL;            
}

and node.h:

struct node
{
    int data;
    struct node *next;
    struct node *prev;
};

I know the problem is about linker and with Makefile but even though I tried different possible solutions, somehow it doesn't work. Therefore, maybe someone can see the mistake I am making. Thanks!

Upvotes: 0

Views: 1990

Answers (2)

Hamed
Hamed

Reputation: 26

I managed to create a Makefile from this source .

The Makefile looks like this:

CXX = g++
CXXFLAGS = -std=c++17 -Wall
LXXFLAGS = -std=c++17
OBJECTS = main.o Circular.o functions.o
TARGET = main

$(TARGET): $(OBJECTS)
    $(CXX) $(LXXFLAG) $(OBJECTS) -o $(TARGET)
main.o: main.cpp Circular.cpp Circular.h functions.cpp functions.h
    $(CXX) $(CXXFLAGS) -c main.cpp
Circular.o: Circular.cpp 
    $(CXX) $(CXXFLAGS) -c Circular.cpp
functions.o: functions.cpp 
    $(CXX) $(CXXFLAGS) -c functions.cpp
clean:
    rm -f $(TARGET) $(OBJECTS)

And also added cout to you Circular constructor to check the execution as below:

#include "Circular.h"
#include <iostream>

using namespace std;


Circular::Circular()
{
    start = NULL;
    last = NULL;   
    cout << "Yes!" << endl;     
}

Here's the result: Output
Don't forget to put a semicolon for your Circular class in your Circular.h.
NOTE: If you aren't able to use make in cmd,use choco install make.

Upvotes: 1

tadman
tadman

Reputation: 211540

The Makefile should be structured to build the dependencies, then the final assembly into a .exe. Each path should be specified exactly as it is, not approximated:

app.exe: lib/main.o lib/Circular.o lib/functions.o 
  g++ lib/main.o lib/Circular.o lib/functions.o -o app.exe

lib/main.o: src/main.cpp
  g++ -c src/main.cpp -o lib/main.o

lib/functions.o: src/functions.cpp
  g++ -c src/functions.cpp -o lib/functions.o

lib/Circular.o: src/Circular.cpp
  g++ -c src/Circular.cpp -o lib/Circular.o

The key here is be consistent and that includes things like the order of things specified in this file. Whatever order you pick, stick to it. This makes tracking down problems way easier.

If this project gets more complex you probably want to pivot to using a dependency tracking Makefile template instead of this homebrew one. Note how in those you don't need to specify a rule for each file, but instead a rule for each type of file, as in .cpp -> .o, and the rest happens automatically.

Upvotes: 1

Related Questions