Undefined reference error on linking - Makefile and includes configured - c++

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 $#.o
%.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.

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 $#.o
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.

Related

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!
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.
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.

C++ How to Reference Other Classes?

I'm new to C++, and I'm having some trouble setting up a simple class reference.
Class: Test.hh
#ifndef _TEST_HH_
#define _TEST_HH_
class Test {
public:
Test (double x);
};
#endif
Class Test.cc
#include "Test.hh"
#include <stdio.h>
Test::Test(double x) {
printf("%f",x);
}
Now I want to access this class from another class:
Class: DriverClass.hh
#ifndef _DRIVERCLASS_HH_
#define _DRIVERCLASS_HH_
#include "Test.hh"
class DriverClass {
public:
DriverClass(double y);
Test *t;
}
#endif
Class DriverClass.cc
#include "DriverClass.hh"
DriverClass::DriverClass(double y) {
t = new Test(y);
}
However, I get an error: "undefined reference to 'Test::Test(double)?
Does anyone know what might be wrong? Please assume that DriverClass is being called directly from a main method (not shown).
There is still an error in your post - a missing ; after the DriverClass
declaration. The rest is correct.
You should compile and link all the sources. The following is a sample Makefile and a
sample test code.
Makefile
all: t
t: t.cc DriverClass.cc Test.cc
g++ -Wall -g -o $# $^
clean:
rm -f *.o t
However, note that it's generally recommended to compile the sources into objects separately in order to compile only the sources changed after the last compilation. For example:
CFLAGS=-Wall -g
all: t
t: t.o DriverClass.o Test.o
g++ -o $# $^
t.o: t.cc DriverClass.o Test.o
g++ $(CFLAGS) -c $< -o $#
DriverClass.o: DriverClass.cc
g++ $(CFLAGS) -c $< -o $#
Test.o: Test.cc
g++ $(CFLAGS) -c $^ -o $#
clean:
rm -f *.o t
I've used the GNU compiler. For the meaning of $# and $^ variables refer to the official documentation.
t.cc
#include "Test.hh"
#include "DriverClass.hh"
int main(int argc, char const* argv[])
{
DriverClass d(10.4);
return 0;
}
Testing
$ make
g++ -Wall -g -o t t.cc DriverClass.cc Test.cc
$ ./t
10.400000
P.S.: don't forget to delete the allocated object.

Error in C++ undefined reference to main

