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

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)

Related

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 $# $<

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.

Makefile: Same Rule for multiple Targets

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.

multiple targets build in makefile

Any idea why something like this wouldnt work in makefile ?
all : $(GOAL_DB) $(GOAL)
%.d: %.cpp
$(CC) $(CPPFLAGS_DB) $< > $#
%.o : %.cpp
$(CC) $(FLAGS_DB) $< -o $#
$(GOAL_DB) : $(OFILES)
$(CC) $(LFLAGS_DB) -o $# $^ $(LIBS_DB)
strip $(GOAL_DB)
rm -f *.o *.d
%.d: %.cpp
$(CC) $(CPPFLAGS) $< > $#
%.o : %.cpp
$(CC) $(FLAGS) $< -o $#
$(GOAL) : $(OFILES)
$(CC) $(LFLAGS) -o $# $^ $(LIBS)
strip $(GOAL)
rm -f *.o *.d
I'm just trying to build two different targets using make all , GNU make.
The first target builds fine , but it not creating new objects files for another target.
A makefile is not like a standard program that is executed sequentially. It seems you've made the assumption that new rules appearing before a new target will apply to that target. This is not the case. The makefile is fully evaluated for variables, targets, dependencies, and more, before it starts applying rules.
Make is going to match those $(OFILES) against only one of those %.d: targets, probably the first target pattern it finds.
The reason you are not getting new objects for the other target is that to make it looks like you are building the same set of files twice, thus skipping the second build because it's already complete.
A solution is to use 'target specific variables':
all : $(GOAL_DB) $(GOAL)
$(GOAL): BUILD_FLAGS=$(FLAGS)
$(GOAL): BUILD_CPPFLAGS=$(CPPFLAGS)
$(GOAL): BUILD_OUTDIR=./outdir
$(GOAL): $(OFILES)
$(GOAL_DB): BUILD_FLAGS=$(FLAGS_DB)
$(GOAL_DB): BUILD_CPPFLAGS=$(CPPFLAGS_DB)
$(GOAL_DB): BUILD_OUTDIR=./outdir_db
$(GOAL_DB): $(OFILES)
%.d: %.cpp
mkdir -p $(BUILD_OUTDIR)
$(CC) $(BUILD_CPPFLAGS) $< > $(BUILD_OUTDIR)/$#
%.o : %.cpp
mkdir -p $(BUILD_OUTDIR)
$(CC) $(BUILD_FLAGS) $< -o $(BUILD_OUTDIR)/$#

Want to place all .o files into a directory, but make stops after compilng fist one

I want to have a neat makefile containing explicit dependencies but placing all .o objects in a separate directory to link it altogether later (in an another file).
The problem is that my make stops after compiling the first source and then stops with no error whatsoever.
CC=gcc
CFLAGS=-c -Wall -pedantic -std=c99
DIR=../obj
$(DIR)/CList.o : CList.c CList.h CList_aux.h Observation.h CList_View_aux.h
$(CC) $(CFLAGS) CList.c -o $#
$(DIR)/CList_aux.o : CList_aux.c CList.h CNode.h
$(CC) $(CFLAGS) CList_aux.c -o $#
$(DIR)/CList_View_aux.o : CList_View_aux.c CNode.h Observation.h
$(CC) $(CFLAGS) CList_View_aux.c -o $#
$(DIR)/CNode.o : CNode.c CNode.h CNode_aux.h Observation.h CList.h
$(CC) $(CFLAGS) CNode.c -o $#
$(DIR)/CNode_aux.o : CNode_aux.c CNode.h Observation.h
$(CC) $(CFLAGS) CNode_aux.c -o $#
$(DIR)/Observation.o : Observation.c Observation.h Observation_aux.h CNode.h
$(CC) $(CFLAGS) Observation.c -o $#
$(DIR)/Observation_aux.o : Observation.c Observation.h
$(CC) $(CFLAGS) Observation_aux.c -o $#
$(DIR)/Record.o : Record.c Record.h Observation.h
$(CC) $(CFLAGS) Record.c -o $#
By default, make builds the first target in the makefile. In this case, that is ${DIR}/CList.o.
You need a different first target, conventionally called all:
OBJECTS = \
$(DIR)/CList.o \
$(DIR)/CList_aux.o \
$(DIR)/CList_View_aux.o \
$(DIR)/CNode.o \
$(DIR)/CNode_aux.o \
$(DIR)/Observation.o \
$(DIR)/Observation_aux.o
all: ${OBJECTS}
Note that this works whether there are any object files in the ${DIR} or not; a wildcard looking for object files in the directory makes sure that those that have already been compiled once are up to date, but doesn't try building those which failed to compile previously, or simply aren't there.
If the Makefile is really just as much as you posted, then you're missing the all: rule. Without having an explicit all rule, make assumes that the first present rule is to be made, so it stops after that. In order to achieve what you want, add (append) this to the Makefile (change the final executable name respectively):
OBJECTS = $(wildcard $(DIR)/*.o)
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(LD) $(LDFLAGS) -o $# $^

Resources