Makefile same target but different dependencies - makefile

I have a bunch of fortran files that I'm trying to compile with a makefile, and part of the makefile looks like this
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.f | $(OBJ_DIR)
$(F90) -c -o $# $< $(FFLAGS) -J $(OBJ_DIR) -I $(OBJ_DIR)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.f90 | $(OBJ_DIR)
$(F90) -c -o $# $< $(FFLAGS) -J $(OBJ_DIR) -I $(OBJ_DIR)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.F90 | $(OBJ_DIR)
$(F90) -c -o $# $< $(FFLAGS) -J $(OBJ_DIR) -I $(OBJ_DIR)
A you can see, its pretty repetitive, as I have to compile *.f, *.f90 and *.F90, but the compilation command is exactly same for all of them. Is there any wat to merge all of them in a single rule?

No.
You could put the rule inside a variable like this:
COMPILE.f90 = $(F90) -c -o $# $< $(FFLAGS) -J $(OBJ_DIR) -I $(OBJ_DIR)
but you still have to write three rules, like this:
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.f | $(OBJ_DIR)
$(COMPILE.f90)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.f90 | $(OBJ_DIR)
$(COMPILE.f90)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.F90 | $(OBJ_DIR)
$(COMPILE.f90)
If you had lots and lots of these you could create a single rule then eval it multiple times:
define COMPILE.f90
$$(OBJ_DIR)/%.o: $$(SRC_DIR)/%.$(SUFFIX) | $$(OBJ_DIR)
$$(F90) -c -o $$# $$< $$(FFLAGS) -J $$(OBJ_DIR) -I $$(OBJ_DIR)
endef
$(foreach SUFFIX,f f90 F90,$(eval $(COMPILE.f90)))
but in my opinion it's not worth the extra complexity just for three rules.

Related

How to create rule for .o files from 2 different folders with .c files using makefile

