Makefile multiple targets from same source file, with different flags - makefile

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

Related

How to make N .o files from N .c files using makefile?

I have 2 .c files that defined in the makefile:
SOURCES = main.c \
memory.c
and I want to build 2 .o files using 1 command "make compile-all" (and don't link them), but can't understand how to do this.
I could create var for objective files and add .PHONY command:
OBJS=$(SOURCES:.c=.o)
.PHONY: compile-all
But what should be written next?
I guess it should be something similar with this:
%.o: %.c $(INCLUDES)
$(CC) -c $< $(CFLAGS) -o $#
But there's no way I can succeed.
Thank you in advance!
BASENAME := main
TARGET := $(BASENAME).out
OBJS=$(SOURCES:.c=.o)
%.i: %.c
$(CC) -E $< $(CFLAGS) -o $#
%.asm: %.c
$(CC) -S $< $(CFLAGS) -o $#
%.o: %.c
$(CC) -c $< $(CFLAGS) -o $#
.PHONY: build
build:$(TARGET)
$(TARGET): $(OBJS)
$(CC) $(OBJS) $(CFLAGS) $(PLATFORM_FLAGS) $(LDFLAGS) -o $#
.PHONY: clean
clean:
rm -f $(OBJS) $(TARGET) *.i *.asm $(BASENAME).map
.PHONY: compile-all
compile-all: $(OBJS)
make compile-all creates .o files from all .c files.

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.

Makefile does not work properly

I've this folder structure
project
|_src
| |_test
| |_main.cpp
|_Makefile
This is my makefile (trying to adapt from this link):
CC = g++
RM = rm
WFLAGS = -c -Wall -W
LDFLAGS =
SRCTESTD = src/test
EXECUTABLE = test
OBJD = .obj
DEPD = .dep
SRCSTEST = $(SRCTESTD)/main.cpp
OBJECTSTEST = $(patsubst %.cpp, $(OBJD)/test/%.o, $(notdir $(SRCSTEST)))
DEPDSTEST = $(patsubst %.cpp, $(DEPD)/test/%.d, $(notdir $(SRCSTEST)))
all: $(SRCSTEST) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTSTEST)
$(CC) $(LDFLAGS) $(OBJECTSTEST) -o $#
.cpp.o:
$(CC) $(WFLAGS) $< -o $#
It does not work, and I've this error
make: *** No rule to make target `.obj/test/main.o', needed by `test'. Stop.
What I'm doing wrong? Sorry for trivial question, but I'm a make newbie.
The link shows outdated methods, such as suffix rules. Making dependencies can also be done during compilation by gcc/g++.
As for the rest, here is it :
EXE := test
SRCDIR := src
OBJDIR := .obj
SRC := $(shell find $(SRCDIR) -name "*.cpp")
OBJ := $(SRC:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEP := $(OBJ:.o=.d)
LDLIBS := # -l flags
LDFLAGS := # -L flags
CPPFLAGS := -MMD -MP # -I flags also
CXXFLAGS := -W -Wall # no -c flag here
.PHONY: all clean fclean re
all: $(EXE)
clean:
$(RM) -r $(OBJDIR)
fclean: clean
$(RM) $(EXE)
re: fclean all
-include $(DEP)
$(EXE): $(OBJ)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
No redefinition of internally defined variables, no suffix rules, correct linking step and dependencies generation.
Update: To avoid calling mkdir for every source file, one should use order-only prerequisites and the special target .SECONDEXPANSION.
Change this block:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
To this:
.SECONDEXPANSION:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp | $$(#D)/
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
%/:
mkdir $*
The error means make can't find a correct rule to build your object files. Your tree structure lacks some informations: only one file ? Where are the others ? Anyway, here are some hints:
In the last two lines, you are using an obsolete feature of make: suffix rules. I suggest you switch to a pattern rule, which is functionaly equivalent.
Say something like:
%.o: %.cpp
$(CXX) $(CXXFLAGS) $< -o $#
Another thing (that shouldn't be a problem here): you are using the variable CC which is internally defined as the default C compiler. It's okay because you redefine it, but as your sources seem to be C++ files, why not use the variable CXX, that is internally defined as the C++ compiler ?
Lastly, to make sure your set of files are correctly defined, you can print them with a dummy show target, see here.
show:
#echo "OBJECTSTEST=$(OBJECTSTEST)"
...

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.

Resources