Autodependency generation in makefiles - gnu-make

I am trying to understand how autodependency is generated in makefiles in the given link, i cannot understand the following piece of code:
DEPDIR = .deps
df = $(DEPDIR)/$(*F)
SRCS = foo.c bar.c ...
%.o : %.c
#$(MAKEDEPEND); \
cp $(df).d $(df).P; \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(df).d >> $(df).P; \
rm -f $(df).d
$(COMPILE.c) -o $# $<
-include $(SRCS:%.c=$(DEPDIR)/%.P)
I got it from this link. I know it will generate dependency files but I am not able to understand what this line does:
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(df).d >> $(df).P; \
Can somebody please explain me this code, so many wildcards give me butterflies, i am new to makefiles.

That is a number of distinct commands so break it up.
-e 's/#.*//'
Delete everything that starts with a # (Comments? Pre-processor directives?)
-e 's/^[^:]*: *//'
Delete everything up to a : on any that has : it.
-e 's/ *\\$$//'
Delete line-continuation slashes (and spaces before them) from the end of lines.
-e '/^$$/ d'
Delete any blank lines.
-e 's/$$/ :/'
Add : to the end of every line.
This adds explicit targets for every listed dependency file so that make "knows" how to build them to avoid the "No rule to make target" errors. The reasoning here is explained in your link in an earlier section.
Briefly, this creates a .P file with the original prerequisites list, then adds targets to it by taking each line, removing any existing target information and any line continuation (\) characters, then adding a target separator (:) to the end. This works with the values for MAKEDEPEND I suggest below; it’s possible you will need to modify the translation for other dependency generators you might use.

This is not meant to be an answer to your actual question, but since you said you were new to GNU make, I think spreading the words that a simpler way to handle auto dependencies exists won't do any harm.
Nowadays compilers like GCC or Clang can do this for you while compiling your code !
Simply pass them a preprocessor flag:
# Preprocessor flags
CPPFLAGS += -MMD
And include the generated files into the Makefile:
-include $(wildcard *.d)
And you're done.
You can learn more about the preprocessor options here for GCC, Clang simply mirror these options.
A relatively good example lies here too.

Related

Makefile, iterate over dirs and exclude some

In a toplevel (unix, GNU) Makefile I want to iterate over a list of subdirs and execute tasks in there but exclude some of them. In this case exclude all subdirs starting with an underscore (_)
The following is working in iterating but ignores the exclusion regex. It still visits dir "_exclude".
In particular I think it ignores the "start of string" ^ (or it takes it literally). I have tried other regexes and they do work. Any idea how to fix that? Or indeed if you have any idea how to eliminate the shelling out or not using GNU makefile extensions?
SHELL=/bin/bash
EXCLUDE_DIRS_REGEX=^_
# later addition:
ALLMAKEFILES = $(shell find . -maxdepth 2 -type f -name Makefile)
SUBDIRS = $(filter-out ./,$(dir $(ALLMAKEFILES)))
all:
for dir in $(SUBDIRS); do \
if [[ "$$dir" =~ $(EXCLUDE_DIRS_REGEX) ]]; then continue; fi; \
make -C $$dir all; \
done
You have two problems to solve:
compute the list of target directories
call make in each of them
For the first one a mixture of make and shell functions or built-ins could be something like:
REGEX := ^_
ALLMAKEDIRS := $(patsubst %/,%,$(dir $(wildcard */Makefile)))
SUBDIRS := $(shell for d in $(ALLMAKEDIRS); \
do ! [[ "$$d" =~ $(REGEX) ]] && echo "$$d"; done)
I kept the REGEX just in case you have more complex regular expressions or you would like it to be easily modified. But of course if it is exactly ^_ and you never change it the following is simpler:
SUBDIRS := $(filter-out _%,$(patsubst %/,%,$(dir $(wildcard */Makefile))))
For the second one your approach is not very make-ish. A better approach would be to have one rule per subdirectory. The following is an example:
.PHONY: all $(SUBDIRS)
all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $# all
It has several advantages:
there is no need to loop over subdirectories in a complicated recipe, make will do it for you,
make can launch several jobs in parallel (see the -j option) and this will speed-up your build.
Note: calling make in a Makefile is not recommended. Prefer $(MAKE). See this section of the manual for the details.

How to define a rule with a recursive recipe in GNU make?

I want to call make files in subfolders from one top make file.
An example of my top make file that works looks like this, where buildPath is a parameter in to the make script:
.PHONY: testSystem
testSystem:
$(MAKE) all -C $(buildPath)/Test1Build
$(MAKE) all -C $(buildPath)/Test2Build
$(MAKE) all -C $(buildPath)/Test3Build
The problem with this solution is that I have to list all subfolders; Test1Build, Test2Build, Test3Build etc.
Is there a way (with make) to define this rule in such a way that the subfolders in the receipt are recursively found without having to list them all?
...or can I solve this problem in a totally different way?
All subfolders begins with Test and ends with Build as a pattern.
It's not hard at all. One simple way:
testSystem:
for d in $(buildPath)/*/.; do \
$(MAKE) all -C $$d; \
done
However, that has many problems. Much more reliable and robust will be this:
subdirs := $(wildcard $(buildPath)/*/.)
testSystem: $(subdirs)
$(subdirs):
$(MAKE) -C $# all
.PHONY: testSystem $(subdirs)
One caveat: if you use parallel make (-j) then you may run into problems with the second solution if the results of the subdirectories depend on each other. If they do then you'll have to declare these dependency relationships in your makefile:
$(buildPath)/foo/. : $(buildPath)/bar/.
etc.

