Reputation: 28878
Suppose I have the following Makefile:
RM = rm -f
FLAGS = -Cr -O1 -gv -gw -g -vw
builddir = ./build/
TD = ./tasks/
all: example1 example3 example5
example1:
fpc 01_Kreisumfang.pas $(FLAGS) -o$(builddir)01_Kreisumfang
example3:
fpc 03_EuroBetrag3.pas $(FLAGS) -o$(builddir)03_EuroBetrag3
example5:
fpc 05_Dreiecke.pas $(FLAGS) -o$(builddir)05_Dreieck
clean:
$(RM) $(builddir)*
At a certain point my Makefile grows to example112
...,
is there a way to define all automatically with out needing to type in all
the targets? I don't want to do this:
all: example1 example3 example5 ... example112
Can I do something like this?
all: (MAGIC to Exclude clean)?
So instead of having to type all the targets, I want make to detect all the targets and exclude a certain list.
I found the following possible hint:
make -rpn | sed -n -e '/^$/ { n ; /^[^ ]*:/p }' |egrep -v -E '(all|clean)'
I don't know how to make this a target by itself, I tried with:
TARGETS =: $(shell make -rpn | sed -n -e '/^$$/ { n ; /^[^ ]*:/p }' |egrep -v -E '(all|clean)')
But it seems to be wrong. Not only it is wrong, it will cause a silly recursion.
So this solution is only available as a shell command, not within the Makefile itself.
Well, make seems to be just cryptic here. The most reasonable solution I found is to create a script and use that:
$ cat doall.sh
#!/bin/bash
for i in `make -rpn | sed -n -e '/^$/ { n ; /^[^ ]*:/p }' | sed -e 's/://' | egrep -v -E '(all|clean)'`;
do make $i;
done
It seems impossible to create it as a make target, or that the ROI on this is very low ...
Upvotes: 9
Views: 9880
Reputation: 60143
I've been using
make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'
(Saved as make-t
) to list all targets.
If you want to build all real targets, then get a listing of all targets that aren't phony:
make -qp | grep -P '^[.a-zA-Z0-9][^$#\/\t=]*:([^=]|$)' |
tee >(cut -d: -f1 ) >(grep '^\s*\.PHONY\s*:' |cut -d: -f2) >/dev/null|
tr ' ' '\n' | sed '/^\s*\./ d; /^\s*$/ d' |sort |uniq -u
should do the job (this assumes no target names with spaces in them).
Upvotes: 0
Reputation: 674
I tried this out using a for loop. Check if this simple example works for you. Took the command from this post.
RM = rm -f
FLAGS = -Cr -O1 -gv -gw -g -vw
builddir = ./build/
TD = ./tasks/
SHELL := /bin/bash
targets=$(shell for file in `find . -name '*.pas' -type f -printf "%f\n" | sed 's/\..*/\.out/'`; do echo "$$file "; done;)
all: $(targets)
%.out:%.pas
fpc $< $(FLAGS) -o (builddir)$@
clean:
$(RM) $(builddir)*
Upvotes: 1