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.
The variable $@ represents the name of the target and $< represents the first prerequisite required to create the output file.
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.
$$ means be interpreted as a $ by the shell. the $(UNZIP_PATH) gets expanded by make before being interpreted by the shell.
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 .
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.
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.
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.
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.
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
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
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