I have a Makefile containing rules for building a small project and cleaning it. For example:
CC:=gcc
LD:=gcc
SOURCES:=$(wildcard src/*.c)
OBJS:=$(SOURCES:src/%.c=build/%.o)
TARGET:=bin/program
all: $(TARGET)
$(TARGET): $(OBJS)
@mkdir -p bin
$(LD) $+ -o $@
build/%.o: src/%.c
@mkdir -p build
$(CC) $+ -c -o $@
clean:
rm -rf $(OBJS)
rm -rf $(TARGET)
rmdir bin
rmdir build
.PHONY: clean all
I am now interested in creating a rule rebuild
which would perform clean
and all
in that order. I do not see how properly achieve the correct ordering.
The solutions I have seen are wrong to my knowledge.
rebuild: clean all
.PHONY: rebuild
Is naturally wrong, because there is no guarantee that dependencies are actually performed in the order of their appearance. all
may execute before clean
.
I have seen answers suggesting order-only dependencies, e.g.
rebuild: | clean all
.PHONY: rebuild
To my knowledge, this does not solve the problem. If you say a: | b c
it means that a
depends on b
and c
, but if b
or c
is taken, it does not force executing the a
rule. It has nothing to do with ordering the dependencies.
The only option I see right now is launching a new instance of make, by having
rebuild : clean
make build
I would really like to avoid launching a new make instance for doing something simple like that!
I did some reasearch on SO. I have seen similar questions but no correct answer. To my knolwedge, making a target .PHONY
or using order-only dependencies is not a solution.
First, it's not true that in a rule:
rebuild: clean all
that all
could be built before clean
when running serially (that is, without parallelism -j
enabled). Make does always build prerequisites in the order they are listed in the makefile (there is a special case for the rule containing the recipe but that's not relevant here). When parallel builds are used then make still walks the dependency tree in the same order but because rules are built in parallel they may not be started in the same order.
However, you're right that this rule is not a great idea for other reasons (directory caching, etc.)
I recommend you use recursive make invocations to do this:
.PHONY: rebuild
rebuild:
$(MAKE) clean
$(MAKE) all
There is a way to do it without recursion; the price is a small amount of redundancy:
.PHONY: rebuild
$(TARGET) rebuild: $(OBJS)
@mkdir -p bin
$(LD) $+ -o $(TARGET) # note that I have replaced $@ with $(TARGET)
rebuild: | clean
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With