How to create Makefile for multiple files in multiple directories? - c++

Good morning,
I new in c++ and I am trying to compile my simple code to executable form. I will explain structure of project.
- main.cpp
- /utility/server.h
- /utility/server.cpp
I enclose file sources for complete information.
main.cpp
#include <iostream>
#include "utility/server.h"
using namespace std;
using namespace server;
int main() {
std::cout << "Content-type:text/html\r\n\r\n";
std::cout << "Your server name is: " << server::get_domain() << '\n';
return 0;
}
server.cpp
#include <cstdlib>
#include "server.h"
namespace server {
static char* get_domain() {
return getenv("SERVER_NAME");
}
}
To my Makefile I added comments to understand what I want to do.
#
# 'make' build executable file
# 'make clean' removes all .o and executable files
#
# define the C compiler to use
CC = g++
# define any compile-time flags
CFLAGS = -Wall -g
# define any directories containing header files other than /usr/include
INCLUDES = -I../utility
# define the C++ source files
SRCS = main.cpp utility/server.cpp
# define the C++ object files
OBJS = $(SRCS:.cpp=.o)
# define the executable file
MAIN = executable.cgi
#
# The following part of the makefile is generic
#
.PHONY: depend clean
all: $(MAIN)
$(MAIN): $(OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS)
# this is a suffix replacement rule for building .o's from .cpp's
.c.o:
$(CC) $(CFLAGS) $(INCLUDES) -cpp $< -o $#
clean:
$(RM) *.o *~ $(MAIN)
depend: $(SRCS)
makedepend $(INCLUDES) $^
And finally error from compilation
g++ -Wall -g -I../utility -o executable.cgi main.o utility/server.o
Undefined symbols for architecture x86_64:
"server::get_domain()", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [executable.cgi] Error 1
From error message I understood there is problem with utility folder, but I don't know how to fix it.
Thank you for your help :)

In server.cpp, here:
namespace server {
static char* get_domain() {
return getenv("SERVER_NAME");
}
}
You have made char* server::get_domain() a static function, making
its definition visible only within this translation unit and invisible to
the linker. Remove the keyword static here, and also in server.h if you have declared the function static there.
A namespace is not a class or struct. Confusingly,
namespace server {
static char* get_domain() {
return getenv("SERVER_NAME");
}
}
server::get_domain() is a static function in that namespace. But
struct server {
static char* get_domain() {
return getenv("SERVER_NAME");
}
};
it is a global function in that class, which the linker can see.

Related

g++ isn't compiling all of the files in my project

