Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a 'rebuild' rule out of 'build' and 'clean' in Makefile?

Tags:

makefile

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.

like image 546
CygnusX1 Avatar asked Nov 13 '16 17:11

CygnusX1


2 Answers

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
like image 80
MadScientist Avatar answered Sep 27 '22 02:09

MadScientist


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
like image 29
Beta Avatar answered Sep 23 '22 02:09

Beta