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
Related
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.
I had to merge two codes (TestOne.cpp + TestTwo.cpp), one of them already has its makefile (TestOne.cpp), but the other has only .h included, each of these .h has no cpp, all the code is on the .h (TestTwo.cpp)
for the makefile it's like this , and it work:
CC = g++
CFLAGS = -std=c++11
test: main.o hung.o
$(CC) -o test main.o hung.o
hung.o: Hungarian.cpp Hungarian.h
$(CC) -c Hungarian.cpp -o hung.o
main.o: testMain.cpp Hungarian.h
$(CC) $(CFLAGS) -c testMain.cpp -o main.o
clean:
-rm main.o hung.o
and the other one (TestTwo.cpp) it's also work by compiling like that :
g++ TestTwo.cpp -o test `pkg-config opencv --libs`
I have to create a new makefile using the first and introducing the seconde commande g++ ... how should i do ?
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.
Consider the following trivial Makefile. Notice that there are two classes with corresponding .h and .cpp files for each.
output: main.o class1.o class2.o
g++ main.o class1.o class2.o -o output
main.o: main.cpp
g++ -c main.cpp
class1.o: class1.cpp class1.h
g++ -c class1.cpp
class2.o: class2.cpp class2.h
g++ -c class2.cpp
clean:
rm *.o output
Is this Makefile robust? How can I make it more robust? Can someone provide a more robust version of this Makefile? It will be running on a 64 bit Red Hat Linux or CentOS machine.
If it matters, I am using:
-gcc --version 4.8.4 (From the GNU Compiler Collection)
-GDB version: GNU gdb (Ubuntu 7.7.1 -0ubuntu5~14.04.2) 7.7.1
I don't think your original makefile is far off the mark. I've just made a few additions:
Added a default all target - it's good to be explicit
Use the CXXFLAGS environment variable in all the calls to g++
Make main.o depend upon class1.h and class2.h as discussed
Specify that clean is a PHONY target just to be on the safe side if you add build artifact called clean
ALL := output
all : $(ALL)
output: main.o class1.o class2.o
g++ $(CXXFLAGS) main.o class1.o class2.o -o output
main.o: main.cpp class1.h class2.h
g++ $(CXXFLAGS) -c main.cpp
class1.o: class1.cpp class1.h
g++ $(CXXFLAGS) -c class1.cpp
class2.o: class2.cpp class2.h
g++ $(CXXFLAGS) -c class2.cpp
.PHONY : clean
clean:
rm *.o output
I would write something like
CXX = g++
# mandatory build flags
AM_CXXFLAGS = -Wall -W -std=gnu++11
# optional build flags
CXXFLAGS = -O2 -Werror
# mandatory link flags
AM_LDFLAGS = -Wl,-as-neeeded
output: main.o class1.o class2.o
${CXX} ${AM_LDFLAGS} ${LDFLAGS} $(filter %.o,$^) -o $#
%: %.cpp
${CXX} ${AM_CXXFLAGS} ${CXXFLAGS} $< -c -o $#
class1.o: class1.cpp class1.h
class2.o: class2.cpp class2.h
the *FLAGS are following automake notation: AM_* mean mandatory flags, the normal flags contain local settings (e.g. debugging or optimiziation).
Usually, AM_CPPFLAGS and CPPFLAGS with preprocessor flags (-I ...) should be used too but I omitted them here
the output target might need ${LIBS} too which have been omitted here
dependency tracking is more tricky and not implemented; you will have to play with -dM compiler option here...
When your program consists only of the listed 5 files, you can write
output_SOURCES = main.c class1.c class2.c class1.h class2.h
output: ${output_SOURCES}
${CXX} ${AM_CXXFLAGS} ${CXXFLAGS} ${AM_LDFLAGS} ${LDFLAGS} $(filter %.cpp,$^) -o $# ${LIBS}
directly.
EDIT:
For automatic dependency tracking, you can write
DEPGENFLAGS = \
-MD -MF ${#D}/.${#F}.d -MT '$#'
%: %.cpp
${CXX} ${DEPGENFLAGS} ${AM_CXXFLAGS} ${CXXFLAGS} $< -c -o $#
-include .deps.main.o.d
-include .deps.class1.o.d
-include .deps.class2.o.d
How can I make it more robust?
Use implicit rules, keep it simple.
LDLIBS+=-lstdc++
output: main.o class1.o class2.o
clean:
rm *.o output
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?