I keep getting an error saying...
(.text+0x20): undefined reference to `main'
collect2: ld returned 1 exit status
make: *** [FuelGauge] Error 1
My project is below as well as my code and makefile. Also if you see any other coding errors feel free to point them out =]
Simulator Class
#include <iostream>
#include <iomanip>
#include "FuelGauge.h"
#include "Odometer.h"
using namespace std;
int main(){
FuelGauge fuel(0); return 0;
}
FuelGauge class
#include "FuelGauge.h"
#include <iostream>
#include <cstdlib>
using namespace std;
void FuelGauge::incrementGas(int gas){
if(currentFuel < maxGallon) {
currentFuel++;
}
}
int FuelGauge::getGas(){
return currentFuel;
}
FuelGauge.h
class FuelGauge {
private:
int currentFuel;
int maxGallon;
public:
void incrementGas(int);
int getGas();
};
Odometer class
#include "FuelGauge.h"
#include "Odometer.h"
#include <iostream>
#include <cstdlib>
using namespace std;
private: int currentMileage;
Odometer::Odometer(){
mileage = 0;
Fuelgauge g;
}
int Odometer::getMileage(){
return mileage;
}
void Odometer::incrementMileage(){
if(mileage <= 999999){
mileage++;
}
else{
mileage = 0;
}
void Odometer::decreaseMileage(){
if(g.currentFuel > 24){
g.currentFuel--;
}
}
}
Odometer.h
class Odometer{
private:
int mileage;
int gallons;
}
Makefile
FLAGS = -Wall
CC = g++
SYMBOLS = -g
all: FuelGauge Odometer CarSimulatorDemo
FuelGauge: FuelGauge.cpp FuelGauge.h
$(CC) $(FLAGS) $(SYMBOLS) -o $# FuelGauge.cpp
Odometer: Odometer.cpp Odometer.h
$(CC) $(FLAGS) $(SYMBOLS) -o $# Odometer.cpp
CarSimulatorDemo: CarSimulatorDemo.cpp
$(CC) $(FLAGS) $(SYMBOLS) -o $# CarSimulatorDemocpp
clean:
rm FuelGauge Odometer CarSimulatorDemo
The problem you're getting is probably not because of your c++ code but rather your Makefile. You want to compile each of your cpp files rather to a object file than the separate application and then link them together into single app. To compile cpp to the .o file use -c option.
To sum up your Makefile should be as follows:
FLAGS = -Wall
CC = g++
SYMBOLS = -g
all: app
app: FuelGauge.o Odometer.o CarSimulatorDemo.o
$(CC) $(FLAGS) $(SYMBOLS) *.o -o app
FuelGauge.o: FuelGauge.cpp FuelGauge.h
$(CC) $(FLAGS) $(SYMBOLS) -c -o FuelGauge.o FuelGauge.cpp
Odometer.o: Odometer.cpp Odometer.h
$(CC) $(FLAGS) $(SYMBOLS) -c -o Odometer.o Odometer.cpp
CarSimulatorDemo.o: CarSimulatorDemo.cpp
$(CC) $(FLAGS) $(SYMBOLS) -c -o CarSimulatorDemo.o CarSimulatorDemo.cpp
clean:
rm FuelGauge.o Odometer.o CarSimulatorDemo.o app
Remember to change spaces in your Makefile to tabulators!
PS. #ifndef should always imply using #endif and in header files always use them!
Your Odometer.h does not end in #endif. Since it has already been included through FuelGauge.h, ODOMETER_H is defined and everything after #ifndef is not compiled (preprocessor expands it to whitespace). Including the function main.

Undefined reference in main Makefile

I did a sample project in linux but i am getting error while running main Makefile
Project Info:
project/database folder having files database.h , database.cpp , bulid-database ,Makefile
database.h
/*data base file*/
#include<iostream>
using namespace std;
class mydatabase
{
public:
mydatabase(int a , int b);
int sum(){return m_a +m_b;}
int diff(){return m_a -m_b;}
int mul(){return m_a *m_b;}
float div(){return m_a /m_b;}
int reminder(){return m_a %m_b;}
private:
int m_a , m_b;
};
database.cpp
#include "database.h"
mydatabase::mydatabase(int a ,int b):m_a(a) , m_b(b)
{
}
bulid-database
make
if [ -f libdatabase.a ];
then
echo "Database-Library Build Success"
cp libdatabase.a ../LIBs/
else
echo "databse-Library Build Failure"
fi
Makefile
HEADERFILES = $(wildcard *.h)
CPPFILES = $(wildcard *.cpp)
OBJFILES = $(patsubst %.cpp,%.o ,$(wildcard *.cpp))
$(OBJFILES): %.o : %.cpp $(HEADERFILES)
g++ -c -o $# $<
ar ruv libdatabase.a $#
ranlib libdatabase.a
project/Main folder having files main.cpp , Makefile
main.cpp
#include "database.h"
#include <iostream>
int main()
{
mydatabase *obj = new mydatabase(10 ,5);
std::cout<<"sum is"<<obj->sum()<<endl;
std::cout<<"diff is"<<obj->diff()<<endl;
std::cout<<"mul is"<<obj->mul()<<endl;
std::cout<<"div is"<<obj->div()<<endl;
std::cout<<"reminder is"<<obj->reminder()<<endl;
getchar();
return 0;
}
Makefile
CC = g++
INCPATH = -I. \
-I.. \
-I../database
LIBPATH = -L../LIBs
LDFLAGS = ${LIBPATH}/libdatabase.a
CFLAGS = ${INCPATH}
testdate:main.o
$(CC) $(CFLAGS) -o testdate main.o $(LDFLAGS)
main.o:main.cpp
$(CC) $(CFLAGS) -c -o main.o main.cpp
ISSUE: database make file is working fine but main Makefile i am having some issue like
Error: main.o: In function main':
main.cpp:(.text+0x92): undefined reference tomydatabase::mydatabase(int, int)'
collect2: ld returned 1 exit status
This line is wrong:
$(CC) $(CFLAGS) -o testdate $(LDFLAGS) main.o
because the library should be specificed AFTER the object main.o on the line. This is due to the way the linker handles the objects. Look at this example:
gcc -o test someobject.o library.a
The linker will:
look up all undefined references of someobject.o and store them
then it opens library.a and resolves the undefined references via library.a
then it closes library.a
If the object and the library are in the other way around, then the linker opens library.a, sees no undefined references in its table and closes it. Then it tries and compiles someobject.o and the undefined references are never satisfied
EDIT:
This is a well-known caveat of GCC, a more detailed stack-overflow explanation can be seen here, and options --start-group and --end-group can help resolve cases where A depends on B, and B depends on A.
It's your Makefile. You want:
libdatabase.a
or
-ldatabase
at the end of your main compile line

Can't compile the project after splitting the source files to cpp and h, getting "undefined refernce to..."

I had a project, where I had only .cpp files. It worked well, but then I realized, that it's not a good practice, so I decided to split it to .cpp and .h files. Nevetheless now I'm not able to compile the project. Could anybody please look at the source and tell me, where the problem is?
Bot.h
#ifndef BOT_H
#define BOT_H
#include <vector>
#include <string>
#include <cstdlib>
using namespace std;
/**
* Class that represents casual Bot - the parent of other bots
*/
class Bot {
public:
Bot();
virtual ~Bot();
bool initialized;
string getRandomMessage();
string getName();
protected:
vector<string> messages;
string name;
};
#endif /* BOT_H */
Bot.cpp
#include <vector>
#include <string>
#include <cstdlib>
#include "Bot.h"
using namespace std;
string Bot::getRandomMessage() {
int r = static_cast<double> (std::rand()) / RAND_MAX * this->messages.size();
return messages[r];
}
Bot::Bot(){
}
Bot::~Bot(){
}
string Bot::getName() {
return this->name;
}
Example of the class that inherits from the Bot class:
GrumpyBot.h
#ifndef GRUMPYBOT_H
#define GRUMPYBOT_H
#include "Bot.h"
class GrumpyBot : public Bot{
public:
GrumpyBot();
GrumpyBot(const GrumpyBot& orig);
virtual ~GrumpyBot();
};
#endif /* GRUMPYBOT_H */
GrumpyBot.cpp
#include "GrumpyBot.h"
GrumpyBot::GrumpyBot() {
initialized = true;
this->name = "GrumpyBot";
messages.push_back("I hate dogs.");
messages.push_back("I hate cats.");
messages.push_back("I hate goats.");
messages.push_back("I hate humans.");
messages.push_back("I hate you.");
messages.push_back("I hate school.");
messages.push_back("I hate love.");
}
Till now it is ok, but problems appear in the Server.cpp class, where I try to create new instances of those classes and call their functions.
I include there both #include "Bot.h" & #include "GrumpyBot.h" and the compiler keeps getting me messages like /home/ubuntu/NetBeansProjects/SemestralniPraceChat/./Server.cpp:335: undefined reference to 'GrumpyBot::GrumpyBot()'
My makefile looks like this:
#macros
Remove=rm -rf
Doxygen=Doxyfile
RUN=./dvoram64
FLAGS=-Wall -pedantic -Wno-long-long -O0 -ggdb -lncurses -pthread -g
OBJECTS=main.o Bot.o Server.o Client.o
#generates final binary and documentation
all: $(Doxygen)
make compile
#build into final binary
compile: $(RUN)
#run program
run: $(RUN)
$(RUN)
clean:
$(Remove) dvoram64
$(Remove) $(OBJECTS)
#generate documentation in '<login>/doc' folder
doc: $(Doxygen) /*
( cd ./ | doxygen $(Doxygen))
#rules how to compile into the executalble file
$(RUN): $(OBJECTS)
Bot.o: ./Bot.cpp ./Bot.h
g++ $(FLAGS) -c ./Bot.cpp
DummyBot.o: ./DummyBot.cpp ./DummyBot.h ./Bot.h
g++ $(FLAGS) -c ./DummyBot.cpp
GrumpyBot.o: ./GrumpyBot.cpp ./GrumpyBot.h ./Bot.h
g++ $(FLAGS) -c ./GrumpyBot.cpp
JokerBot.o: ./JokerBot.cpp ./JokerBot.h ./Bot.h
g++ $(FLAGS) -c ./JokerBot.cpp
WeatherBot.o: ./WeatherBot.cpp ./WeatherBot.h ./Bot.h
g++ $(FLAGS) -c ./WeatherBot.cpp
Client.o: ./Client.cpp
g++ $(FLAGS) -c ./Client.cpp
main.o: ./main.cpp ./Server.cpp ./Bot.h ./JokerBot.h ./WeatherBot.h ./GrumpyBot.h ./DummyBot.h ./Client.cpp
g++ ./main.cpp $(FLAGS) -o ./dvoram64
Server.o: ./Server.cpp ./Bot.h ./JokerBot.h ./WeatherBot.h ./GrumpyBot.h ./DummyBot.h
g++ $(FLAGS) -c ./Server.cpp
undefined reference is a linker error, you are not passing the objects for the linking process.
In the makefile, replace main.o: lines with
main.o: main.cpp
g++ $(FLAGS) -c main.cpp
remove -lncurses from $(FLAGS) and add:
link: <all the o files>
g++ <all the o files> -lncurses -pthread -o dvoram64
then calling:
make link
will create the correctly linked executable.
Edit:
If you define the $(OBJECTS) variable, the link should be:
link: $(OBJECTS)
g++ $(OBJECTS) -lncurses -pthread -o dvoram64