Execution of the recipe for multiple targets at once - makefile

I have a project where I need to process many files in the same way. My GNUMakefile looks like this:
$(SOURCES) = file1.a file2.a file3.a ... fileN.a
$(TARGETS) = $(SOURCES:.a=.b)
%.b: %.a
build-tool $?
all: $(TARGETS)
This makefile executes build-tool for each target, which is slow. So I want it to execute build-tool only once with list of all updated prerequisites.
I tried to add the following rule:
$(TARGETS): $(SOURCES)
And it helped on first build like that:
$ make all
build-tool file1.a file2.a ... fileN.a
But on subsequent builds build-tool was executed as many times as many targets I have:
$ touch file1.a && make all
build-tool file1.a
build-tool file1.a
...
build-tool file1.a
In the other hand, if I change recipe to build-tool $# it will execute build-tool once with all prerequisites in all cases, which is undesirable too.
Is there some method to execute the recipe only once for all targets, i.e. with all prerequisites on first build and only modified on subsequent builds?

You can't use a pattern rule for this. That's why you're seeing everything build multiple times. You have to use a "sentinel" file that make can use to determine which files have changed since the last time you built.
For example, something like this will work:
$(SOURCES) = file1.a file2.a file3.a ... fileN.a
$(TARGETS) = $(SOURCES:.a=.b)
.PHONY: all
all: .ran-build-tool
.ran-build-tool: $(SOURCES)
build-tool $?
#touch $#
ETA: If you need another level you can do something like:
$(SOURCES) = file1.a file2.a file3.a ... fileN.a
$(TARGETS) = $(SOURCES:.a=.b)
.PHONY: all
all: .ran-build-tool2
.ran-build-tool2: $(TARGETS) | .ran-build-tool
build-tool2 $?
#touch $#
.ran-build-tool: $(SOURCES)
build-tool $?
#touch $#

According to an answer to "multiple targets from one recipe and parallel execution" you may write something like:
file1%b file2%b file3%b: file1%a file2%a file3%a
build-tool $?

Related

Makefile skips dependency