I want to have the possibility to build output files from different folders depending on the command.
./source_files/ - folder with *.c files for make build2 and make unit_test commands.
./source_files/unit_test/ - folder with *.c files for make unit_testcommands
I have 2 commands:
this works - command make build2 should take files ./source_files/*.c, make ./build/*.o from them and create <name.a> library;
this doesn't work - command make unit_test should take files ./source_files/*.c and also ./source_files/unit_tests/*.c make ./build/*.o from them and create test.out file.
make unit_test generates the output:
make: *** No rule to make target 'build/test_main.o', needed by 'unit_test'. Stop.
I have 2 rules for *.o files. I guess I have to combine them into one, but I have no idea how to do that. Can you help me with it, please?
$(BUILDDIR)/%.o: $(SRCDIR)/%.c | $(BUILDDIR)
$(CC) -c $< $(INCLDIR) -o $#
$(BUILDDIR)/%.o: $(UNITSRCS)/%.c | $(BUILDDIR)
$(CC) -c $< $(INCLDIR) -o $#
makefile:
#Compiler flags
CC := gcc
INCLDIR := -I./includes
LIBS := -lcunit
#Directories and files
BUILDDIR := build
SRCDIR := source_files
SRCS := $(wildcard $(SRCDIR)/*.c)
OBJS := $(SRCS:$(SRCDIR)/%.c=$(BUILDDIR)/%.o)
UNITDIR := $(SRCDIR)/unit_tests
UNITSRCS := $(wildcard $(UNITDIR)/*.c)
UNITOBJS := $(UNITSRCS:$(UNITDIR)/%.c=$(BUILDDIR)/%.o)
STLIB := $(BUILDDIR)/libbinary_tree.a
$(BUILDDIR):
mkdir $(BUILDDIR)
$(BUILDDIR)/%.o: $(SRCDIR)/%.c | $(BUILDDIR)
$(CC) -c $< $(INCLDIR) -o $#
$(BUILDDIR)/%.o: $(UNITSRCS)/%.c | $(BUILDDIR)
$(CC) -c $< $(INCLDIR) -o $#
.PHONY: unit_test
unit_test: $(OBJS) $(UNITOBJS)
$(CC) $(OBJS) $(UNITOBJS) $(INCLDIR) $(LIBS) -o $(BUILDDIR)/test_main.out
.PHONY: build2
build2: $(OBJS)
ar -rcs $(STLIB) $(OBJS)
.PHONY: clean
clean:
rm -r $(BUILDDIR)
This rule is OK:
$(BUILDDIR)/%.o: $(SRCDIR)/%.c | $(BUILDDIR)
$(CC) -c $< $(INCLDIR) -o $#
But this rule is wrong:
$(BUILDDIR)/%.o: $(UNITSRCS)/%.c | $(BUILDDIR)
$(CC) -c $< $(INCLDIR) -o $#
Just as in the first rule, you want to have $(UNITDIR)/%.c not $(UNITSRCS)/%.c. After make expands the variable the latter will clearly be wrong.

Building A Dependency List with GCC and Make

There appear to be multiple weird ways to do this, and it combines a lot of things in make that I don't quite understand. My folder structure is as follows.
src
| - utils
| - utils.h
| - utils.c
| - buffer.c
| - json.c
| - middleware
| - middleware.h
| - middleware.c
| - server
| - etc
tests
| - utils.c
| - middleware.c
| - server.c
Every folder under src is a library. and all files under that folder comprise the library.
For every library there is a respective .c file, under the tests dir, which will become an executable that can run each of those tests.
Any library can depend on other libraries, so I want to ensure that with make, when I make a change, the dependency tree is rebuilt, and each library retested that has a modification in a dependent file.
Here is what I have tried. I am leaving out quite obvious or irrelevant things for brevity.
OBJS := $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(wildcard $(SRCDIR)/*/*.c))
INCS := $(patsubst $(SRCDIR)/%.h,$(INCDIR)/%.h,$(wildcard $(SRCDIR)/*/*.h))
IMMM := $(patsubst $(OBJDIR)/%.o,$(LIBDIR)/%.a,$(foreach LIB,$(LLIST),$(filter $(OBJDIR)/$(LIB)/$(LIB).o,$(OBJS))))
LIBS := $(foreach PRE,$(LLIST),$(subst $(PRE)/,lib,$(filter $(LIBDIR)/$(PRE)/$(PRE).a,$(IMMM))))
LINK := $(foreach LIB,$(LLIST),-l$(LIB))
TSTO := $(patsubst $(TSTDIR)/%.c,$(OBJDIR)/$(TSTDIR)/%.o, $(wildcard $(TSTDIR)/*.c))
TSTE := $(foreach LIB,$(LLIST),$(TGTDIR)/$(LIB).exe)
DEPS := $(OBJS:.o=.d)
DEPT := $(TSTO:.o=.d)
.PHONY: all
all: $(TGTDIR)/$(TGT)
$(TGTDIR)/$(TGT): $(LIBS) | tests
$(CC) -o $# bench/main.c $(LIBS)
tests: $(TSTE)
for test in $^ ; do \
chmod +x ./$${test} ; \
./$${test}; \
done
$(TSTE): $(TSTO) $(DEPT) | $(OBJS)
#mkdir -p $(#D)
$(CC) -o $# $(OBJS) $(filter $(OBJDIR)/$(TSTDIR)/$(basename $(notdir $#)).o, $(TSTO))
$(OBJDIR)/$(TSTDIR)/%.o: $(TSTDIR)/%.c
#mkdir -p $(#D)
$(CC) -o $# -c $<
$(OBJDIR)/$(TSTDIR)/%.d: $(TSTDIR)/%.c
#mkdir -p $(#D)
$(CC) -MM -MG $< $(CFLAGS)
$(LIBS): $(OBJS)
#mkdir -p $(#D)
$(AR) rcs $# $(filter $(subst lib,$(OBJDIR)/, $(basename $(notdir $#)))/%.o, $(OBJS))
$(OBJDIR)/%.o: $(SRCDIR)/%.c | folders
#mkdir -p $(#D)
$(CC) -o $# -c $<
$(OBJDIR)/%.d: $(SRCDIR)/%.c | folders
#mkdir -p $(#D)
$(CC) -MM -MG $< $(CFLAGS)
The output for deps and dept are:
deps => obj/middleware/middleware.d obj/utils/utils.d
dept => obj/tests/middleware.d obj/tests/utils.d
All of the test dependencies are getting listed correctly.
gcc -MM -MG tests/middleware.c -Wall -O0 -std=c11 -DDEBUG -g outputs
middleware.o: tests/middleware.c tests/../src/middleware/middleware.h
However, I don't see the bug, why my $(OBJDIR)/%.d `$(DEPS) dependencies are not being ran.
So,
I'm not sure what sed command I need to get the desired output from (CC) -MM -MG $< $(CFLAGS)
Do I need the -include: $(DEPS) and `-include: $(DEPT) where does that go?
Where is the bug not allowing $(DEPS) target to run?
Is there anything else I'm missing?

makefile parse target to define dependencies

I have source files in several directories and I want to compile them in a one unique temporary directory, currently I use this target to create my object files :
$(BUILD_DIR)/%.o :
#echo "Compiling $#"
$(VERBOSE) $(CC) $(CFLAGS) -c $(DEFINES) $(INCLUDES) -o $# $(shell echo "$(SOURCES)" | sed 's/ /\n/g' | sed -nr '/\/$(*F)\.c/p')
It is working well but when I modify a source file, the object one is not recompiled. So I have to add the source file to the dependencies.
But this target doesn't work :
$(BUILD_DIR)/%.o : $(shell echo "$(SOURCES)" | sed 's/ /\n/g' | sed -nr '/\/$(*F)\.c/p')
#echo "Compiling $#"
$(VERBOSE) $(CC) $(CFLAGS) -c $(DEFINES) $(INCLUDES) -o $# $^
Is there any way to use target name in dependencies ?
Assuming you are using GNU Make...
Use a pattern rule like:
obj/%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
to tell make that an object file obj/<name>.o is to be compiled from a source file
<name>.c
In conjunction with this, use the VPATH special variable
to inform make of directories in which it should look for any <name>.c, if it is not
in the current directory.
Also, add an order-only prerequisite
to the pattern rule to ensure that the directory (obj) to which your object files are compiled
exists when needed:
obj/%.o: %.c | obj
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
So for example, with project structure:
./
-- Makefile
-- aa/
-- main.c
-- bb/
-- foo.c
-- obj/ #<-- Compile object files in here
-- prog #<- program to be built
And:
Makefile
VPATH := aa:bb
SRCS := foo.c main.c
OBJS := $(addprefix obj/, $(SRCS:.c=.o))
.PHONY: all clean
all: prog
prog: $(OBJS)
$(CC) $(LDFLAGS) -o $# $^ $(LDLIBS)
obj/%.o: %.c | obj
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
obj:
mkdir $#
clean:
$(RM) $(OBJS) prog
the build runs like:
$ make
cc -c -o obj/foo.o bb/foo.c
cc -c -o obj/main.o aa/main.c
cc -o prog obj/foo.o obj/main.o

Makefile: match multiple pattern rules

I have a makefile like this:
EXT = .cc
BLD = .build
all: bin/analyses/test
bin/analyses/test: $(BLD)/object.o
.SECONDEXPANSION:
$(DEPS): $(BLD)/%.d: src/%$(EXT) | $(BLD)/$$(dir %)
$(CXX) $(CPPFLAGS) -MM -MT '$(#:.d=.o)' $< -MF $#
$(BLD)/%.o: | $(BLD)
$(CXX) $(CXXFLAGS) -c $(filter %$(EXT),$^) -o $#
bin/%: $(BLD)/%.o | $$(dir bin/%)
$(CXX) $(LDFLAGS) $(filter %.o,$^) -o $# $(LDLIBS)
bin/%/ $(BLD)/%/:
mkdir -p $#
If line 6 looks the way it is, then everything works. Both bin/analyses/test: and bin/%: rules are used. But if I change line 6 to
bin/analyses/%: $(BLD)/object.o
only the bin/%: rule gets picked up.
How can I make multiple pattern rules match for the same target?
First, Make sometimes removes trailing slashes from targets, which can cause some confusion. In this case it takes your rule bin/%/ $(BLD)/%/: ..., which you clearly intended for directories, and uses it for files, at least sometimes. It is easy enough to do without an explicit rule for directories, by using mkdir -p in other rules.
Second, Make doesn't combine pattern rules the way it does ordinary rules. It finds one pattern rule and uses that. In a relatively simple case like this, we can write a rule that will do what we want:
all: bin/analyses/test
$(BLD)/%.o:
mkdir -p $(dir $#)
$(CXX) $(CXXFLAGS) -c $^ -o $#
bin/analyses/%: $(BLD)/analyses/%.o $(BLD)/object.o
mkdir -p $(dir $#)
$(CXX) $(LDFLAGS) $^ -o $# $(LDLIBS)
bin/%: $(BLD)/%.o
mkdir -p $(dir $#)
$(CXX) $(LDFLAGS) $^ -o $# $(LDLIBS)
(There is some obvious redundancy in those last two rules which I don't see how to iron out without making the makefile less readable, but it works as intended.)

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

Resources