Need help understanding makefile pattern rule % : %.o - c++

I want to change this makefile into something simpler using pattern rules I read about in a book:
VPATH = src
CPPFLAGS = -I include
main.o: main.cpp
g++ $(CPPFLAGS) $<
TwoDimensionalShape.o: TwoDimensionalShape.cpp
g++ -c $(CPPFLAGS) $<
Square.o: Square.cpp Square.h
g++ -c $(CPPFLAGS) $<
Circle.o: Circle.cpp Circle.h
g++ -c $(CPPFLAGS) $<
Rectangle.o: Rectangle.cpp Rectangle.h
g++ -c $(CPPFLAGS) $<
Triangle.o: Triangle.cpp Triangle.h
g++ -c $(CPPFLAGS) $<
ShapeStack.o: ShapeStack.cpp ShapeStack.h
g++ -c $(CPPFLAGS) $<
ScreenManager.o: ScreenManager.cpp ScreenManager.h
g++ -c $(CPPFLAGS) $<
ScreenState.o: ScreenState.cpp ScreenState.h
g++ -c $(CPPFLAGS) $<
SquareState.o: SquareState.cpp SquareState.h
g++ -c $(CPPFLAGS) $<
CircleState.o: CircleState.cpp CircleState.h
g++ -c $(CPPFLAGS) $<
After reading the book I can write the above using pattern rules like this. But I don't understand how it is working:
#source files are in "src" folder.
VPATH = src
#header files are in "include" folder.
CPPFLAGS = -I include -Wall
all: main.o TwoDimensionalShape.o Square.o Circle.o Rectangle.o Triangle.o ShapeStack.o ScreenManager.o ScreenState.o SquareState.o CircleState.o
g++ $(CPPFLAGS) $^
%.o: %.cpp
g++ -c $(CPPFLAGS) $<
%: %.o
g++ $<
This makefile is correct however I don't understand how it is working.
If I change for example 2 source files, how does this makefile understand to only compile the changed two source files and not all of source files?
In the book I read, example was about C not C++ and last line was %: %.c. Then why is my line which is %: %.o working? Shouldn't it be %: %.cpp?

This makefile is correct however I don't understand how it is working.
If your new Makefile is a replacement for the old one, it is definitely NOT working.
In the "old" one you have e.g.
ShapeStack.o: ShapeStack.cpp ShapeStack.h
which tells that ShapeStack.o depends on the .cpp and header file. Your new Makefile did not have any dependencies to other files which will result in a lot of trouble. Simply touch one of your headers and type make. Nothing will happen!
So at minimum you have to introduce your source file dependecies, maybe manual as in your old makefile or with some more automatism which uses the dependency check from the compiler, using gcc it is with "gcc -MM".
For getting automated prerequisites see https://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html
And using vpath can result in a lot of trouble. There are some articels, e.g.:
http://make.mad-scientist.net/papers/how-not-to-use-vpath/
Some example Makefiles can be found already here:
minimum c++ make file for linux

Related

how to include and compile a library in a makefile

I'm trying to build this hello world project that includes a library with both .h and .cpp files (and hence the library needs to be compiled too). The directory structure is
helloworld/lib/StanfordCPPLib/console.h
/src/hello.h
/src/hello.cpp
You can see the project code here
When I run make with the following makefile, i get an error that console.h (which is included by hello.cpp) cannot be found
CC=gcc
CFLAGS=-I.
DEPS = hello.h
OBJ = hello.o
#console.h is in lib/StanfordCPPLib and it is included by hello.cpp
INC=-I../lib/StanfordCPPLib
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
hellomake: $(OBJ)
g++ -o $# $^ $(CFLAGS) $(INC)
How to include the StanfordLibrary in this makefile so that it is both included and compiled.
(note, I'm aware the original sourcecode contains a QT creator file, however, I'm trying to build it using make)
The main problem is that your rule for building objs:
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
doesn't use your include path in $(INC)
Another problem is that you are matching on the wrong file extension. e.g. %.c should be %.cpp.
You also have some extra redundant junk in there, so I suggest you update your makefile like this to get the idea:
CC=gcc
DEPS = hello.h
OBJ = hello.o
INC=-I. -I../lib/StanfordCPPLib
%.o: %.cpp $(DEPS)
$(CC) $(INC) -c $<
hellomake: $(OBJ)
g++ -o $# $^
This builds fine in my little mock setup.
Remember that it is actually necessary for you to use g++ under hellomake: for everything to link properly.

GNU makefile rules and dependencies

I've been doing a lot of reading on how to write makefiles to build an application on Linux but I'm massively confused about the many different ways to apparently achieve the same goal.
This is what I have come up with so far to build an archive.
SHELL = /bin/sh
CXX = g++
DEBUG = -g
CXXFLAGS = -std=c++11 -Wall -pedantic #-Wextra
CPPFLAGS = -I. \
-I./include
SOURCES = foo1.cpp \
foo2.cpp \
foo3.cpp
OBJECTS = $(SOURCES:.cpp=.o)
The following rule successfully compiles each source file into an object file and then creates an archive:
libfoo.a: $(OBJECTS)
ar rvcs $# $(OBJECTS)
%.o: src/%.cpp ./include/%.h
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $# $<
This also does the same thing:
libfoo.a: $(OBJECTS)
ar rvcs $# $(OBJECTS)
$(OBJECTS) : %.o:src/%.cpp
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $# $<
However, this fails with an error that there is no rule to make target 'foo1.o:%.h
libfoo.a: $(OBJECTS)
ar rvcs $# $(OBJECTS)
$(OBJECTS) : %.o:src/%.cpp %.o:%.h
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $# $<
Can someone please explain why it doesn't work and which approach is best?
The first option lists the header files as dependencies but the second option doesn't. That is my motivation for the third option.
How do I list the headers as dependencies using options 2 or 3?
TIA
The feature you're using in try #2 and try #3 is static pattern rules and the syntax looks like this:
<targets...> : <target-pattern> : <prerequisites...>
There can only be two colons, not three. You should write your try #3 above as:
$(OBJECTS) : %.o : src/%.cpp %.h
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $# $<
Note one critical thing: this rule will FAIL if you ever create any .cpp file which does not have an associated .h file. Just sayin'.

