Makefile: Same Rule for multiple Targets - makefile

I've some targets (lets say 3). So after the makefile has run, I want to have 3 executable files.
Here's what I've done by now:
CC = gcc
CFLAGS = -Wall -pedantic -ansi
ECHO = server_echo
ECHO_O = echo.o
FOO = server_foo
FOO_O = foo.o
ALL = $(ECHO) $(FOO)
ALL_O = ECHO_O FOO_O
all: $(ALL)
$(ECHO): $(ECHO_O)
$(CC) $(CFLAGS) -o $(ECHO) $(ECHO_O)
$(FOO): $(FOO_O)
$(CC) $(CFLAGS) -o $(FOO) $(FOO_O)
.PHONY: clean
clean:
- rm -f $(ALL)
- rm -f *.o
- rm -f core
%.o: %.c
$(CC) $(CFLAGS) -c $<
.PHONY: mci
mci: clean $(ALL)
There I've a duplicate of rules for the targets $(ECHO) and $(FOO). Is there any way, that I can eliminate the duplication? Something like:
for target, target_o in $(ALL), $(ALL_O)
target: target_o
$(CC) $(CFLAGS) -o target target_o
end for
Or is there another way to solve my Problem?
Thanks for your help

Nothing easier:
$(ECHO): $(ECHO_O)
$(FOO): $(FOO_O)
$(ECHO) $(FOO):
$(CC) $(CFLAGS) -o $# $^
Or you can do away with the variables ECHO_O and FOO_O entirely with a static pattern rule:
$(ECHO) $(FOO): % : %.o
$(CC) $(CFLAGS) -o $# $^

