Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run pre- and post-recipes for every target using GNU Make?

In make, is it possible to define a pre- and post-recipe for every target?

I want to (implicitly) insert the pre-recipe just above the first line of the explicit recipe and then (implicitly) insert the post-recipe after the last line in the explicit recipe.

It would be pretty easy to do it using regular expressions to insert lines but implicit ones would be so much cleaner.

like image 932
Bob Avatar asked Jun 21 '16 18:06

Bob


People also ask

What does $@ mean in makefile?

The variable $@ represents the name of the target and $< represents the first prerequisite required to create the output file.

How do I call a target in makefile?

When you type make or make [target] , the Make will look through your current directory for a Makefile. This file must be called makefile or Makefile . Make will then look for the corresponding target in the makefile. If you don't provide a target, Make will just run the first target it finds.

What is $$ in makefile?

$$ means be interpreted as a $ by the shell. the $(UNZIP_PATH) gets expanded by make before being interpreted by the shell.

What does .phony do in makefile?

The special rule . PHONY is used to specify that the target is not a file. Common uses are clean and all . This way it won't conflict if you have files named clean or all .

What does it mean to force a target to run its recipe?

This implies that all targets depending on this one will always have their recipe run. An example will illustrate this: Here the target ‘ FORCE ’ satisfies the special conditions, so the target clean that depends on it is forced to run its recipe.

How does make work with no prerequisites or recipes?

If a rule has no prerequisites or recipe, and the target of the rule is a nonexistent file, then make imagines this target to have been updated whenever its rule is run. This implies that all targets depending on this one will always have their recipe run.

What are the different types of GNU make prerequisites?

There are actually two different types of prerequisites understood by GNU make: normal prerequisites such as described in the previous section, and order-only prerequisites.

How does a normal prerequisite work?

A normal prerequisite makes two statements: first, it imposes an order in which recipes will be invoked: the recipes for all prerequisites of a target will be completed before the recipe for the target is run.


2 Answers

You can create a special helper shell that executes the desired pre- and post- actions before and after its input script and tell make to use that shell for executing the recipes (use the SHELL variable to that end).

Besides, if you are using multiline recipes, you will have to enable the .ONESHELL mode.

Caveat: in this mode a failed command (except the last one) doesn't fail the rule, so you either have to join the commands with &&, or append || exit 1 to the end of each command, or run the real shell with the -e option.

Example:

pre-post-shell

#!/bin/bash

preaction()
{
    echo "Pre-action"
}

postaction()
{
    echo "Post-action"
}

preaction && /bin/bash "$@" && postaction

makefile

SHELL=./pre-post-shell

all: Hello Bye

.ONESHELL:

Hello:
    @echo Hello
    echo Hello again

Bye:
    @echo Bye

Output:

$ make
Pre-action
Hello
Hello again
Post-action
Pre-action
Bye
Post-action
like image 138
Leon Avatar answered Oct 18 '22 10:10

Leon


You can have a target that you call using the $(MAKE) command on the same file making the call:

THIS_FILE:=$(lastword $(MAKEFILE_LIST))

SOURCES:=main.cpp other.cpp
OBJECTS:=$(SOURCES:.cpp=.o)

OUT:=main

.PHONY: all pre post

all: $(OUT)

$(OUT): $(OBJECTS)
    $(CXX) $(LDFLAGS) -o $(OUT) $(OBJECTS) $(LIBS)

pre:
    @echo "PRE TARGET"

post:
    @echo "POST TARGET"

%.o: pre %.cpp
    $(CXX) $(CXXFLAGS) -c $(lastword $^) -o $@
    @$(MAKE) -f $(THIS_FILE) post

This example Makefile will output something like:

PRE TARGET
g++ -std=c++11 -O2 -g -c main.cpp -o main.o
POST TARGET
PRE TARGET
g++ -std=c++11 -O2 -g -c other.cpp -o other.o
POST TARGET
g++ -o main main.o other.o
like image 39
RamblingMad Avatar answered Oct 18 '22 11:10

RamblingMad