dj4567
dj4567

Reputation: 73

Weird make behavior with rule

I have a rule that create a file and an other one that copy it. But on running make, the prerequisites of the rule is called twice but I don't know why!

If I have a $(shell ./myscript) in prerequisite instead of the actual $(warning ...), the script is called twice!

The Makefile that reproduces the bug:

NAME := test

$(NAME):
    @touch $@

install-$(NAME): $(NAME) install-copy-$(NAME)

.PHONY: install-$(NAME)
.PRECIOUS: %.copy

.SECONDEXPANSION:

%.copy: $$*
    @cp $< $@

install-copy-%: $$(warning START) $$*.copy $$(warning END)
    @echo done

Actual output:

make: START
make: START
make: END
done

Expected output:

make: START
make: END
done

Why START is outputed twice? If I have a function that call a script instead of the $(warning) the script is called twice.

I have no idea... I want to keep the .SECONDEXPANSION because I don't want that the $(shell script ...) or the $(warning ...) was called when the rule is not called. I can't list all the files that will be installed in the .PRECIOUS, because I don't know since this file are generated by an external script. (like doxygen). With the .PRECIOUS: %.copy the first time START is outputed twice, but once the file exist, START is outputed once...

Thanks!

The Makefile with real case:

NAME := test
INSTALL_DIR := saved

# generate the documentation into $$*/
generateDoc-%:
    touch $*/$(shell head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')

install-$(NAME): generateDoc-$(NAME) install-doc-$(NAME)

.PHONY: install-$(NAME)
.PRECIOUS: $(INSTALL_DIR)/%

.SECONDEXPANSION:

$(INSTALL_DIR)/%: $$(NAME)/$$*
    cp $< $@

install-doc-%: $$(warning START) $$(subst $$*,$$(INSTALL_DIR),$$(shell find $$* -type f)) $$(warning END)
    @echo done

Upvotes: 1

Views: 122

Answers (1)

Alex Cohn
Alex Cohn

Reputation: 57203

make -d explains that after making target test, it tries to make target install-copy-test (that invokes the first pair of START/END). After that it looks for a rule with intermediate file test.copy.

All this on assumption that you run make install-test

> make install-test -n
touch test
make: START
make: END
make: START
make: END
cp test test.copy
done
rm test.copy

The natural fix would be to specify

.PRECIOUS: $(NAME).copy

Upvotes: 1

Related Questions