For a bit larger rules, the call function or canned recipes can be useful.
Here is an untested example with the call function:
define COMPILE =
$(CC) $(CFLAGS) -o $(2) $(1)
endef
$(ECHO): $(ECHO_O)
$(call COMPILE,$^,$#)
$(FOO): $(FOO_O)
$(call COMPILE,$^,$#)
Here is an untested example with a canned recipe:
define COMPILE =
$(CC) $(CFLAGS) -o $# $^
endef
$(ECHO): $(ECHO_O)
$(COMPILE)
$(FOO): $(FOO_O)
$(COMPILE)
The examples contain multi-line variables as well as automatic variables.
Just in case, here is a link to the tutorial that I find useful: link.

Related

Why does my Makefile with pattern rules not create debugging symbols for main?

I am using this auto-generated Makefile with pattern rules, that I oviously do not understand yet. I want to create debuggins symbols and then debug main, but it doesn't work. There is a -g flag. Adding $(LDFLAGS) statement above after $(ODIR) does not print one as expcted.
IDIR =./include
CC=g++
CFLAGS = -I$(IDIR)
LDFLAGS = -g
ODIR=./
LIBS=
_OBJ = main.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.c
$(CC) -c -o $# $< $(CFLAGS)
main: $(OBJ)
$(CC) $(LDFLAGS) -o $# $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o
This is the terminal output
g++ -c -o Source.o Source.cpp
g++ -g -o Source Source.o -I./include
Your sources are C++ (.cpp) but your Makefile contains explicit instructions for building C files. Make is therefore falling back to its built in implicit rules.
Also note that by convention those rules use $(CXX) to refer to the C++ compiler, with $(CXXFLAGS) replacing $(CFLAGS), and the -I flag belongs in $(CPPFLAGS):
IDIR =./include
CPPFLAGS = -I$(IDIR)
CXXFLAGS = -g
ODIR=.
LIBS=
_OBJ = main.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.cpp
$(CXX) -c -o $# $(CPPFLAGS) $(CXXFLAGS) $<
main: $(OBJ)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $# $^ $(LIBS)
.PHONY: clean
clean:
rm -f $(OBJ)
If you were to do away with the ODIR handling and use the conventional variable names you could do without the explicit .o: .cpp rule altogether.

Makefile multiple targets from same source file, with different flags

I have a binary that I need to build multiple times with different compiler flags. Therefore, I have a Makefile that states something like:
OBJECTS_A := $(addprefix $(OBJFOLDER)/, $(SOURCES:.cpp=.a.o))
OBJECTS_B := $(addprefix $(OBJFOLDER)/, $(SOURCES:.cpp=.b.o))
OBJECTS_C := $(addprefix $(OBJFOLDER)/, $(SOURCES:.cpp=.c.o))
I also define a rule to change the flags for each OBJECTS_x:
$(OBJECTS_B): DEFINES+=-D_B
$(OBJECTS_C): DEFINES+=-D_C
And this is where the problem happens: If I state the targets separately, as:
$(OBJFOLDER)/%.a.o: %.cpp
$(COMPILER) $(CFLAGS) $(INCFOLDER) $(DEFINES) -c $< -o $#
$(OBJFOLDER)/%.b.o: %.cpp
$(COMPILER) $(CFLAGS) $(INCFOLDER) $(DEFINES) -c $< -o $#
$(OBJFOLDER)/%.c.o: %.cpp
$(COMPILER) $(CFLAGS) $(INCFOLDER) $(DEFINES) -c $< -o $#
All works. However, if I merge all rules into one, only the first is evaluated:
$(OBJFOLDER)/%.a.o $(OBJFOLDER)/%.b.o $(OBJFOLDER)/%.c.o: %.cpp
$(COMPILER) $(CFLAGS) $(INCFOLDER) $(DEFINES) -c $< -o $#
What I get on a dry run is that only $(OBJFOLDER)/%.a.o objects are build, but on the linking rule each binary requires its objects (and b and c binaries fail to build, therefore).
Any ideas?
Thank you!
You can achieve this using secondary expansion :
.SECONDEXPANSION:
$(OBJFOLDER)/%.o: $$(basename $$*).cpp
$(COMPILER) $(CFLAGS) $(INCFOLDER) $(DEFINES) -c $< -o $#
Note that this is not a very idiomatic way of doing this, a more usual define / call / eval combo can be used to generate rules as in your first solution :
VARIANTS=a b c
DEFINES_FOR_a=
DEFINES_FOR_b=-D_B
DEFINES_FOR_c=-D_C
define make_target =
$$(OBJFOLDER)/%.$(1).o: %.cpp
$$(COMPILER) $$(CFLAGS) $$(INCFOLDER) $$(DEFINES_FOR_$(1)) -c $$< -o $$#
endef
$(eval $(foreach variant,$(VARIANTS),$(call make_target,$(variant))))
Another way is to create symlinks to your source files and compile those with different flags. This way the same one generic pattern rule (OBJFOLDER)/%.o: %.cpp can build all of your targets:
OBJECTS_A := $(SOURCES:%.cpp=$(OBJFOLDER)/%.a.o)
OBJECTS_B := $(SOURCES:%.cpp=$(OBJFOLDER)/%.b.o)
OBJECTS_B := $(SOURCES:%.cpp=$(OBJFOLDER)/%.c.o)
$(OBJECTS_B): DEFINES+=-D_B
$(OBJECTS_C): DEFINES+=-D_C
%.a.cpp : %.cpp
ln -s $< $#
%.b.cpp : %.cpp
ln -s $< $#
%.c.cpp : %.cpp
ln -s $< $#
$(OBJFOLDER)/%.o: %.cpp
$(COMPILER) $(CFLAGS) $(INCFOLDER) $(DEFINES) -c -o $# $<

makefile - define dependency using variable with objects when building many executables

I'm following great tutorial about ffmpeg (http://dranger.com/ffmpeg) and I'm trying to build a generic makefile for it.
My problem is that I cannot define a generic rule for executables to be depenent on an object of the same name but with ".o" suffix.
Example: when invoked make all I want to build 2 executables tutorial01 and tutorial02 out of 2 files tutorial01.cpp and tutorial02.cpp, but first I want to compile them into *.o and then link them.
My whole Makefile is like so:
CC=g++
CXXFLAGS="-std=c++11"
CXXFLAGS+=`sdl-config --cflags`
LDFLAGS=-L/usr/lib/x86_64-linux-gnu/
LDFLAGS+=-L/lib/x86_64-linux-gnu/
LDFLAGS+=-lavutil-ffmpeg -lavcodec-ffmpeg -lavformat-ffmpeg -lswscale-ffmpeg
LDFLAGS+=`sdl-config --libs`
SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLES=$(SOURCES:.cpp=)
all : $(EXECUTABLES)
# Not working:
#%$(EXECUTABLES) : $(OBJECTS)
# $(CC) $< -o $# $(LDFLAGS) $(LD_LIBS)
#
# Not working (always substitutes the first found):
#$(EXECUTABLES) : $(OBJECTS)
# $(CC) $< -o $# $(LDFLAGS) $(LD_LIBS)
#
# Not working:
#for exec in $(EXECUTABLES) ; do \
#$(exec) : $(exec).o ; \
#done
#
# Working:
#tutorial01:tutorial01.o
#tutorial02:tutorial02.o
#tutorial03:tutorial03.o
%: %.o
$(CC) $< -o $# $(LDFLAGS) $(LD_LIBS)
%.o : %.cpp
$(CC) $(CXXFLAGS) -c $< -o $#
clean:
rm -rf $(OBJECTS) $(EXECUTABLES)
I tried what is stated above as "not working" and also gave an example of what is working but not generic.
# Not working (always substitutes the first found):
$(EXECUTABLES) : $(OBJECTS)
$(CC) $< -o $# $(LDFLAGS) $(LD_LIBS)
This fails because $(OBJECTS) expands to something like tutorial01.o tutorial02.o tutorial03.o for all targets, and $< expands to the first prerequisite, which is the same (tutorial01.o) for all targets.
# Not working:
for exec in $(EXECUTABLES) ; do \
$(exec) : $(exec).o ; \
done
This fails because it is for-loop written in shell syntax. You can write a for-loop in Make syntax, but it is not needed here.
I would use a pattern rule:
tutorial%: tutorial%.o
$(CC) $< -o $# $(LDFLAGS) $(LD_LIBS)
or a static pattern rule:
$(EXECUTABLES): %: %.o
$(CC) $< -o $# $(LDFLAGS) $(LD_LIBS)

How to replace parent directory in Makefile

I've the following situation:
SOURCES=home/main.cpp modelChecking/Configuracao.cpp modelChecking/Estado.cpp modelChecking/Formula.cpp modelChecking/ModelChecking.cpp lib/VisitTree.cpp
SUFIX=$(SOURCES:.cpp=.o)
OBJECTS=$(SUFIX)
all: refiner
refiner: $(OBJECTS)
$(CC) $^ -o refiner
home/main.o: home/main.cpp
$(CC) $(CFLAGS) $< -o $#
modelChecking/Configuracao.o: modelChecking/Configuracao.cpp
$(CC) $(CFLAGS) $< -o $#
modelChecking/Estado.o: modelChecking/Estado.cpp
$(CC) $(CFLAGS) $< -o $#
...
...and so on.
As you can see, I have different directories to compile my executable.
Now, I want to put every file .o in the bin/ folder and the variable OBJECT must replace the every parent directory, and I tried different ways:
OBJECTS=$(SUFIX:%/ = bin/)
OBJECTS=$(subst %/,bin/,$(SUFIX))
OBJECTS=$(patsubst %/,bin/,$(SUFIX))
When I use something like this $(subst home/,bin/,$(SUFIX)) it works, because I type the substring "home/", but I need of a regular expression to replace all directories.
And I'll need to change the target too, perhaps the code below will works:
%.o: %.cpp
$(CC) $(CFLAGS) $< -o $#
... But I prefer every target separate
You are looking for SUFIX=$(addprefix bin/,$(notdir $(SOURCES:.cpp=.o)))
The Makefile will look like:
SOURCES=home/main.cpp modelChecking/Configuracao.cpp
SUFIX=$(addprefix bin/,$(notdir $(SOURCES:.cpp=.o)))
OBJECTS=$(SUFIX)
all: refiner
refiner: $(OBJECTS)
$(CC) $^ -o refiner
bin/main.o: home/main.cpp
$(CC) $(CFLAGS) -c $< -o $#
bin/Configuracao.o: modelChecking/Configuracao.cpp
$(CC) $(CFLAGS) -c $< -o $#
However I suggest to use SUBDIRS instead. Create to Makefiles
Makefile
SUBDIRS = bin
.PHONY: subdirs $(SUBDIRS)
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $#
bin/Makefile
SOURCES=../home/main.cpp ../modelChecking/Configuracao.cpp
SUFIX=$(addprefix bin/,$(notdir $(SOURCES:.cpp=.o)))
OBJECTS=$(SUFIX)
all: refiner
refiner: $(OBJECTS)
$(CC) $^ -o refiner
main.o: ../home/main.cpp
$(CC) $(CFLAGS) -c $< -o $#
Configuracao.o: ../modelChecking/Configuracao.cpp
$(CC) $(CFLAGS) -c $< -o $#
This way you will not have to worry about object prefix.

Out-of-tree build makefile without automake?

Consider the following dead-simple Makefile:
foo: foo.c
$(CC) $(CFLAGS) -o $# $<
And the following directory structure for ~/foo:
Makefile
foo.c
How can I adjust the Makefile such that I can do something like:
/tmp$ make -f ~/foo/Makefile
cc -o foo /home/me/foo/foo.c
I have tried to use $(srcdir), but that seems automake-specific. Is there any other similar variable?
This will do it:
foo: /home/me/foo/foo.c
$(CC) $(CFLAGS) -o $# $<
Or this:
foo: foo.c
$(CC) $(CFLAGS) -o $# $<
vpath %.c /home/me/foo
Or, if you don't want to hard-code the path into the makefile:
foo: foo.c
$(CC) $(CFLAGS) -o $# $<
vpath %.c $(dir $(lastword $(MAKEFILE_LIST)))

Resources