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.
Related
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.
I need to access a C++ function from C but I get some error like :-
/tmp/ccUqcSZT.o: In function `main':
main.c:(.text+0x5): undefined reference to `load_alert_to_db'
collect2: error: ld returned 1 exit status
My main.c code is:-
#include <stdio.h>
extern void load_alert_to_db(void);
int main(void){
/* Create empty queue */
load_alert_to_db();
return 0;
}
C++ code implementation db_manager.cpp is:-
#include <sstream>
#include <iostream>
#include <sstream>
#include <string>
#include <ctime>
#include <cstdlib>
#include <algorithm>
#include <time.h>
#include <cstring>
#include <fstream>
//using namespace oracle::occi;
#include <iostream>
using namespace std;
extern "C" void load_alert_to_db(void)
{
cout<<"db occi"<<endl;
}
makefile is:-
CC= g++
all:
$(CC) -c -Wall -Werror -fPIC db_manager.cpp
$(CC) -shared -o libdb_manager.so db_manager.o
gcc -L/home/oracle/Desktop/storage/ -Wall main.c -o data -ldb_manager
gcc -o data main.c
clean:
rm -f *.o data
so please help me which one is my problem. I am also include
export LD_LIBRARY_PATH=/home/oracle/Desktop/storage/:$LD_LIBRARY_PATH
environmental variable in .bash_profile
gcc -o data main.c
Not sure why you have this line in your makefile since it will compile main.c without reference to the previously created library and hence cause an undefined-symbol error such as the one you're seeing.
This is especially so, since you appear to have done it the right way on the preceding line:
gcc -L/home/oracle/Desktop/storage/ -Wall main.c -o data -ldb_manager
However, the entire point of using makefiles is so that it figures out the minimum necessary commands for you, based on dependencies. Lumping a large swathe of commands into a single rule tends to defeat that purpose. You would be better off making your rules a little more targeted, such as (untested but should be close):
all: data
data: main.o libdb_manager.so
gcc -o data main.o -ldb_manager
main.o: main.c
gcc -o main.o main.c
libdb_manager.so: db_manager.cpp
g++ -c -Wall -Werror -fPIC -o db_manager.o db_manager.cpp
g++ -shared -o libdb_manager.so db_manager.o
That way, if you make a small change to one part (like main.c), it doesn't have to go and compile/link everything in your build tree.
Your makefile seems to be completely broken and random, and you're not even linking the required object files. You can simplify this:
all:
$(CC) -c -Wall -Werror -fPIC db_manager.cpp
$(CC) -shared -o libdb_manager.so db_manager.o
gcc -L/home/oracle/Desktop/storage/ -Wall main.c -o data -ldb_manager
gcc -o data main.c
to just this:
all:
gcc -Wall -c main.c
g++ -Wall -c db_manager.cpp
g++ main.o db_manager.o -o data
this is what I needed to do:
Supposing the C++ function is called Debug::Write(str)
Then in your hpp file do the following:
#ifdef __cplusplus
extern "C" void DebugTmp(char *str);
#endif
Then in the corresponding cpp file do this:
void DebugTmp(char *str)
{
Debug::Write(str);
}
Then in your C file where you call DebugTmp define the prototype:
void DebugTmp(char *str);
then call it as below:
static void MyFunction( void )
{
DebugTmp("This is debug trace\n");
}
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.
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
I would like to write a make file, but I'm quit newbie. I have the main file where I include the l_mpc.h helper.h written by me, also I'm using the gnuplot, because of this I need the gnuplot_i.hpp.
This is my make file
CPPFLAGS=-I /usr/local/include/eigen3
dc_motor_main.out : dc_motor_main.o
g++ -o main.out dc_motor_main.o
dc_motor_main.o: l_mpc.o helper.o
g++ $(CPPFLAGS) -c dc_motor_main.cpp l_mpc.o helper.o
gnuplot_i.o: gnuplot_i.hpp
g++ $(CPPFLAGS) -c gnuplot_i.hpp
l_mpc.o: l_mpc.cpp l_mpc.h
g++ $(CPPFLAGS) -c l_mpc.cpp
helper.o: helper.cpp helper.h
g++ $(CPPFLAGS) -c helper.cpp
clean:
rm *.o dc_motor_main.out
and the output is the following:
g++ -I /usr/local/include/eigen3 -c l_mpc.cpp
g++ -I /usr/local/include/eigen3 -c helper.cpp
g++ -I /usr/local/include/eigen3 -c dc_motor_main.cpp l_mpc.o helper.o
g++: warning: l_mpc.o: linker input file unused because linking not done
g++: warning: helper.o: linker input file unused because linking not done
g++ -o main.out dc_motor_main.o
dc_motor_main.o: In function `main':
dc_motor_main.cpp:(.text+0x3ab3): undefined reference to `SysMat::SysMat()'
dc_motor_main.cpp:(.text+0x40fa): undefined reference to `SysMat::calcMPCFi(int)'
The SysMat::SysMat() is in the l_mpc.h, Where do I make the mistake?
This is my header files:
main.cpp
#include <iostream>
#include <Eigen/Dense>
#include <sys/time.h>
#include "gnuplot_i.hpp"
#include "l_mpc.h"
#include "helper.h"
#define DEBUG 1
int main( int argc, char* argv[])
{ ....
helper.h
#include <iostream>
#include <Eigen/Dense>
#include <sys/time.h>
#include "gnuplot_i.hpp"
using namespace Eigen;
double now();
void plot_x(MatrixXd, Gnuplot *);
void plot_x(MatrixXd, float, Gnuplot *);
void plot_xy(MatrixXd, MatrixXd, Gnuplot *);
void plot_xy(MatrixXd, Gnuplot *);
template <typename T> int sgn(T val) {
return (T(0) < val) - (val < T(0));
}
l_mpc.h
#include <iostream>
#include <Eigen/Dense>
#include <sys/time.h>
#include "gnuplot_i.hpp"
using namespace Eigen;
class SysMat
{
public:
MatrixXd Fi;
MatrixXd Ga;
MatrixXd C;
MatrixXd Er;
private:
MatrixXd MPCFi;
MatrixXd MPCGa;
MatrixXd MPCGy;
public:
SysMat(MatrixXd, MatrixXd, MatrixXd);
SysMat();
~SysMat();
void calcMPCFi(int);
void calcMPCGa(int);
void calcMPCGy(int, int);
MatrixXd calcContSig(MatrixXd, MatrixXd, MatrixXd);
MatrixXd calcError(MatrixXd, MatrixXd, MatrixXd);
};
The mistake looks to be here
dc_motor_main.out : dc_motor_main.o
g++ -o main.out dc_motor_main.o
dc_motor_main.o: l_mpc.o helper.o
g++ $(CPPFLAGS) -c dc_motor_main.cpp l_mpc.o helper.o
should be
main.out : dc_motor_main.o l_mpc.o helper.o
g++ -o main.out dc_motor_main.o l_mpc.o helper.o
dc_motor_main.o: l_mpc.o helper.o
g++ $(CPPFLAGS) -c dc_motor_main.cpp
assuming that you want your executable file to be called main.out.
When you use the g++ -c option you are compiling only. The final step without -c is called linking, that should link together all the *.o files you have created by compiling each *.cpp file.
As Olaf says in his answer there are various ways you can make this less repetitive, but what is above is the basic steps however you do it.
Make already knows how to build object files out of appropriate sources. So, most of the time you need only define the dependencies and you can simplify the Makefile to
CPPFLAGS=-I /usr/local/include/eigen3
LDFLAGS = # insert linker flags, if needed
LDLIBS = # insert needed libraries here
OBJS = \
dc_motor_main.o \
gnuplot_i.o \
l_mpc.o \
helper.o \
dc_motor_main.out: $(OBJS)
g++ $(LDFLAGS) -o $# $(OBJS) $(LDLIBS)
gnuplot_i.o: gnuplot_i.hpp
l_mpc.o: l_mpc.h
helper.o: helper.h
clean:
rm $(OBJS) dc_motor_main.out
Keep in mind, that the commands must be prefixed by a tab character. Don't insert spaces instead.