G++ unresolved identifier, cannot find linker error - c++

I'm not sure if this is an error in my makefile, header, or source, but it looks like all the relevant pieces of code should link up nicely so I can use functions from one C++ file inside another, but I'm running into a brick wall. Here's a simplified version of what I'm working with:
common.h:
//common.h
#ifndef COMMON_H
#define COMMON_H
int foo();
#endif
common.cc:
//common.cc
#include "common.h"
int main(){
int z = foo();
return 0;
}//main
int foo(){
int x = 5;
int y = 7;
return x + y;
}//foo
test.cc:
//test.cc
#include "common.h"
int main(){
return foo();
}
And the makefile (sorry, it's a bit more complex, to better reflect how my overall project is operating):
TARGETS = common test
FLAGS = -lpthread
DEPS = common.h
all: $(TARGETS)
common: common.cc $(DEPS)
g++ $^ $(FLAGS) -g -o $#
test: test.cc $(DEPS)
g++ $(FLAGS) $^ -g -o $#
clean::
rm -fv $(TARGETS) *~
The compiler seems happy compiling common.cc, but runs into an unresolved identifier error on test.cc:
g++ -lpthread test.cc common.h -g -o test
/tmp/ccMwBGAj.o: In function `main':
/home/...../test.cc:6: undefined reference to `foo()'
Am I missing something here?
Thanks!

First, notice that when you try to build test, the only files you use are test.cc and common.h. The code in test.cc calls the function foo(), but that function is not defined in either of those files; it is defined in common.cc, which was not invited. And if you try to fix that by adding common.cc or common.o to the recipe, you'll run into more trouble, because common.cc contains a definition of main(), and so does test.cc, and there can be only one.
If you want to use foo() with other versions of main(), you should not put a main() in common.cc.
Now for the makefile recipe:
test: test.cc $(DEPS)
g++ $(FLAGS) $^ -g -o $#
This expands to:
test: test.cc common.h
g++ -lpthread test.cc common.h -g -o test
Which is incorrect, as #NeilButterworth has pointed out. You could do this:
test: test.cc common.cc
g++ test.cc common.cc -lpthread -g -o test
which can be written as:
test: test.cc common.cc
g++ $^ $(FLAGS) -g -o $#
But that can fail to rebuild when common.h is changed, and when it does rebuild it can recompile a source that hasn't changed. A better approach is:
common.o: common.cc $(DEPS)
g++ -c $< -g -o $#
test.o: test.cc $(DEPS)
g++ -c $< -g -o $#
common: common.o
g++ $^ $(FLAGS) -o $#
test: test.o common.o
g++ $^ $(FLAGS) -o $#
And further improvement is possible, once you have this much working.

Related

Compiling multiple c++ files doesn't work with certain file names

I am trying to compile multiple .cpp files, using a Makefile with make. I have a .cpp file containing the main function, in the other .cpp file a basic class (for every doubt I'll put all the code i'm using down here).
Example of names used to make it compile or to make it not compile:
-it works by having them named "prova.cpp"(contains the main function) and "pa.cpp"(contains the class) (below the commands done by the Makefile)
gioele#GioPC-U:~/Dev/Cpp/Exercises/666prova$ make
g++ -g -Wall -c src/prova.cpp -o obj/prova.o
g++ -g -Wall -c src/pa.cpp -o obj/pa.o
g++ -g -Wall obj/prova.o -o bin/provaBin
-it doesn't work by having them named "ciao.cpp"(contains the main function) and "pa.cpp"(contains the class)
gioele#GioPC-U:~/Dev/Cpp/Exercises/666prova$ make
g++ -g -Wall -c src/pa.cpp -o obj/pa.o
g++ -g -Wall -c src/ciao.cpp -o obj/ciao.o
g++ -g -Wall obj/pa.o -o bin/provaBin
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [Makefile:15: bin/provaBin] Errore 1
I think the problem is with the order of the files inside the Makefile. When it doesn't work is because is trying to get a binary from the .o without the main function. No idea on how to resolve.
The file with the main method:
#include <iostream>
int main() {
std::cout << "Hello world!" << std::endl;
return 0;
}
The class file:
class Class {
public:
int x;
int y;
};
The Makefile (still learning to work with Makefiles, probably the problem is here, any advice to make a Makefile of this kind better is appreciated, or if I am using something not properly):
CC=g++
CFLAGS=-g -Wall
OBJ=obj
SRC=src
BINDIR=bin
BIN=$(BINDIR)/provaBin
SRCS=$(wildcard $(SRC)/*.cpp)
OBJS=$(patsubst $(SRC)/%.cpp, $(OBJ)/%.o, $(SRCS))
all: $(BIN)
$(BIN): $(OBJS)
$(CC) $(CFLAGS) $< -o $#
$(OBJ)/%.o: $(SRC)/%.cpp
$(CC) $(CFLAGS) -c $< -o $#
clean:
$(RM) $(BINDIR)/* $(OBJ)/*
Thank you in advance.
You can fix this by changing one character.
In this rule:
$(BIN): $(OBJS)
$(CC) $(CFLAGS) $< -o $#
the prerequisite list $(OBJS) expands to a list of object files, such as prova.o pa.o or pa.o ciao.o. You want Make to incorporate that list into the linking command, like this:
g++ -g -Wall prova.o pa.o -o bin/provaBin
But the automatic variable $< expands to only the first item in the prerequisite list. If the first item is an object file that does not contain the main() function, such as pa.o, the linker will complain that main() is missing. (If it is an object file that contains main(), such as prova.o, then you will not get that error, but you may still have problems.)
The solution is to use the automatic variable $^, which expands to the complete list of prerequisites:
$(BIN): $(OBJS)
$(CC) $(CFLAGS) $^ -o $#

Printing the output straight from makefile to a .txt file

I have a test.cpp file that test my class, then I have a Makefile that I use to run my program AND run my tests (after running the tests, the result should be written into a .txt file as well as into the terminal). This is my test.cpp:
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
#include "Weather.h"
using namespace std;
TEST_CASE("Random test") {
Weather testt(10, 1, 0, "sunny");
CHECK(testt.getAirTemperature() == 10);
}
And this is my Makefile
CC = g++
CFLAGS = -c -Wall
TEST_TARGET = test.exe
TEST_OUT = test_out.txt
all: program
program: main.o Weather.o myException.o
$(CC) main.o Weather.o myException.o -o program
main.o: main.cpp
$(CC) $(CFLAGS) main.cpp
Weather.o: Weather.cpp
$(CC) $(CFLAGS) Weather.cpp
myException.o: myException.cpp
$(CC) $(CFLAGS) myException.cpp
build_test: test.o Weather.o myException.o
$(CC) test.o Weather.o myException.o -o $(TEST_TARGET)
run_test: $(TEST_TARGET)
$(TEST_TARGET) >> $(TEST_OUT) && $(TEST_TARGET)
test.o: test.cpp
$(CC) $(CFLAGS) test.cpp
rebuild: clean all
clean:
rm -rf *o program
You can ignore everything in the makefile just look at build_test run_test and test.o Since these are 3 things that I use for this task. In the terminal, when I write make build_test an executable is created successfully without any problem, although when I move on to make run_test I get test.exe >> test_out.txt && test.exe. make: *** [Makefile:24: run_test] Error 1. So it says the issue is in the 24th line which is $(TEST_TARGET) >> $(TEST_OUT) && $(TEST_TARGET). My question is, did I get the idea of how I should print it into a file and a terminal wrong? Or how should I output the results the doctest.h provides me with.

C Gnu makefile I cannot make a static library with ar

When I try this;
VPATH= ./src
CXXFLAGS= -I "./include"
program: ListNode.o LinkedList.o TreeNode.o Tree.o Test.o
g++ lib\ListNode.o lib\LinkedList.o lib\TreeNode.o lib\Tree.o lib\Test.o -o bin\program
ListNode.o: ListNode.cpp
g++ -c $(CXXFLAGS) $< -o lib\ListNode.o
LinkedList.o: LinkedList.cpp
g++ -c $(CXXFLAGS) $< -o lib\LinkedList.o
TreeNode.o: TreeNode.cpp
g++ -c $(CXXFLAGS) $< -o lib\TreeNode.o
Tree.o: Tree.cpp
g++ -c $(CXXFLAGS) $< -o lib\Tree.o
Test.o: Test.cpp
g++ -c $(CXXFLAGS) $< -o lib\Test.o
clean:
del *.exe
del *.o
It all works without any problem.But for my homework I have to create a static library.Anyway when I add this command to the makefile;
VPATH= ./src
CXXFLAGS= -I "./include"
program: ListNode.o LinkedList.o TreeNode.o Tree.o Test.o
g++ lib\ListNode.o lib\LinkedList.o lib\TreeNode.o lib\Tree.o lib\Test.o -o bin\program
ListNode.o: ListNode.cpp
g++ -c $(CXXFLAGS) $< -o lib\ListNode.o
LinkedList.o: LinkedList.cpp
g++ -c $(CXXFLAGS) $< -o lib\LinkedList.o
TreeNode.o: TreeNode.cpp
g++ -c $(CXXFLAGS) $< -o lib\TreeNode.o
Tree.o: Tree.cpp
g++ -c $(CXXFLAGS) $< -o lib\Tree.o
Test.o: Test.cpp
g++ -c $(CXXFLAGS) $< -o lib\Test.o
clean:
del *.exe
del *.o
libclass.a: ListNode.o LinkedList.o
ar -rcs libclass.a lib\ListNode.o lib\LinkedList.o
It doesn't do anything.There is no file or there is no error.Its like it doesn't exist :/
By the way I think it'd be good to mention about that if I use first makefile and then I put this code on terminal;
ar -rcs libclass.a lib\*.o
It works like magic i mean perfectly.So I need a little bit help cuz I'm about to go insane.Any help would be appreciated.
Add:
all: program libclass.a
to the beginning of your makefile. By default, make builds only the first target it finds in your makefile. This declares a fake target named "all" that depends on "program" and "libclass.a", so make ends up building both.

expected type-specifier before 'classname'

I have been looking this up for a while and there are a bunch of solutions but I don't think they are quite what my problem is,
at the moment I have a folder with some classes for a 'UI' for my client, I have compiled and tested these classes separate to my main project and they all work great, and my current makefile for my project without this new package works fine, but when I add my new package to my project and update my makefile and include the new UI files in my main I get a problem saying that previous classes in my project that I have already tested no longer work, for a better Idea of what I mean here
Terminal:
make -f makeLedger2.mk
gcc -o sqlite3 SQLite/sqlite3.c SQLite/shell.c -lm -lrt -lpthread -ldl
g++ -c rsa/Number.cpp
g++ -c rsa/BigInt.cpp -lm -lrt -lpthread -ldl
g++ -c rsa/Rsa.cpp -lm -lrt -lpthread -ldl
g++ -c database/Entry.cpp
g++ -c rsa/Key.cpp
g++ -c database/PersonalDataBase.cpp -lm -lrt -lpthread -ldl
gcc -o sqlite.o -c SQLite/sqlite3.c -lm -lrt -lpthread -ldl
g++ -c ClientUI/UIOutput.cpp
g++ -c ClientUI/UserCommand.cpp
g++ -c ClientUI/KeyboardController.cpp
g++ -c Network/P2P/Network.cpp -lm -lrt -lpthread -ldl
g++ -c main.cpp -lm -lrt -lpthread -ldl
main.cpp: In function ‘int main()’:
main.cpp:23:11: error: ‘overlay’ was not declared in this scope
main.cpp:23:25: error: expected type-specifier before ‘Network’
main.cpp:23:25: error: expected ‘;’ before ‘Network’
make: *** [main.o] Error 1
The biggest problem here is this is untouched from before I updated my makefile, (i.e. my Network class does not run into this error before I include, or all my code would compile without the addition of this new package 'ClientUI')
my makefile:
CXX = g++
CC = gcc
LIB = -lm -lrt -lpthread -ldl
BIN = SQLite ledger database Network/P2P Control ClientUI
****Added : UIOutput.o UserCommand.o KeyboardController.o***
OBJECTS = Number.o BigInt.o Rsa.o LedgerEntry.o Entry.o Key.o PersonalDataBase.o sqlite.o UIOutput.o UserCommand.o KeyboardController.o Network.o main.o
VPATH = SQLite rsa database Network/P2P Control ClientUI
all : $(BIN)
sqlite3: sqlite3.c shell.c
$(CC) -o $# $^ $(LIB)
ledger: $(OBJECTS)
$(CXX) -o $# $^ $(LIB)
Number.o: rsa/Number.cpp rsa/Number.h
$(CXX) -c rsa/Number.cpp
BigInt.o: rsa/BigInt.cpp rsa/BigInt.h rsa/Number.h
$(CXX) -c rsa/BigInt.cpp$(LIB)
Rsa.o: rsa/Rsa.cpp rsa/Rsa.h rsa/BigInt.h rsa/Number.h
$(CXX) -c rsa/Rsa.cpp $(LIB)
Key.o: rsa/Key.cpp rsa/Key.h rsa/Number.h
$(CXX) -c rsa/Key.cpp
Entry.o: database/Entry.cpp database/Entry.h rsa/Number.h
$(CXX) -c database/Entry.cpp
PersonalDataBase.o: database/PersonalDataBase.cpp database/PersonalDataBase.h SQLite/sqlite3.h database/Entry.h rsa/Key.h
$(CXX) -c database/PersonalDataBase.cpp $(LIB)
*****NEW PACKAGE******
UIOutput.o: ClientUI/UIOutput.h ClientUI/UIOutput.cpp
$(CXX) -c ClientUI/UIOutput.cpp
UserCommand.o: ClientUI/UserCommand.cpp ClientUI/UserCommand.h
$(CXX) -c ClientUI/UserCommand.cpp
KeyboardController.o: ClientUI/KeyboardController.cpp
$(CXX) -c ClientUI/KeyboardController.cpp
*****NEW PACKAGE End******
Network.o: Network/P2P/Network.cpp
$(CXX) -c Network/P2P/Network.cpp $(LIB)
***Include KeyboardController below***
main.o: main.cpp database/PersonalDataBase.h Network/P2P/Network.h ClientUI/KeyboardController.h
$(CXX) -c main.cpp $(LIB)
sqlite.o: sqlite3.c
$(CC) -o $# -c $^ $(LIB)
clean:
rm -f $(BIN)
rm -f $(OBJECTS)
.PHONEY: all, clean
for New Dependencies,
Message includes UIOutput
UserCommand Extends Message (includes)
KeyboardController includes UserCommand
this makefile for jsut these files works (and a test main.cpp for them)
out: UIOutput.o UserCommand.o KeyboardController.o main.o
g++ -o out UIOutput.o UserCommand.o KeyboardController.o main.o
UIOutput.o: UIOutput.h UIOutput.cpp
g++ -c UIOutput.cpp
UserCommand.o: UserCommand.cpp UserCommand.h Message.h UIOutput.h
g++ -c UserCommand.cpp
KeyboardController.o: KeyboardController.cpp KeyboardController.h UserCommand.h Message.h UIOutput.h
g++ -c KeyboardController.cpp
main.o: KeyboardController.h main.cpp
g++ -c main.cpp
main.cpp
#include "Network/P2P/Network.h"
#include "rsa/BigInt.h"
#include "rsa/Number.h"
#include "rsa/Rsa.h"
#include "database/PersonalDataBase.h"
//****Litterally All I do is include it here and I get an issue
//if I commented it out I would be fine and all the .o files would be built, including my new ones, and this can compile
#include "ClientUI/KeyboardController.h"
#include <iostream>
#include <sys/time.h>
#include <stdlib.h>
#include <limits>
using namespace std;
using namespace BigIntOperators;
using namespace RSA;
int main()
{
Network *overlay = new Network("Alice", "LOLO1");
....
.....
I'm doing nothing different to how I import my other packages, and I have compiled all the newly added files and tested them without problem seperatley, furthermore the packages ClientUI shares no dependancies with any other file, except in my main function... what's happening here?

C++ makefile while seperate the declaration and implementation

I wrote a small simple SQL interpreter in C++, in my main.cpp
the code is something like
#include "lexer.h"
#include "parser.h"
#include "interpreter.h"
using namespace std;
int main(int argc, char* argv[]) {
//my code
}
In lexer.h,parser.h, interpretor.h, each contain the declaration and implementation of a class with the same name of the header file.My question is how should I write my makefile so that I can separate the declaration and implementation, for example, declaration in lexer.h, implementation in lexer.cpp ?
The simplest way to do it is like below
interpreter: main.cc lexer.cc parser.cc interpreter.cc
g++ -o interpreter main.cc lexer.cc parser.cc interpreter.cc -I
but sometimes is useful to use different targets. This is because if you modify a single file in your project, you don't have to recompile everything, only what you modified.So you can do like below
Using dependencies
all: interpreter
interpreter: main.o lexer.o parser.o interpreter.o
g++ main.o lexer.o parser.o interpreter.o -o interpreter
main.o: main.cc
g++ -c main.cc
lexer.o: lexer.cc
g++ -c lexer.cc
parser.o: parser.cc
g++ -c parser.cc
interpreter.o: interpreter.cc
g++ -c interpreter.cc
clean:
rm -rf *o hello
Using variables and comments
We can also use variables when writing Makefiles
# Implementing a new sql lexer the variable CC will be
# the compiler to use.
CC=g++
# these flags will be passed to the compiler.
CFLAGS=-c -Wall
all: interpreter
interpreter: main.o lexer.o parser.o interpreter.o
$(CC) main.o lexer.o parser.o interpreter.o -o interpreter
main.o: main.cc
$(CC) $(CFLAGS) main.cc
lexer.o: lexer.cc
$(CC) $(CFLAGS) lexer.cc
parser.o: parser.cc
$(CC) $(CFLAGS) parser.cc
interpreter.o: interpreter.cc
$(CC) $(CFLAGS) interpreter.cc
clean:
rm -rf *o hello