Pattern matching Makefile with multiple executable targets - build

I have a makefile that builds multiple executable targets prog0...prog99. All the compiler and link options are the same for each executable:
prog0: prog0.cpp prog0.h
$(CC) $(CFLAGS) prog0 prog0.cpp $(LINKFLAGS)
prog1: prog1.cpp prog1.h
$(CC) $(CFLAGS) prog1 prog1.cpp $(LINKFLAGS)
.
.
.
.
prog99: prog99.cpp prog99.h
$(CC) $(CFLAGS) prog99 prog99.cpp $(LINKFLAGS)
I was wondering if there is a pattern matching technique similar to building object files that could be applied to the above, so as to reduce the repetition of the makefile.

Yes, certainly:
prog%: prog%.cpp prog%.h
$(CC) $(CFLAGS) $# $< $(LINKFLAGS)

Related

How can I use different rules in Makefile for two groups of files?

I have one Makefile to build an executable and a library. Executable consists of a lot of source files and library consists of one .cpp file. The difference between compilation of executable and library is -fPIC option.
There is a compilation rule:
%.o : %.cpp
$(CXX) -c $(CXXFLAGS) $< -o $#
all: $(TARGET) $(TARGET_LIB)
$(TARGET): $(OBJS)
$(CXX) $(LDFLAGS) -o $# $^
$(TARGET_LIB): $(LIBOBJS)
$(CXX) $(LDFLAGS) -fPIC -shared -o $# $^
I tried to add compilation rule for library and got this:
lib.o : lib.cpp
$(CXX) -fPIC -c $(CXXFLAGS) $< -o $#
%.o : %.cpp
$(CXX) -c $(CXXFLAGS) $< -o $#
all: $(TARGET) $(TARGET_LIB)
$(TARGET): $(OBJS)
$(CXX) $(LDFLAGS) -o $# $^
$(TARGET_LIB): $(LIBOBJS)
$(CXX) $(LDFLAGS) -fPIC -shared -o $# $^
Unfortunately, only lib is compiled in this case. Second rule is omitted.
How can I use a rule for one file and different rule for group of other files?
If you just run make without a target, the first target gets built. So just put all back at the top and it should work fine.

Looping makefile with multiple main functions

I am trying to write a makefile that can create one executable per main function.
I have a list of files: main1.cpp, main2.cpp, and main3.cpp. They each contain an int main() function. Obviously I can't build these into one exec, which is not the goal here, so how can I build each one of these into its own executable? This is one solution:
main1: main1.cpp
$(CC) -o $# $^
main2: main2.cpp
$(CC) -o $# $^
main3: main3.cpp
$(CC) -o $# $^
But there MUST be a better way to do this. Is there some type of looping feature to makefiles that will make this process easier? Like a for loop?
A mixture of wildcard, patsubst and static pattern rules, plus the standard make variables for C++ compilation and linking:
SRCS := $(wildcard main*.cpp)
EXES := $(patsubst %.cpp,%,$(SRCS))
$(EXES): %: %.cpp
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $# $< $(LDLIBS)
But as make knows already how to make all this you could as well get rid of your Makefile and just type make main1...
While it's not a very sophisticated makefile, your solution is fine for three simple programs. You could make it more generic and support building all three targets at the same time with an "all" target.
all: main1 main2 main3
main1: main1.cpp
$(CC) -o $# $^
main2: main2.cpp
$(CC) -o $# $^
main3: main3.cpp
$(CC) -o $# $^

Makefile pattern rules differences

What is the difference between .cpp.o:, .o: and %.o: %.c?
Here's a simple Makefile example:
CC=g++
CFLAGS=-c -Wall
SOURCES=file1.cpp file2.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=program
$(EXECUTABLE): $(OBJECTS)
$(CC) $(OBJECTS) -o $#
#.o:
#.cpp.o:
%.o: %.c
$(CC) $(CFLAGS) $< -o $#
all: $(SOURCES) $(EXECUTABLE)
clean:
rm -rf $(OBJECTS) $(EXECUTABLE)
I have noticed that the output is same, but I guess they are interpreted on a different way internally.
Is there a preferred way of doing this?
.cpp.o: # build *.o from *.cpp (old style notation)
%.o: %.c # build *.o from *.c (new style notation)
Both work but the new style is more powerful because it allows you to write more complicated constructions thanks to pattern matching:
%.uuu: %.vvv %.www

compile only objects by default with makefile

I am trying to write a makefile to compile and generate only object files from the source code. I have this so far:
CC=g++
CFLAGS=-c -Wall -std=c++11
SOURCES=$(wildcard *.h)
OBJECTS=$(SOURCES:.cpp=.o)
all: $(OBJECTS)
$(OBJECTS):
$(CC) $(CFLAGS) $< -o $#
when I call it, it prints:
make: Nothing to be done for `all'.
Obviously I am making a mistake, but I don't know which one, because I am seeing in the GNU make documentation page a very similar example.
Any help would be very appreciated.
Replace: SOURCES=$(wildcard *.h) with SOURCES=$(wildcard *.cpp)
and:
$(OBJECTS):
$(CC) $(CFLAGS) $< -o $#
with:
%.o: %.cpp
$(CC) $(CFLAGS) $< -o $#
This means that each {file}.o is depend on existence of {file}.cpp.

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'.