I have this sample (siimplified) makefile
all: a a.e b b.e
.SUFFIXES:
a a.e:
touch $#
b: a
ln -sf $(notdir $<) $#
b.e: a.e
ln -sf $(notdir $<) $#
clean:
rm -f a* b*
and it works.
I would like to use Pattern Rules as follow:
all: a a.e b b.e
.SUFFIXES:
a a.e:
touch $#
b%: a%
ln -sf $(notdir $<) $#
clean:
rm -f a* b*
but it fails:
$ make
touch a
touch a.e
make: *** No rule to make target 'b', needed by 'all'. Stop.
I cannot figure out why, and I don't know how to make it works
Does this info from the manual give you your answer:
The target is a pattern for matching file names; the ‘%’ matches any nonempty substring, while other characters match only themselves.
(emphasis added)?
Related
I have a circular dependency using make:
CC = gcc
IFLAGS = -Iinclude
CFLAGS = -Wall -g -c -fPIC -pedantic
AFLAGS = -shared
LFLAGS =
VERSION = $(shell cat desc/major).$(shell cat desc/minor).$(shell cat desc/patch)
DFLAGS = -D_XOPEN_SOURCE=700 -DLTKVER=\"$(VERSION)\"
OBJECTS = $(patsubst src/%.c,tmp/%.o, $(shell ls -1 src/*.c))
#OUTPUT = tmp/$(lastword $(subst /, ,$(shell pwd)))
OUT_BIN = install/usr/lib/libLTK.so
OUT_MAN = $(patsubst man/%,install/usr/share/man/%.gz, $(shell find man -type f))
PATH_INCLUDE = install/usr/include/LTK-$(VERSION)
OUT_INCLUDE = $(patsubst %,$(PATH_INCLUDE)/%, $(shell find include -type f -printf "%f\n"))
PC = %
all: $(OUT_BIN) $(OUT_MAN) $(OUT_INCLUDE)
# chmod 755 install/usr/lib/libLTK.so.$(VERSION)
ln -sf install/usr/lib/libLTK.so.$(VERSION) install/usr/lib/libLTK.so
# chmod 755 install/usr/include/LTK-$(VERSION)
# chmod 644 install/usr/include/LTK-$(VERSION)/*
ln -sf install/usr/include/LTK-$(VERSION) install/usr/include/LTK
$(OUT_BIN): $(OBJECTS)
mkdir -p $(shell dirname $#)
$(CC) $(AFLAGS) -o $#.$(VERSION) $^ $(LFLAGS)
tmp/%.o : src/%.c
mkdir -p $(shell dirname $#)
$(CC) $(CFLAGS) -o $# $< $(DFLAGS) $(IFLAGS)
install/usr/share/%.gz : %
mkdir -p $(shell dirname $#)
gzip -c $< > $#
.SECONDEXPANSION:
%.h : $$(patsubst $(PATH_INCLUDE)/$$(PC),include/$$(PC),$$#)
mkdir -p $(shell dirname $$#)
cp $< $$#
clean:
rm -rf tmp install
At second expansion header files, prerequisites are generated from second expansions.
But it's a header that generates another and this new one can be found on the disk.
But make rather prefers to consider a circular dependency and ignore it.
How can I force make to see that the file exists before it searches a target to generate it?
Circular dependences are completely independent of what exists on the disk or doesn't exist on the disk. When make runs it parses the makefile and constructs a graph representing the dependency relationship between targets. This graph must be acyclic, because make will walk the graph looking for whether targets are out of date. If there's a cycle in the graph, then make would recurse forever trying to walk the graph.
For example:
a: b ; touch $#
b: a ; touch $#
It doesn't matter whether these files exist or not: make still needs to be sure that "a" is newer than "b" to satisfy the first dependency, and that "b" is newer than "a" to satisfy the second dependency.
This cannot ever be true, obviously.
Finally resolved by substituing $(OUT_INCLUDE) to %.h.
The goal to auto copy include files is preserved.
Substitued this:
.SECONDEXPANSION:
$(OUT_INCLUDE) : $$(patsubst $(PATH_INCLUDE)/$$(PERCENT),include/$$(PERCENT),$$#)
mkdir -p $(shell dirname $#)
cp $< $#
For this:
.SECONDEXPANSION:
%.h : $$(patsubst $(PATH_INCLUDE)/$$(PC),include/$$(PC),$$#)
mkdir -p $(shell dirname $$#)
cp $< $$#
But I'm still asking myself on "is there anything to force file before dependency".
After looking at the code it looks like no, unless I omit something.
I have this makefile code:
$(DIRS):
#echo " MKDIR build/tmp/base/socket/$#"
$(Q)mkdir -p $#/
%.a.s:
#echo " CC build/tmp/base/socket/$#"
$(Q)$(CC) $(CFLAGS_A) -S $< -o $#
%.so.s:
#echo " CC build/tmp/base/socket/$#"
$(Q)$(CC) $(CFLAGS_SO) -S $< -o $#
%.o: %.s
#echo " AS build/tmp/base/socket/$#"
$(Q)$(AS) $< -o $#
tcp/client.a.s: $(TCP_CLIENT_SRC) $(TCP_CLIENT_INC)
tcp/client.so.s: $(TCP_CLIENT_SRC) $(TCP_CLIENT_INC)
tcp/server.a.s: $(TCP_SERVER_SRC) $(TCP_SERVER_INC)
tcp/server.so.s: $(TCP_SERVER_SRC) $(TCP_SERVER_INC)
I'd like to add a | tcp in the prerequisites of all targets that have a leading tcp/ in their name, but I'd like to be able to do it in one line. I wouldn't want to append that manually to every line that needs it.
I thought of adding this new rule:
tcp/%.s: | tcp
but it isn't doing anything.
I also thought of the more generic, which would be nicer, but same results:
%.s: | $(#D)
How should I write that?
A workaround would be to call mkdir every time (include it in both %.a.s and %.so.s rules), but that would add unnecessary calls to mkdir, wouldn't it?
I am not a fan of pattern rules. They are too arbitrary for my tastes.
(What actually happens depends on what files you may have lying around on your hard disk.)
You cannot just add a prerequisite to a given set of targets using a pattern rule
Well you can if you use static pattern rules. This is a much nicer idiom. Here we prefix a pattern rule with the actual list of sources you want the pattern rule to apply to. This is good where you can describe dependencies using make's noddy pattern matching.
A sketch:
%.a: ; date >$# # Pattern rule
tcp: ; mkdir -p $# # Explicit rule
tcp/a.a: tcp/%.a: | tcp ; # Static pattern rule!
.PHONY: all
all: tcp/a.a
all: c.a
all: dir/b.a
all: ; : $# Success
And we have:
$ make all
mkdir -p tcp
date >tcp/a.a
date >c.a
date >dir/b.a
/bin/sh: dir/b.a: No such file or directory
make: *** [Makefile:3: dir/b.a] Error 1
Here we have told make that before it builds (i.e., "runs the recipe for") tcp/a.a, it must first build tcp. That works. We didn't tell make about the directory for dir/b.a, so that failed. Note that the .a file's recipe is still in an ordinary pattern rule. This is just by way of exposition. I would definitely change this.
Yeah, in this case the pattern rule for tcp/ is over-the-top. Consider though that before you create tcp/a.a, you might first need to create a auto/a.src (say).
tcp/a.a: tcp/%.a: auto/%.src | tcp ; # Static pattern rule!
Easily extensible.
targets := tcp/a.a tcp/b.a tcp/c.a
${targets}: tcp/%.a: auto/%.src | tcp ; # Static pattern rule!
[By the way, in your original makefile, your archive and shared object should depend on the .o files, not the source (???)]
You cannot just add a prerequisite to a given set of targets using a pattern rule. That's not how pattern rules work: they are rules: they must have a recipe associated with them. A pattern rule without a recipe actually deletes that pattern rule (see Canceling Implicit Rules).
You can either create two sets of pattern rules, one for all targets and a second one for just targets that start with tcp/ that have an extra prerequisite, but you have to write the entire pattern rule twice, including a recipe, not just the pattern line.
Or just put the mkdir into the recipe. A mkdir on a directory that already exists won't even be noticeable.
This answer is only to show a working Makefile implementing #bobbogo 's answer.
This Makefile is a leaf of a Makefile tree, so all variables not defined here are exported by upper Makefiles.
Makefile:
#! /usr/bin/make -f
################################################################################
# *AUTHOR*
# FULL NAME "Alejandro Colomar Andrés"
################################################################################
################################################################################
DIRS = \
$(CURDIR)/tcp
OBJ = \
$(CURDIR)/tcp/client.o \
$(CURDIR)/tcp/server.o \
$(CURDIR)/foo.o
SRC = \
$(SRC_DIR)/base/socket/tcp/client.c \
$(SRC_DIR)/base/socket/tcp/server.c \
$(SRC_DIR)/base/socket/foo.c
DEP = $(OBJ:.o=.d)
BOTH_OBJ = $(subst .a.o,.a.o ,$(join $(OBJ:.o=.a.o),$(OBJ:.o=.so.o)))
BOTH_ASM = $(subst .a.s,.a.s ,$(join $(OBJ:.o=.a.s),$(OBJ:.o=.so.s)))
NEEDDIR = $(DEP) $(BOTH_ASM)
################################################################################
PHONY := all
all: $(BOTH_OBJ)
#:
$(DIRS): $(CURDIR)/%:
#echo " MKDIR build/tmp/base/socket/$*"
$(Q)mkdir -p $#
$(NEEDDIR): | $(DIRS)
$(CURDIR)/%.d: $(SRC_DIR)/base/socket/%.c
#echo " CC -M build/tmp/base/socket/$*.d"
$(Q)$(CC) $(CFLAGS_A) -MG -MT"$#" \
-MT"$(CURDIR)/$*.a.s" -MT"$(CURDIR)/$*.so.s" \
-M $< -MF $#
$(CURDIR)/%.a.s: $(SRC_DIR)/base/socket/%.c $(CURDIR)/%.d
#echo " CC build/tmp/base/socket/$*.a.s"
$(Q)$(CC) $(CFLAGS_A) -S $< -o $#
$(CURDIR)/%.so.s: $(SRC_DIR)/base/socket/%.c $(CURDIR)/%.d
#echo " CC build/tmp/base/socket/$*.so.s"
$(Q)$(CC) $(CFLAGS_SO) -S $< -o $#
$(CURDIR)/%.o: $(CURDIR)/%.s
#echo " AS build/tmp/base/socket/$*.o"
$(Q)$(AS) $< -o $#
include $(DEP)
PHONY += clean
clean:
$(Q)rm -rf *.o *.s *.d
################################################################################
# Declare the contents of the PHONY variable as phony.
.PHONY: $(PHONY)
################################################################################
######## End of file ###########################################################
################################################################################
output:
MKDIR build/tmp/base/socket/tcp
CC -M build/tmp/base/socket/foo.d
CC -M build/tmp/base/socket/tcp/server.d
CC -M build/tmp/base/socket/tcp/client.d
CC build/tmp/base/socket/tcp/client.a.s
AS build/tmp/base/socket/tcp/client.a.o
CC build/tmp/base/socket/tcp/client.so.s
AS build/tmp/base/socket/tcp/client.so.o
CC build/tmp/base/socket/tcp/server.a.s
AS build/tmp/base/socket/tcp/server.a.o
CC build/tmp/base/socket/tcp/server.so.s
AS build/tmp/base/socket/tcp/server.so.o
CC build/tmp/base/socket/foo.a.s
AS build/tmp/base/socket/foo.a.o
CC build/tmp/base/socket/foo.so.s
AS build/tmp/base/socket/foo.so.o
I'm want to have .h files to be included as my dependencies for a given .o file. I followed these instructions and adapted them to my Makefile. However when I do touch myhfile.h a corresponding .o file is not rebuilt. It seems to me dependencies are correct and are included into the Makefile. Just can't figure out why it is not working. Any help is appreciated. Makefile is included below
ROOT=.
BUILDDIR=$(ROOT)/build
LIBDIR=$(BUILDDIR)/lib
OBJDIR=$(BUILDDIR)/obj
INCLUDEDIR=$(BUILDDIR)/include
DEPDIR=$(BUILDDIR)/dep
LIB=mylib
XCOMPILE=arm-linux-gnueabihf-
CC=$(XCOMPILE)gcc
AR=$(XCOMPILE)ar
DEPFLAGS+=\
-MT $# \
-MMD \
-MP \
-MF \
$(DEPDIR)/$*.Td
CFLAGS+=\
-Wall \
-Wextra \
-Werror \
-pedantic \
-std=gnu11 \
-fPIC
CPPFLAGS+=\
$(INCLUDE)
SRCDIRS+=\
$(ROOT)/../3rdparty/log/src \
$(ROOT)/LTC2947/src \
$(ROOT)/i2c/src \
$(ROOT)/spi/src \
$(ROOT)/sensors/src \
$(ROOT)/telegraf/src \
$(ROOT)/uart-packet/src \
$(ROOT)/STCN75/src \
$(ROOT)/utils/src
DEPDIRS+=\
$(SRCDIRS) \
$(ROOT)/addresses-ports/src
VPATH+=\
$(SRCDIRS)
SRC+=$(shell find $(SRCDIRS) -type f -name "*\.c")
DEP+=$(shell find $(DEPDIRS) -type f -name "*\.h")
OBJ=$(patsubst %.c, $(OBJDIR)/%.o, $(notdir $(SRC)))
INCLUDE=$(addprefix -I,$(sort $(dir $(DEP))))
POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $#
release: CFLAGS+=-O3
release: all
debug: CFLAGS+=-ggdb
debug: CPPFLAGS+=-DDEBUG
debug: all
all: lib include
lib: $(LIBDIR)/$(LIB).a $(LIBDIR)/$(LIB).so
include: $(INCLUDEDIR)
$(LIBDIR)/$(LIB).a: $(OBJ) | $(LIBDIR)
$(AR) rcs $# $^
$(LIBDIR)/$(LIB).so: $(OBJ) | $(LIBDIR)
$(CC) $(CPPFLAGS) $(CFLAGS) -shared $(LDFLAGS) -lc $^ -o $#
$(INCLUDEDIR): $(DEP)
if [[ ! -d $# ]]; then mkdir -p $#; fi
cp $^ $#
touch $#
%.o: %.c
$(OBJDIR)/%.o: %.c $(DEPDIR)/%.d | $(DEPDIR) $(OBJDIR)
$(CC) $(DEPFLAGS) $(CFLAGS) $(CPPFLAGS) -c $< -o $#
$(POSTCOMPILE)
$(DEPDIR):
mkdir -p $#
$(LIBDIR):
mkdir -p $#
$(OBJDIR):
mkdir -p $#
.PHONY: clean
clean:
rm -rf $(BUILDDIR)
$(DEPDIR)/%.d: ;
.PRECIOUS: $(DEPDIR)/%.d
include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC))))
EDIT
$(info $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC))))) produced an empty string. $(info $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC)))) produced a right list of dependencies
./build/dep/./../3rdparty/log/src/log.d ./build/dep/./uart-packet/src/uart_packet.d ./build/dep/./utils/src/utils.d ./build/dep/./telegraf/src/telegraf.d ./build/dep/./i2c/src/myproject_i2c.d ./build/dep/./spi/src/myproject_spi.d ./build/dep/./LTC2947/src/LTC2947.d ./build/dep/./sensors/src/sensors.d ./build/dep/./STCN75/src/STCN75.d
So I removed $(wildcard ...) function
However that didn't solve the problem.
To test the it I decided to run:
1. make clean
2. make
3. touch telegraf/src/telegraf.h
4. make build/obj/telegraf.d
5. make build/obj/telegraf.Td
6. make build/obj/telegraf.o
Steps 1-3 worked fine. However steps 4-6 didn't work.
Step 4 produced a following result:
make: *** No rule to make target 'buid/dep/telegraf.d'. Stop.
Step 5 produced a following result:
make: *** No rule to make target 'buid/dep/telegraf.Td'. Stop.
Step 6 simply didn't rebuild the target.
I took a look at build/dep/telegraf.d after step 2 and here is what I have there:
$ cat build/dep/telegraf.d
build/obj/telegraf.o: telegraf/src/telegraf.c ../3rdparty/log/src/log.h \
telegraf/src/telegraf.h utils/src/utils.h
../3rdparty/log/src/log.h:
telegraf/src/telegraf.h:
utils/src/utils.h:
It seems to me dependencies are generated correctly.
I also tried running make -d build/obj/telegraf.o. Unfortunately I can't post a whole output for it (stackoverflow won't allow it, message becomes to large). But here is the end of the output. (For those who are interested, full output can be seen here)
No need to remake target 'telegraf.c'; using VPATH name './telegraf/src/telegraf.c'.
Considering target file 'build/dep/telegraf.d'.
Looking for an implicit rule for 'build/dep/telegraf.d'.
Trying pattern rule with stem 'telegraf'.
Found an implicit rule for 'build/dep/telegraf.d'.
Finished prerequisites of target file 'build/dep/telegraf.d'.
No need to remake target 'build/dep/telegraf.d'.
Considering target file 'build/dep'.
Finished prerequisites of target file 'build/dep'.
No need to remake target 'build/dep'.
Considering target file 'build/obj'.
Finished prerequisites of target file 'build/obj'.
No need to remake target 'build/obj'.
Finished prerequisites of target file 'build/obj/telegraf.o'.
Prerequisite './telegraf/src/telegraf.c' is older than target 'build/obj/telegraf.o'.
Prerequisite 'build/dep/telegraf.d' is older than target 'build/obj/telegraf.o'.
Prerequisite 'build/dep' is order-only for target 'build/obj/telegraf.o'.
Prerequisite 'build/obj' is order-only for target 'build/obj/telegraf.o'.
No need to remake target 'build/obj/telegraf.o'.
make: 'build/obj/telegraf.o' is up to date.
It looks to that this line is the issue, Prerequisite 'build/dep/telegraf.d' is older than target 'build/obj/telegraf.o'.. Somehow I need to make it younger but I'm not sure how.
Any help is appreciated.
Unfortunately you've gone running off in the wrong direction here :).
You should not have removed the $(wildcard ...); that is needed/wanted.
The fact that it returned the empty string is THE problem you're having and rather than just remove it you needed to figure out why and fix it. The fact that your .d files look like ./build/dep/./../3rdparty/log/src/log.d is the problem... that is NOT the path to the .d files you are creating. You are creating files like ./build/dep/log.d
The problem is this: you are creating .d files in the recipe using this rule:
POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $#
Here, $* is the stem of the file so for ./build/obj/log.o the value of $* will be log. So you are creating ./build/dep/log.d.
But when you convert your SRC variable to .d files in the include line, you use the basename function. This merely strips off the suffix of the path, it doesn't remove the directory. So if your source file is ./../3rdparty/log/src/log.c then basename yields ./../3rdparty/log/src/log and your wildcard matches the wrong thing.
You need to compute your wildcard for your include line like this:
include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(notdir $(basename $(SRC)))))
Adding the notdir to strip out the paths, as well, will give you the dependency file you want: ./build/dep/log.d etc.
Pattern rules work:
$ ls
Makefile hello.txt world.txt
$ cat Makefile
all: hello.out world.out
%.out: %.txt
cp $< $#
$ make
cp hello.txt hello.out
cp world.txt world.out
However, when I try to replace them with what I think is the exact equivalent suffix rules, they don't work:
$ ls
Makefile hello.txt world.txt
$ cat Makefile
.POSIX:
.SUFFIXES:
.SUFFIXES:.txt.out
all: hello.out world.out
.txt.out:
cp $< $#
$ make
make: *** No rule to make target 'hello.out', needed by 'all'. Stop.
I don't understand why.
This line is the problem:
.SUFFIXES: .txt.out
It declares a single suffix, .txt.out, not two of them. You can change it to this:
.SUFFIXES: .txt .out
Let's consider this tiny example. Everything should work fine without the VILLAIN. Actually this word leads to an error but not where I was expecting it...
The error:
$ make
mkdir -p obj
zip out.exe obj/foo.o obj/bar.o obj/baz.o
zip warning: name not matched: obj/foo.o
zip warning: name not matched: obj/bar.o
zip warning: name not matched: obj/baz.o
zip error: Nothing to do! (out.exe)
Makefile:9: recipe for target 'out.exe' failed
make: *** [out.exe] Error 12
It seems make wants to go a bit too fast by executing a recipe where its dependencies are not already made (obj/foo.o ...). Actually I was expecting an error like: "Unable to find VILLAIN to make obj/foo.o"
The Makefile:
#!/usr/bin/env make
SRCDIR = src
OBJDIR = obj
SRC = $(addsuffix .c,foo bar baz)
OBJ = $(addprefix $(OBJDIR)/, $(notdir $(SRC:c=o)))
out.exe: $(OBJ)
zip $# $^
$(OBJDIR)/%.o: $(SRCDIR)/%.c VILLAIN
cp $< $#
$(OBJ) : | $(OBJDIR)
$(OBJDIR):
mkdir -p $#
clean:
rm -f *.c
rm -rf $(OBJDIR)/ $(SRCDIR)/
mkdir -p $(SRCDIR)/
touch $(addprefix $(SRCDIR)/,$(SRC))
However if I remove the villain everything works fine:
$ make clean
rm -f *.c
rm -rf obj/ src/
mkdir -p src/
touch src/foo.c src/bar.c src/baz.c
$ make
mkdir -p obj
cp src/foo.c obj/foo.o
cp src/bar.c obj/bar.o
cp src/baz.c obj/baz.o
zip out.exe obj/foo.o obj/bar.o obj/baz.o
adding: obj/foo.o (stored 0%)
adding: obj/bar.o (stored 0%)
adding: obj/baz.o (stored 0%)
Why make try to make a target before building its prerequisite?
Pattern rules don't work like explicit rules in this respect. There can be many, many different pattern rules that could be used to create the same target (consider, a .o can be created from a C source file, C++ source file, FORTRAN source file, etc. etc.)
So, when make tries to find a pattern rule to build a target, in order to decide whether the pattern matches or not make will try to build all the prerequisites. If one of the prerequisites cannot be built, then it is not an error! Make simply goes on to the next pattern rule that matches and tries that. So the fact that VILLIAN doesn't exist and can't be built, just means that make will never select this pattern rule because the prerequisites cannot be satisfied... but this is not an error and no message will be printed (well, if you look at make's debug output you'll see a note about it).
So make will discover it has no rules that know how to build obj/foo.o. You'd expect to get an error at that point... but you won't because you've added this rule:
$(OBJ) : | $(OBJDIR)
By doing this you've declared obj/foo.o to be a target that make knows about and so it won't complain if the target doesn't exist. If you change this to add the order-only prerequisite into the pattern rule, then you'll get more comprehensible behavior:
$(OBJDIR)/%.o: $(SRCDIR)/%.c VILLAIN | $(OBJDIR)
cp $< $#
$(OBJDIR):
mkdir -p $#
Gives:
make: *** No rule to make target 'obj/foo.o', needed by 'out.exe'. Stop.