I'm trying to build a c++ project in VS Code but when i try to build it g++ throws an error saying:
g++ -std=c++17 -ggdb -Iinclude src/main.cpp -o bin/main
Undefined symbols for architecture x86_64:
"MessageBus::MessageBus()", referenced from:
_main in main-244f95.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [bin/main] Error 1
The terminal process "/bin/zsh '-c', 'make'" terminated with exit code: 2.
Here are the files that i think are causing the problem:
MessageBus.h
#pragma once
#include "../Utils/Queue.h"
#include "../Utils/SimpleList.h"
#include "Messages/Message.h"
class System;
class MessageBus
{
public:
MessageBus();
~MessageBus();
void addReciever(System* system);
void postMessage(Message* msg);
void notify();
private:
Queue<Message> msgQueue;
SimpleList<System*> systems;
};
MessageBus.cpp
#include "MessageBus.h"
#include "System.h"
MessageBus::MessageBus() {}
MessageBus::~MessageBus() {}
void MessageBus::postMessage(Message* msg) {
msgQueue.add(msg);
}
void MessageBus::addReciever(System* system) {
systems.add(system);
}
void MessageBus::notify() {
int queueLength = msgQueue.getLength();
for (int i = 0; i < queueLength; i++) {
Message msg = msgQueue.pop();
for (int j = 0; j < systems.getLength(); j++) {
System* system = systems.get(j);
system->handleMessage(&msg);
}
}
}
main.cpp
#include "EventSystem/MessageBus.h"
int main(int argc, char* argv[])
{
MessageBus* msgBus = new MessageBus();
}
Makefile
CXX := g++
CXX_FLAGS := -std=c++17 -ggdb
BIN := bin
SRC := src
INCLUDE := include
LIBRARIES :=
EXECUTABLE := main
all: $(BIN)/$(EXECUTABLE)
run: clean all
clear
./$(BIN)/$(EXECUTABLE)
$(BIN)/$(EXECUTABLE): $(SRC)/*.cpp
$(CXX) $(CXX_FLAGS) -I$(INCLUDE) $^ -o $# $(LIBRARIES)
clean:
-rm $(BIN)/*
But when i try to compile these files together using the terminal:
g++ main.cpp EventSystem/MessageBus.cpp -o maintest
it works just fine, so i think the problem is that my files aren't compiled together. I think this might have something to do with the linker being unable to find the correct files and it might have something to do with my project structure?
This is my current structure
As you can see the header files are located together with the source code. Should i separate the header files from the cpp files or is it that i have put them in subdirectories? Or is it something else entirely? I'm somewhat new to c++ and Makefiles and i can't seem to understand what is causing the problem.
Edit:
Solution:
As #MadScientist suggested i replaced $(SRC)/*.cpp in my Makefile with $(shell find $(SRC) -name \*.cpp -print) which solved the problem. But as #WhozCraig mentioned i should probably switch to cmake to avoid Makefiles in the future.
You list the "working" command as:
g++ main.cpp EventSystem/MessageBus.cpp -o maintest
but your recipe is:
$(BIN)/$(EXECUTABLE): $(SRC)/*.cpp
The glob expression $(SRC)/*.cpp won't match the file main.cpp.
If we could see your link line, we'd probably be able to see that main.cpp is missing.

C++ How would I combine two makefile object target rules (which are located in another folder) into one target/rule?

My C++ program consists of three files:
two source files 'main.cpp' and 'hellolib.cpp'
a header file 'hellolib.h'
I am creating a makefile for this program. For my assignment I need one target ('hello') that compiles all source files in an executable.
Another target ('obj') should compile all '.cpp' files into objects and link them together in an executable.
When running make I prefer the object files to be created in a seperate folder called 'bin'. The source files are would be in a folder called 'src'. These folders are siblings, the makefile is in it's parent folder.
My makefile works fine but I wish two combine the two targets 'bin/main.o' and 'bin/hellolib.o' into one to reduce the amount of rules, especially for later when I am dealing with more source files.
I imagined the replacement would look something like this, but it doesn't seem to work.
It gives me the error: "*** No rule ot make target 'bin/main.o',
needed by 'obj'. Stop.
bin/%.o : src/%.cpp
$(CC) -c $< -o $#
Working Makefile:
CC = g++
SOURCES = ./src/main.cpp \
./src/hellolib.cpp
OBJECTS = ./bin/main.o \
./bin/hellolib.o
hello : $(SOURCES)
$(CC) -o $# $^
obj : $(OBJECTS)
$(CC) -o $# $^
bin/main.o : src/main.cpp
$(CC) -c $< -o $#
bin/hellolib.o : src/hellolib.cpp
$(CC) -c $< -o $#
clean:
#rm -rf hello obj bin/*.o
main.cpp:
#include "hellolib.h"
int main() {
Hello h("Name");
h.Print();
return 0;
}
hellolib.cpp
#include "hellolib.h"
#include <iostream>
Hello::Hello(std::string name) {
if (name.empty()) {
cout << "Name is not valid!";
return;
}
_name = name;
}
void Hello::Print() {
cout << "Hello " << _name << endl;
}
hellolib.h
#ifndef HELLO_LIB_H
#define HELLO_LIB_H
#include <string>
using namespace std;
class Hello {
std::string _name;
public:
Hello(std::string name);
void Print();
};
#endif
You need to change:
OBJECTS = ./bin/main.o \
./bin/hellolib.o
to:
OBJECTS = bin/main.o \
bin/hellolib.o
(Removing leading "./"). Either that, or change your pattern rule to include the leading "./":
./bin/%.o : src/%.cpp
$(CC) -c $< -o $#
Make rule matching uses text matching. It's not based on filenames, so "./././foo" and "foo" are not the same thing.
Personally I recommend rewriting like this:
SOURCES = src/main.cpp \
src/hellolib.cpp
OBJECTS = $(patsubst src/%.cpp,bin/%.o,$(SOURCES))
so you only need to keep the list of files in one place.
You can make a rule that builds anything conforming to a specific pattern like this:
bin/%.o : src/%.cpp
$(CC) -c -o $# $<
That will compile any bin/%.o dependency from the corresponding source src/%.cpp.
Also it is standard when compiling C++ to use CXX rather than CC (which is for C code).

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

Linking in mac os x (10.8)

I'm trying to compile a multi file bit of code which up until now has been working fine.
But now I am getting some linker errors. I have a class definition 'njPhaseSpace' which is reported as being:
ld: duplicate symbol njPhaseSpace::njPhaseSpace(int)in Source/Currents.o and
/var/folders/p8/0bwv51kn2w5cx4jnsg6xm7340000gn/T//ccb0Psoz.o for architecture x86_64
I have no idea what the /var/folder/.../ccb0Psoz.o file is about and it isnt (intentionally) begin used in my project.
if I change the name to something different - but similar - such as njPhaseSpaceX it will compile and link up fine. But then I clean the project using 'make clean' and when I try to remake I get the same link error again! (but with a different /var/.../XXXXXX.o file)
Any suggestions?
Cheers
UPDATE: More strange things: When I look in the /var/folder/... directory to see which file is causing the duplication no such file exists!
UPDATE: The njPhaseSpace source file is:
// Standard header files
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <stdio.h>
#include <math.h>
#include <complex>
#include <iomanip>
#include "LoadBar.h"
// CLHEP header files
#include <CLHEP/Vector/LorentzVector.h>
#include <CLHEP/Random/RanluxEngine.h>
// More convenient label for four-vectors
typedef CLHEP::HepLorentzVector HLV;
// Definition of structure to hold the phase-space point
struct ParticleStruct {
HLV pa;
HLV pb;
HLV pep;
HLV pem;
HLV p1;
HLV p2;
HLV p3;
double xa;
double xb;
} ;
// A class for the n-jet phase space
class njPhaseSpace {
private:
// Incoming Particle Momenta
HLV pa;
HLV pb;
// Emitted leptons
HLV pep;
HLV pem;
// Outgoing parton momenta
std::vector <HLV> OutgoingPartons;
// Kinematic factors
double xa;
double xb;
public:
// Constructor for class
njPhaseSpace(int n);
// Returns a vector of the outgoing parton momenta
std::vector <HLV> ReturnOutgoingPartons() {
return OutgoingPartons;
}
// HLV IncomingForward
} ;
// Class constructor - adds n vectors to the Outgoing array
njPhaseSpace::njPhaseSpace(int n) {
// Add n final states to the OutgoingPartons vector
for (int i = 0; i < n; i++) {
HLV temp;
OutgoingPartons.push_back(temp);
}
}
UPDATE: This problem goes away when the class constructor is included in the body of the class definition. Whilst its good I can avoid this it doesnt really help because now to develop my class everything will have to sit inside the definition.
UPDATE: The makefile used to compile (Analysis is something seperate I am currently running make Explorer -j8):
#/bin/bash
# CXX Compiler
CXX = g++
# Directories For Compilation
INCDIR = MadGraph
LIBDIR = MadGraph
SRCDIR = Source
# Compilation Flags
CXXFLAGS = -O3 -lm
LIBFLAGS = $(shell clhep-config --libs) $(shell fastjet-config --libs) $(shell clhep-config --libs) $(shell root-config --libs)
INCFLAGS = $(shell clhep-config --include) -I/$(INCDIR) -I$(SRCDIR) -I. $(shell fastjet-config --cxxflags --plugins) $(shell clhep-config --libs) $(shell root-config --cflags)
FLAGS = $(CXXFLAGS) $(LIBFLAGS) $(INCFLAGS)
# Object Files
Objects = $(addprefix $(SRCDIR)/, Currents.o mstwpdf.o LoadBar.o)
MadObjects = $(addprefix $(LIBDIR)/, HelAmps_sm.o Parameters_sm.o read_slha.o CPPProcess2j.o CPPProcess3j.o)
# Main targets
all: Analysis Explorer
Analysis: $(SRCDIR)/Analysis2jepem.cxx $(Objects) $(SRCDIR)/CGenerator2jepem.o
$(CXX) $(SRCDIR)/Analysis2jepem.cxx -o $# $(FLAGS) $(Objects) $(SRCDIR)/CGenerator2jepem.o
Explorer: $(SRCDIR)/qQepemqQ_Explorer.cxx $(Objects) $(MadObjects) $(LIBDIR)/libmodel_sm.a
$(CXX) $(SRCDIR)/qQepemqQ_Explorer.cxx -o $# $(FLAGS) $(Objects) -lmodel_sm -L$(LIBDIR)
# Build object files
$(Objects):
$(CXX) -c $(#:.o=.cxx) -o $#
# Build the MG5 object code
$(MadObjects):
$(CXX) -c $(#:.o=.cxx) -o $# -I../
$(SRCDIR)/CGenerator2jepem.o:
$(CXX) -c $(#:.o=.cxx) -o $#
# Build the Standard Model library
$(LIBDIR)/libmodel_sm.a: $(MadObjects)
$(AR) cru $# $^
ranlib $#
# Debugging flags
debug: CXX += -g -Wall -pendantic
debug: all
# Create a clean build
.PHONY: clean
clean:
rm -f $(Objects) $(MadObjects) $(LIBDIR)/2j/libmodel_sm.a $(LIBDIR)/3j/libmodel_sm.a $(TARGET) $(SRCDIR)/CGenerator2jepem.o Analysis Explorer
The problem is that the class constructor is defined in the header file as:
njPhaseSpace::njPhaseSpace(int n) {
// Add n final states to the OutgoingPartons vector
for (int i = 0; i < n; i++) {
HLV temp;
OutgoingPartons.push_back(temp);
}
Either put it in the class declaration, or into it's own separate .cpp file that is compiled and linked separately.
This is no different from creating a non-inline/non-static/non anonymous namespaced function in a .h file and #including it in multiple .cpp files.
This error is sometimes prompted if you include the files like this:
File a included in file b;
Filb and file a included in file c.
Can you try to put the "static" keyword in front of the class constructor that gives you problems?

c++ functions defined outside of class in separate .cpp file and makefile linking

I have a project using functions from a class CRandomMersenne, declared in header randomc.h; the functions are defined in a different file mersenne.cpp. In my makefile I have an object *MC_funcs2.o* that uses functions from the class. The source *MC_funcs2.cpp* includes the header randomc.h. However the compiler complains:
MC_funcs2.o:MC_funcs2.cpp:(.text+0x20): undefined reference to `CRandomMersenne::Random()'
I understand there is something I've done wrong with declaring functions outside the class definition, including header file to use mentioned functions and maybe with the linking in the makefile. Here is a stripped down version of some of the files:
makefile:
SpMC3: SpMC3.cpp SpMC.h mersenne.o MC_funcs2.o
g++ SpMC3.cpp MC_funcs2.o mersenne.o -o SpMC3
MC_funcs2.o: MC_funcs2.cpp SpMC.h randomc.h
g++ -c MC_funcs2.cpp mersenne.cpp
mersenne.o: mersenne.cpp randomc.h userintf.cpp
g++ -c mersenne.cpp userintf.cpp
SpMC3.cpp (main program):
#include "SpMC.h"
int main() {
cout << "boing" << endl;
return 0;
}
MCfuncs2.cpp (the one that doesn't compile):
#include "SpMC.h"
#include "randomc.h"
CRandomMersenne RanGen(time(0));
void outrandom() {
ofstream out;
out << RanGen.Random() << endl;
return;
}
Any ideas?
This error just means mersenne.cpp not being compiled ...make sure it get compiled and linked...
I would strongly advise compiling each individual source file *.c to a object file *.o, i.ex. mersenne.cpp -> mersenne.o. This can be achieved without having to specify each object file manually.
CC = gcc
CFLAGS = -g -O2
OBJECTS = main.o foo.o
main : $(OBJECTS)
$(CC) $(CFLAGS) $(OBJECTS) -o main
%.o : %.c
$(CC) $(CFLAGS) -c $<
For further information on makefiles, please take a look a this tutorial or excellent SO answer in How to make a SIMPLE C++ Makefile?.