I've created a makefile for my little project
.SUFFIXES:
%.cpp:
$(COMP) -c -o $(subst .cpp,.o,$#) $(SRCDIR)$# $(CFLAGS)
platformL: COMP:=gcc
platformL: $(FILES)
$(COMP) -o $(NAME) $(subst .cpp,.o,$(FILES)) $(CFLAGS)
rm $(subst .cpp,.o,$(FILES))
platformW: COMP:=wine gcc
platformW: $(FILES)
$(COMP) -o $(NAME).exe $(subst .cpp,.o,$(FILES)) $(CFLAGS)
rm $(subst .cpp,.o,$(FILES))
default: platformL platformW
echo Done!
Everything worked fine until I branched to 2 different platforms, 'make' command executes only my platformL branch. After spending some time with it I discovered that adding '.PHONY' won't fix the problem. Also, it appears that only the first branch from the top gets executed (I have put the lines of platformW before platformL and only Windows compilation was performed).
How can I make it execute both branches?
Make always builds the first explicit target (and all prerequisites of the first explicit target) in the makefile, by default. That's all it will build by default.
You can either specify multiple things to build on the command line, like make platformL platformW, or you can add a new first target that depends on all the other targets you want built. By tradition that target is named all but you can call it whatever you want:
all: platformL platformW
.PHONY: all
...
platformL: ...
...
platformW: ...

How do I include a built *.mk into Makefile more idiomatically? Also why `.PHONY: .DEFAULT` fails?

I want make to build something and reuse some of generated makefiles as an include.
Here is simplified model of what I have so far:
Makefile
all: myprogram
.PHONY: .DEFAULT
.DEFAULT:
${MAKE} something_tricky.mk
${MAKE} -f actual_makefikle.mk $#
.SUFFIXES:
something_tricky.mk:
echo "TRICKY_VARIABLE=qwerty" > something_tricky.mk
actual_makefile.mk
include something_tricky.mk
all: myprogram
myprogram:
echo ${TRICKY_VARIABLE} > $#
It sometihng like works, but has problems. For example .PHONY: .DEFAULT doesn't work, so I can't automatically rebuild any file.
My questions:
How do I make .PHONY: .DEFAULT work?
Is there any other way to delegate all targets to other Makefile (after building some dependencies of it)
Are there any simpler and better patterns about such things that I don't know? (expect of abandoning Makefile-centric approach and embracing more high-level build system)
Make will automatically attempt to remake any included makefiles, and then start over. The following should work
include something_tricky.mk
.PHONY: all
all: myprogram
myprogram: $(MAKEFILE_LIST)
echo $(TRICKY_VARIABLE) > $#
something_tricky.mk:
echo TRICKY_VARIABLE=qwerty > something_tricky.mk

Makefile automatic variable changed by prerequisite

first time here. I am relatively new to makefiles. Here is my current makefile:
# Closure compiler php script path
closure = ../../cli/scripts/Compilers/closure.php
# Destination directory
dest = ../../static/js/
# Build directory
build = build/
# Tell "make" to search build and destination dirs
vpath %.o $(build)
vpath %.js $(dest)
all: main.js
#echo "Done.";
main.js: \
date.o \
jquery.autocomplete.o \
jquery.bullseye.o \
jquery.clickopen.o \
jquery.fbmodal.o \
jquery.helpers.o \
jquery.pulljson.o \
jquery.thumbrotate.o \
jquery.timefmt.o \
jquery.tools.o \
layout.main.o
cat $^ > $(dest)$#
%.o: %.js
php $(closure) $*.js $(build)$#
clean:
rm -rf $(build)*.o
rm -rf $(dest)*.js
The problem is with the following line:
cat $^ > $(dest)$#.
It is supposed to cat all the prerequisite objects (minified javascript) into one final js library. According to makefile docs, $^ is an automatic variable which contains a list of prerequisites with directories they are in. From my experience, it behaves differently depending on wether prerequisite needs to be compiled or not.
If prerequisite is up-to-date, this code works perfectly and $^ contains a list like:
build/date.o build/jquery.autocomplete.o build/jquery.bullseye.o....
However if prerequisite needs a fresh compile, then $^ gets directory part stripped and looks like:
date.o jquery.autocomplete.o jquery.bullseye.o
Only the file which needs a fresh compile gets directory part stripped.
I have managed to work around this issue by replacing
cat $^ > $(dest)$#
with
cat $(addprefix $(build), $(^F) ) > $(dest)$#.
I don't like it because:
It's a hack
$(^F) is semi-deprecated
I want to understand why make behaves like this.
thanks
Look here:
# Tell "make" to search build and destination dirs
vpath %.o $(build)
If Make is looking for foo.o, it will look in the local directory first. If it finds no foo.o there, it will look in $(build) (i.e. build/, and you might reconsider your variable names).
And how would Make build foo.o, if it couldn't find it anywhere? With this rule:
%.o: %.js
php $(closure) $*.js $(build)$#
This rule violates an important guideline of makefiles, in that the target (foo.o) is not the name of the thing actually built (build/foo.o).
Now consider what happens when Make tries to execute this rule:
main.js: date.o ...
cat $^ > $(dest)$#
So if date.o is up to date, it's in build/. Make finds it there, and the automatic variable $^ expands to build/date.o ...
But if date.o must be rebuilt, then Make looks to the %.o rule, which promises to build date.o (not build/date.o), so Make takes that rule at its word and $^ expands to date.o ...
There are several ways to solve this problem. I'd do something like this:
OBJS := date.o jquery.autocomplete.o jquery.bullseye.o ...
OBJS := $(addprefix $(build),$(OBJS))
$(dest)main.js: $(OBJS)
cat $^ > $#
# you might have to tinker with this rule a little
$(build)%.o: %.js
php $(closure) $< $#

How can I manage make targets that don't have suffixes?

I've got a make file that generates multiple targets. Something like:
target-a: target-a.src target-include.src
#$(BUILD_TOOL) -f $< -o $#
target-b: target-b.src target-include.src
#$(BUILD_TOOL) -f $< -o $#
target-c: target-c.src target-include.src
#$(BUILD_TOOL) -f $< -o $#
The actual build process (abbreviated as $(BUILD_TOOL) above) is a multiple line thing involving compilers, scripts and various whatnot, but suffice to say, the build process acts on the first target dependency ($<) and produces the output target ($#).
This is quite unwieldly. Would what I've got below be considered a safe way to replace the above (using a pattern rule that doesn't have a suffix)?
all: target-a target-b target-c
% : %.src target-include.src
#$(BUILD_TOOL) -f $< -o $#
The make tool is GNU, and I'm content to use it's powerful extensions.
If target is a literal string, renierpost's solution is very good. If it isn't (or even if it is) this will work:
TARGETS := target-a target-b target-c
all: $(TARGETS)
$(TARGETS): % : %.src target-include.src
#$(BUILD_TOOL) -f $< -o $#
Note that this rule will not build targets you did not intend, not even target-include.
It depends on the rest of your Makefile, but in principle this should work,
if all files are in one directory.
It's better practice to use extensions on your targets.
Is target a literal string? In that case, you can be more specific
(and speed up rule application a tiny little bit, but it's fast already) by using
all: target-a target-b target-c
target-% : target-%.src target-include.src
#$(BUILD_TOOL) -f $< -o $#
GNU make's advanced syntax will come into play if you want to automatically deduce the names of target-a target-b target-c from the target-*.src filenames on the filesystem or something similar.

How do I make a makefile rule execute its prerequisites?

I have a makefile containing rules to build the system, tests, and run them. The last item is executed by just calling a shell script. Among other things, this prevents me from running the tests in parallel.
I have the following variables:
TEST_SRC=$(wildcard tests/*.c)
TESTS=$(patsubst %.c,%,${TEST_SRC})
and it builds the tests with the rule
$(TESTS): %: %.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $<
Is it possible (and if so, how?) to create a rule "tests" that, when run, will execute each item in the $TESTS variable?
You could do it this way:
# a separate target to run each test
RUN_TESTS = $(addprefix run_, $(TESTS))
# a pattern rule for those targets, which will remake the test iff neccessary
.PHONY: $(RUN_TESTS)
$(RUN_TESTS):run_%:%
./$<
# One Rule to Ring Them All, One Rule to... sorry.
.PHONY: tests
tests: $(RUN_TESTS)
I believe that a rule like this:
run_tests: $(TESTS)
Should do the trick:
$ make run_tests
It will not execute anything, but it will have $(TESTS) as a dependency and run them first.

Resources