Makefile for c++ with one .o file and one .CPP file

I am trying to create a makefile to build a windows c++ project on linux. I have to compile .cpp in different directories, to create a library .so with the objects.
For that I have created a script to find the .cpp and put it in a file :
SOURCE= \
./Source/CHAINE.CPP\
./Source/CRACKCHN.CPP\
./Source/LISTEPTR.CPP\
Now my makefile looks like : (I know I will have to change the $(TARGET) : $(OBJECT) rule, but thats not my problem here i think)
-include sources.mk
OBJECT = $(SOURCE:%.CPP=%.o)
#
$(TARGET) : $(OBJECT)
$(CC) $(CFLAGS) -o $# $^ $(LIBS)
$(OBJECT) : $(SOURCE)
$(CC) $(CFLAG) $(PREPROC) -c $< -o $(OBJ_DIR)/$# $(INCLUDE)
But when i do the make command, all the objects are created with the first .CPP (CHAINE.CPP here) :
g++ -Wall -D _MSC_VER -D _GPP -c Source/CHAINE.CPP -o ./Source/CHAINE.o
===
g++ -Wall -D _MSC_VER -D _GPP -c Source/CHAINE.CPP -o ./Source/CRACKCHN.o
===
g++ -Wall -D _MSC_VER -D _GPP -c Source/CHAINE.CPP -o ./Source/LISTEPTR.o
This is the first time I have to create a makefile, and I have a lot of problems to solve it, if anybody have a solution?
$(OBJECT) is a list of all objects. With the last rule you seem to want to tell Make how to build a single .o from a single .cpp. It should have a for of:
%.o: %.cpp
$(CC) $(CFLAG) $(PREPROC) -c $< -o $(OBJ_DIR)/$# $(INCLUDE)

How to specify the dependency of each source file on its corresponding header file by using wild cards?

Should be a simple makefile question, but didn't find a solution after some quick surfing.
Basically I have a bunch of "cpp" codes, each of which has a corresponding header file with the same stem name. I want to specify the dependency of each source file on its corresponding header file by using wild cards. The last commented-out line is what I want to add, and apparently its not working as intended.
SOURCES=a.cpp b.cpp c.cpp
HEADERS=$(SOURCES:.cpp=.h)
OBJECTS=$(SOURCES:.cpp=.o)
$(OBJECTS): %.o: %.cpp
$(CC) -fPIC -c $< -o $#
#$(OBJECTS): $(HEADERS)
You can add this:
$(OBJECTS): %.o: %.h
or modify your rule:
$(OBJECTS): %.o: %.cpp %.h
$(CC) -fPIC -c $< -o $#

building program with make and automatic dependencies

I have written a simple C++ program, and for the first time I want to compile and link it using a makefile. As a challenge I want to make a makefile, which lists all dependencies by itself. I am following this tutorial. My program consist of main.cpp, ext1.cpp and ext1.h. Following the tutorial, I have the following makefile
VPATH = src include
CPPFLAGS = -o include
CC = gcc
SOURCES = main.cpp \
ext1.cpp
-include $(subst .c,.d,$(SOURCES))
%.d: %.c
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
When I run this I get the message: make: *** No targets specified and no makefile found. Stop. It is not clear to me what I am missing in my case?
You are trying to do too much at once.
Step 1. Your first makefile should build the executable without attempting automatic dependency detection.
VPATH = include src
CPPFLAGS += -Iinclude
CC = gcc
exec: main.o ext1.o
$(CC) $^ -o $#
%.o: %.cc
$(CC) -c $(CPPFLAGS) $< -o $#
main.o ext1.o: ext1.h
Step 2. Once that works perfectly, you can put the header dependencies in separate files:
makefile:
VPATH = include src
CPPFLAGS += -Iinclude
CC = gcc
exec: main.o ext1.o
$(CC) $^ -o $#
%.o: %.cc
$(CC) -c $(CPPFLAGS) $< -o $#
-include *.d
main.d:
main.o : ext1.h
ext1.d:
ext1.o: ext1.h
Step 3. Once that works perfectly, you can generate the dependency files automatically:
VPATH = include src
CPPFLAGS += -Iinclude
CC = gcc
exec: main.o ext1.o
$(CC) $^ -o $#
%.o: %.cc
$(CC) -c -MMD $(CPPFLAGS) $< -o $#
-include *.d
no make file found ? what name you have given for makefile? make sure its makefile or Makefile if you are just executing command make else you can pass file name to make like this
make -f yourmakefile
and changes suggested by Petr Budnik must work