Why undefiner reference? - c++

In my test.cpp I have:
#include <iostream>
#include "first.h"
using namespace std;
int main ()
{
auto dliste = d::data_preparation::prepare_d(100);
cout << "Hello World!\n";
return 0;
}
In my first.h I have:
namespace d {
namespace data_preparation {
something;
std::vector<row<mdata::dliste>> prepare_d(int f);
something;
}
}
In my first.cpp I have:
#include "first.h"
something;
namespace d {
namespace data_preparation {
vector<row<mdata::dliste>> prepare_d(int f) {
vector<row<mdata::dliste>> dliste;
cout << f << '\n';
return dliste;
}
}
}
When I compile this I get:
undefined reference to
`d::data_preparation::prepare_d(int)'
EDITED
In my Makefile I have:
test: test.o
$(CXX) -o $# $(LDFLAGS) $^ $(LDLIBS)
Should I modify it somehow?

You have most likely forgot to link first.cpp to your executable.
Just run this commands (if you are using gcc):
g++ -c first.cpp -o first.o
g++ -c test.cpp -o test.o
g++ test.o first.o
Or just use the compact version:
g++ first.cpp test.cpp -o app
You should edit your Makefile along the lines of:
app: test.o first.o
$(CXX) $^ -o $# $(LDFLAGS) $(LDLIBS)
test.o: test.cpp
$(CXX) -c test.cpp -o first.o
first.o: first.cpp
$(CXX) -c first.cpp -o first.o
Notice: I'm forced to use 4 spaces for indentation but Makefile may require tabs instead.

Related

Calling function from other C++ source doesn't work

I've looked at several posts of the same questions on here and as far as I've figured I've done what they said to do. However, I still get a "undefined reference to `cmb::functionA()'" warning.
I have the header:
//combine.h
#ifndef COMBINE_H
#define COMBINE_H
namespace cmb
{
void functionA();
}
#endif
Function source file:
// combine.cc
#include <iostream>
#include "combine.h"
using namespace std;
namespace cmb
{
void functionA()
{
cout << "print something\n";
}
}
And main:
//main.cc
#include "combine.h"
using namespace std;
using namespace cmd;
int main(int argc, char *argv[])
{
functionA();
}
It is now working when compiling manually (g++ -o Test *.cc -Wall --std=c++17) but using make still gives me the same error. I really don't understand make files so any help would be appreciated.
makefile:
CXX := g++
CXXFLAGS += -Wall -std=c++17
LIBSRCS = $(filter-out main.cc,$(shell find -name \*.cc))
LIBOBJS = $(patsubst %.cc,%.o,$(LIBSRCS))
main: main.o combine.o libproject.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $# $<
$(LIBOBJS): %.o: %.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $# $<
libproject.a: $(LIBOBJS)
ar rcs $# $^
clean:
rm -f libproject.a $(LIBOBJS)
.PHONY: clean
I just use make main in terminal.
You must add combine.o after main: in the makefile.
Since you use a library, you need to tell the linker to use it (LDFLAGS), and it should be after the main in g++ command. As in previous comments, the using namespace cmd needed to be changed to cmb
This one worked for me:
CXX := g++
CXXFLAGS += -Wall -std=c++17
LIBSRCS = $(filter-out ./main.cc,$(shell find -name \*.cc))
LIBOBJS = $(patsubst %.cc,%.o,$(LIBSRCS))
LDFLAGS += -L. -lproject
main: main.o libproject.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# $< $(LDFLAGS)
libproject.a: $(LIBOBJS)
ar rcs $# $^
.PHONY: clean
clean:
rm -f libproject.a $(LIBOBJS) main main.o
I also needed to add ./ in filtering out main.cc
Example run:
jontte#jontte-Latitude-E5420:~/Temp/maketest$ make
g++ -Wall -std=c++17 -c -o main.o main.cc
g++ -Wall -std=c++17 -c -o combine.o combine.cc
ar rcs libproject.a combine.o
g++ -Wall -std=c++17 -o main main.o -L. -lproject
jontte#jontte-Latitude-E5420:~/Temp/maketest$ ./main
print something
jontte#jontte-Latitude-E5420:~/Temp/maketest$ make clean
rm -f libproject.a ./combine.o main main.o
jontte#jontte-Latitude-E5420:~/Temp/maketest$

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.

Multiple hops in Makefile

I have a C/C++ mixed project and for each source code, I want to generate an assembly file (.S) and then an object file (.o) from the assembly. I thought the following Makefile should work:
all: a.o b.o main.o
g++ $^ -o main
%.o: %.S
gcc -o $# $<
%.S: %.c
gcc -S -o $# $<
%.S: %.cc
g++ -S -o $# $<
clean:
rm -rf *.o main
Ideally, in order to generate X.o, X.S needs to be generated by using one of the rules depending on whether X.c or X.cpp is available.
However, make apparently doesn't work the way I imagined. It resorts to the default rule for X.o and neither %.S: %.c nor %.S: %.cpp was applied... make -n gives
cc -c -o a.o a.c
g++ -c -o b.o b.cc
g++ -c -o main.o main.cc
g++ a.o b.o main.o -o main
The following example code can reproduce this:
// a.c
int a() { return 0;}
// b.cc
int b() { return 0;}
// main.cc
extern "C" int a();
extern int b();
int main() { a(); b(); return 0; }
I must have some misunderstanding of how a target is resolved. Any idea?
Use .SUFFIXES: at the top of your Makefile to flush predefined suffixes. Working example:
$tail -n +1 a.c b.cc main.cc Makefile; make clean; make; ./main
==> a.c <==
#include <stdio.h>
void a(void) {
printf("a\n");
}
==> b.cc <==
#include <stdio.h>
void b(void) {
printf("b\n");
}
==> main.cc <==
extern "C" {
void a(void);
}
void b(void);
int main(void) {
a();
b();
}
==> Makefile <==
.SUFFIXES:
all: main.o a.o b.o
g++ $^ -o main # all
%.o: %.S
gcc -c -o $# $< #o
%.S: %.c
gcc -S -o $# $< #Sc
%.S: %.cc
g++ -S -o $# $< #Scc
clean:
rm -rf *.o main
rm -rf *.o main
g++ -S -o main.S main.cc #Scc
gcc -c -o main.o main.S #o
gcc -S -o a.S a.c #Sc
gcc -c -o a.o a.S #o
g++ -S -o b.S b.cc #Scc
gcc -c -o b.o b.S #o
g++ main.o a.o b.o -o main # all
rm b.S main.S a.S
a
b
You need to cancel the implicit rules as they are a better match, add the following lines
%.o: %.cc
%.o: %.c
Note that your rule for all is broken as it doesn't create a file called all, make already knows how to assemble object files from assembly, and it also already knows how to link object files into a program if one of the object files matches the target
assembly := a.s b.s main.s
objects := $(assembly:.s=.o)
.SECONDARY: $(assembly)
main: CC := $(CXX)
main: $(objects)
%.s: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -S -o $# $<
%.s: %.cc
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -S -o $# $<
%.o: %.cc
%.o: %.c
clean: ; $(RM) $(objects) $(assembly) main

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.

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