Set a variable inside prerequisites or eval function

I have this code, and it works, but as you see I do the substitute three times, I would like to set a variable to the value, but with no success
$($(PKG)-py-valgrind-tests-status): $($(PKG)-swig-dlib)
$($(PKG)-py-valgrind-tests-status): $(OBJ_OUTPUT_DIR)%.valgrind_passed: %.py
#echo env $(PKG-TEST-HELPER-ENV) valgrind $(VALGRIND-FLAGS) --log-file=$(subst valgrind_passed,valgrind.log,$#) $(PYTHON_BIN) $< -v ; \
env $(PKG-TEST-HELPER-ENV) $(VALGRIND) $(VALGRIND-FLAGS) --log-file=$(subst valgrind_passed,valgrind.log,$#) $(PYTHON_BIN) $< -v \
|| (cat $(subst valgrind_passed,valgrind.log,$#); exit 1)
#touch $#
the problematic line $(subst valgrind_passed,valgrind.log,$#)
I tried:
$($(PKG)-py-valgrind-tests-status): LOG-FILE = $(subst valgrind_passed,valgrind.log,$#)
and
.SECONDEXPANSION:
$($(PKG)-py-valgrind-tests-status): LOG-FILE = $$(subst valgrind_passed,valgrind.log,$#)
and(inside the recipe)
$(eval LOG-FILE = $$(subst valgrind_passed,valgrind.log,$#))
but for all, if I write
--log-file=$(LOG-FILE)
log file come's up empty.
I have no more ideas on how to go forward,
appreciate the help, thanks!
Are you sure you're using GNU make? What version are you using (run make --version)?
There's nothing wrong with your first attempt, using a target-specific variable. If this doesn't work then you've got something wrong or different about your makefile that you haven't explained. Maybe if you showed the actual complete section of the makefile with the target-specific variable being set and used we might see what's wrong.
Your second attempt can't work because secondary expansion applies only the prerequisites, not target-specific variables (but, as above, it's not needed anyway).
Your third attempt might work but again, without seeing exactly what you do with the eval we can't say for sure. You don't need to double the $ before the subst function; it can be expanded first and it will still work.

Error in calling one make target from another

$make --- Will have normal build
$make CAdvisor
Above will do following steps:
1) Update variable CC, now it should become "cadvise -pdb mypdb +wlint +wall aCC"
2) Run all with updated CC option
CC = aCC
CFLAGS = -c #-Wall
LDFLAGS =
SOURCES = foo.cc
OBJECTS = $(SOURCES:.cc=.o)
EXECUTABLE = observer
RM=rm -rf
CADVISE_OPTS= -pdb mypdb +wlint
CADVISE= /opt/cadvise/bin/cadvise
.PHONY : CAdvisor update_cc clean all
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cc.o:
$(CC) $(CFLAGS) $< -o $#
clean:
$(RM) $(EXECUTABLE) $(OBJECTS)
update_cc: CC := ${$(CADVISE) $(CADVISE_OPTS) $(CC)}
CAdvisor: update_cc all;
#echo DEBD $(CC)
Now above code is giving me error:
**$ make CAdvisor
Make: Don't know how to make CC. Stop.
$**
How to fix this error
Any better option?
Linkes:link_how to call target from another
Thanks
Sorry, but that's not how target-specific variables work. Target-specific variables are scoped to their target and any prerequisite built as a result of building that target. It's not the case that the target-specific setting changes the value of the global variable for the rest of the recipes expanded by make.
In your example, all is not a prerequisite of update_cc, it's a sibling. So, target-specific variables that are set for update_cc have no impact on the all target.
Second, using ${$(CADVISE) $(CADVISE_OPTS) $(CC)} is definitely not right: the inside will be expanded first then because the entire thing is enclosed in ${...} it will be treated as a variable name, and that variable (which clearly doesn't exist) will be looked up, resulting in an empty string.
I don't know why you have added the extra target update_cc at all; why not just set the target-specific variable on the CAdvisor target?
CAdvisor: CC := $(CADVISE) $(CADVISE_OPTS) $(CC)
CAdvisor: all
#echo DEBD $(CC)

Can GNU Make recognise multiple matches in a pattern?

I have a rule in a makefile like this:
%.120.png : %.svg
inkscape -z -e $# -w 120 -h 120 $<
which works as intended. I would like to rewrite this in a more generic fashion, something like this:
%.%2.png : %.svg
inkscape -z -e $# -w %2 -h %1 $<
where %2 is a second match (% being the first).
As far as I know, this isn't supported. However, if it is, how ?
You cannot use multiple patterns. In the example you give, though, it's not hard to automate the recipe, although you'll still have to write multiple patterns:
INKSCAPECMD = inkscape -z -e $# -w $(patsubst $*.%.png,%,$#) -h $* $<
%.120.png : %.svg
$(INKSCAPECMD)
%.100.png : %.svg
$(INKSCAPECMD)
Etc. Except, looking at it more I'm pretty sure your description is wrong and that this pattern won't do what you really want

Resources