Makefile rules

What’s Wrong With GNU make?
HOWTO: Intro to GNU make variables

target: normal-prerequisites | order-only-prerequisites
    recipe

Debugging

$ make -d
==> print out the parser results

$ make -p
==> execute make but prints the database
(buildins + Makefile) at the end

.SUFFIXES

      Considering target file 'obj/osa541x_sim/advaNtpd/ntpd/ntp_parser.o'.
       File 'obj/osa541x_sim/advaNtpd/ntpd/ntp_parser.o' does not exist.
        Considering target file 'src/ntpd/ntp_parser.c'.
         Looking for an implicit rule for 'src/ntpd/ntp_parser.c'.
         Trying pattern rule with stem 'ntp_parser'.

         Trying implicit prerequisite 'src/ntpd/ntp_parser.y'.
         Found an implicit rule for 'src/ntpd/ntp_parser.c'.
          Considering target file 'src/ntpd/ntp_parser.y'.

           Looking for an implicit rule for 'src/ntpd/ntp_parser.y'.
           Trying pattern rule with stem 'ntp_parser.y'.
           Found an implicit rule for 'src/ntpd/ntp_parser.y'.
           Finished prerequisites of target file 'src/ntpd/ntp_parser.y'.
          No need to remake target 'src/ntpd/ntp_parser.y'.
         Finished prerequisites of target file 'src/ntpd/ntp_parser.c'.
         Prerequisite 'src/ntpd/ntp_parser.y' is newer than target 'src/ntpd/ntp_parser.c'.
        Must remake target 'src/ntpd/ntp_parser.c'.
yacc  src/ntpd/ntp_parser.y 
Putting child 0xe159d0 (src/ntpd/ntp_parser.c) PID 5528 on the chain.
Live child 0xe159d0 (src/ntpd/ntp_parser.c) PID 5528 
make: yacc: Command not found
Reaping losing child 0xe159d0 PID 5528 
<builtin>: recipe for target 'src/ntpd/ntp_parser.c' failed
make: *** [src/ntpd/ntp_parser.c] Error 127
Removing child 0xe159d0 PID 5528 from chain.
# default
SUFFIXES := .out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym .yl .s .S .mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo .w .ch .web .sh .elc .el

[...]

%.c: %.y
#  recipe to execute (built-in):
	$(YACC.y) $< 
	 mv -f y.tab.c $@
.SUFFIXES:
      Considering target file 'obj/osa541x_sim/advaNtpd/ntpd/ntp_parser.o'.
       File 'obj/osa541x_sim/advaNtpd/ntpd/ntp_parser.o' does not exist.
        Considering target file 'src/ntpd/ntp_parser.c'.
         Looking for an implicit rule for 'src/ntpd/ntp_parser.c'.
         Trying pattern rule with stem 'ntp_parser'.
         Trying implicit prerequisite 'src/ntpd/ntp_parser.w'.
         Trying pattern rule with stem 'ntp_parser.c'.
         Found an implicit rule for 'src/ntpd/ntp_parser.c'.
         Finished prerequisites of target file 'src/ntpd/ntp_parser.c'.
        No need to remake target 'src/ntpd/ntp_parser.c'.
       Finished prerequisites of target file 'obj/osa541x_sim/advaNtpd/ntpd/ntp_parser.o'.
      Must remake target 'obj/osa541x_sim/advaNtpd/ntpd/ntp_parser.o'.
Putting child 0x1dcaaa0 (obj/osa541x_sim/advaNtpd/ntpd/ntp_parser.o) PID 5755 on the chain.
Live child 0x1dcaaa0 (obj/osa541x_sim/advaNtpd/ntpd/ntp_parser.o) PID 5755 
[CC] src/ntpd/ntp_parser.c

Tagged Commands / Command Prefix

What do @, – and + do as prefixes to recipe lines in Make?

Command lines can have one or more of the following three prefixes:

  • a hyphen-minus (-), specifying that errors are ignored
  • an at sign (@), specifying that the command is not printed to standard output before it is executed
  • a plus sign (+), the command is executed even if Make is invoked in a “do not execute” mode
  • @ suppresses the normal ‘echo’ of the command that is executed.
  • – means ignore the exit status of the command that is executed (normally, a non-zero exit status would stop that part of the build).
  • + means ‘execute this command under make -n’ (when commands are not normally executed).

Substitution

Substitution References

SOURCE = main.c test.c bla.cpp blu.cpp bli.c
OBJECT = $(SOURCES:%.c=%.o)

Result:
main.o test.o bla.cpp blu.cpp bli.o

Functions

Functions for String Substitution and Analysis

SOURCE     = main.c test.c bla.cpp blu.cpp bli.c
C_OBJECT   = $(filter %.c,$(SOURCE): %.c=%.o)
CXX_OBJECT = $(filter %.cpp,$(SOURCE): %.cpp=%.o)

Result:
main.o test.o bla.cpp blu.cpp bli.o

Setting Variables = := ?= !=

Setting Variables
The Two Flavors of Variables
Computing Makefile variable on assignment

 = Recursively expanded variable
:= Simply expanded variables
?= Only set variable if it’s not already set
!= execute program and set variable to its output
FOO ?= bar

equal to

ifeq ($(origin FOO), undefined)
FOO = bar
endif
hash != printf '\043'
file_list != find . -name '*.c'

equal to

hash := $(shell printf '\043')
var := $(shell find . -name "*.c")

Double-Colon Rules

Double-Colon Rules
What are double-colon rules in a Makefile for?
Makefiles – Make and the Double colon

ibxxx.a : sub1.o sub2.o
    ar rv libxxx.a sub1.o
    ar rv libxxx.a sub2.o

====

libxxx.a :: sub1.o
    ar rv libxxx.a sub1.o

libxxx.a :: sub2.o
    ar rv libxxx.a sub2.o

Empty Recipes (Semicolon)

Using Empty Recipes
What does it mean when a semicolon occurs in a makefile target’s prerequisites?

Match-Anything Pattern Rules

target: ;

% :: ;

Order-Only-Prerequisites

Types of Prerequisites
What does $$@ and the pipe symbol in Makefile stand for?
Makefile execute phonytargets of a file only if file does not exists

targets: normal-prerequisites | order-only-prerequisites
    recipe

Pattern Rules

You define an implicit rule by writing a pattern rule. A pattern rule looks like an ordinary rule, except that its target contains the character ‘%’ (exactly one of them). The target is considered a pattern for matching file names; the ‘%’ can match any nonempty substring, while other characters match only themselves. The prerequisites likewise use ‘%’ to show how their names relate to the target name.

Defining and Redefining Pattern Rules
Pattern Rule Examples

%.o : %.c
    $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

Automatic Variables

Automatic Variables

$@
The file name of the target of the rule.
$%
The target member name, when the target is an archive member.
$<
The name of the first prerequisite.
$?
The names of all the prerequisites that are newer than the target, with spaces between them.
$^
The names of all the prerequisites, with spaces between them.
$+
This is like ‘$^’, but prerequisites listed more than once are duplicated in the order they were listed in the makefile.
$|
The names of all the order-only prerequisites, with spaces between them.
$*
The stem with which an implicit rule matches.

Built-in Target Names

Special Built-in Target Names

.PHONY
The prerequisites of the special target .PHONY are considered to be phony targets. When it is time to consider such a target, make will run its recipe unconditionally, regardless of whether a file with that name exists or what its last-modification time is.
.SUFFIXES
The prerequisites of the special target .SUFFIXES are the list of suffixes to be used in checking for suffix rules.
.DEFAULT
.
.PRECIOUS
.
.INTERMEDIATE
.
.SECONDARY
.
.SECONDEXPANSION
.
.DELETE_ON_ERROR
.
.IGNORE
.
.LOW_RESOLUTION_TIME
.
.SILENT
.
.EXPORT_ALL_VARIABLES
.
.NOTPARALLEL
.
.ONESHELL
.
.POSIX
.

Canned Recipes / Functions/ Templates

Defining Canned Recipes
Makefiles: can 'canned recipes' have parameters?

define run-yacc =
yacc $(firstword $^)
mv y.tab.c $@
endef

define DIRECTORY_template
$(1):
	@echo "[MKDIR] $$@"
	@mkdir -p $(1)

endef

$(eval $(call DIRECTORY_template,testdir))

foo.c : foo.y testdir
    $(run-yacc)

Makefile as a functional language program

The following article describes a real practical application: avoiding the explosion of makefile rules in a project that executes many test cases on many platforms. Each test target is built from its own set of source code files. Each (Scheme) platform has its own particular way of assembling source code files into a project; some source code files might need be omitted from the build for a particular platform. Because GNU make turns out to be a functional programming system, we can reduce the number of rules from * to just + .

The language of GNU make is indeed functional, complete with combinators (map and filter), applications and anonymous abstractions. GNU make does support lambda-abstractions. The following is one example from the Makefile in question: it is a rule to build a test target for the SCM Scheme system. The list of source code files and the name of the target/root-test-file are passed as two arguments of the rule:

 make-scmi= scm -b -l $(LIBDIR)/myenv-scm.scm \
            $(foreach file,$(1),-l $(LIBDIR)/$(file)) \
            -l $(2).scm

The rule returns an OS command to interpret or compile the target. The rule can be invoked as

$(call make-scmi,util.scm catch-error.scm,vmyenv)

. As in TeX, the arguments of a function are numbered (it is possible to assign them meaningful symbolic names, too). Makefile's foreach corresponds to Scheme's map. The comparison with the corresponding Scheme code is striking:

 (define make-scmi
    (lambda (arg1 arg2)
         `(scm -b -l ,(mks LIBDIR '/ 'myenv-scm.scm)
            ,@(map (lambda (file) `(-l ,(mks LIBDIR '/ file))) arg1)
           -l ,(mks arg2 '.scm))))

Timestamp on files and directories

Makefile re-generates some object-files, but I didn't know why:

$ cat Makefile
[...]
obj/pi/main.o: obj/pi src/main.f90
	@echo "[FC] src/main.f90"
	@gfortran -o $@ -c src/main.f90

obj/pi/pi.o: obj/pi src/pi.f90
	@echo "[FC] src/pi.f90"
	@gfortran -o $@ -c src/pi.f90 
[...]

$ make clean && make
$ make -d
[...]
     Prerequisite 'obj/pi' is newer than target 'obj/pi/main.o'.
     Prerequisite 'src/main.f90' is older than target 'obj/pi/main.o'.
    Must remake target 'obj/pi/main.o'.
[...]
target: dependencies/prerequisites
<Tab> system command(s)/recipe

It imposes a dependency relationship: if any prerequisite is newer than the target, then the target is considered out-of-date and must be rebuilt.

The directory timestamp is updated, when a file in this directory is updated!!

$ stat obj/pi --printf '%n\nmtime: %y\nctime: %z\natime: %x\ncrtime:%w\n'
obj/pi
mtime: 2016-01-08 18:48:17.841692523 +0100
ctime: 2016-01-08 18:48:17.841692523 +0100
atime: 2016-01-08 18:49:34.724417557 +0100

$ touch obj/pi/test

$ stat obj/pi --printf '%n\nmtime: %y\nctime: %z\natime: %x\ncrtime:%w\n'
obj/pi
mtime: 2016-01-08 18:49:46.300225133 +0100
ctime: 2016-01-08 18:49:46.300225133 +0100
atime: 2016-01-08 18:49:34.724417557 +0100

$ stat obj/pi/test --printf '%n\nmtime: %y\nctime: %z\natime: %x\ncrtime:%w\n'
obj/pi/test
mtime: 2016-01-08 18:49:46.300225133 +0100
ctime: 2016-01-08 18:49:46.300225133 +0100
atime: 2016-01-08 18:49:46.300225133 +0100

I changed the directory creation on target 'all' so that the object files doesn't directly depend on the directories anymore:

define DIRECTORY_template

DIRECTORIES += obj/$(1)

obj/$(1):
	@echo "[MKDIR] $$@"
	@mkdir -p obj/$(1)

endef

[...]

DIRECTORIES =

all: mkdirs $(PROGRAMS)

$(foreach prog,$(PROGRAMS),$(eval $(call VARIABLE_template,$(prog))))
$(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))

mkdirs: $(DIRECTORIES) 

Difference between Build Tools

Build Tools: Make, Rake, Ant, MSBuild
RAKE – Ruby Make

Multi-Architecture Builds

Multi-Architecture Builds
How Not to Use VPATH
Rules of Makefiles

BSD make

Programming in Makefiles for NetBSD

GNU make

GNU make with Java

Java: Gnu Make Makefile Examples

make++

Makepp
Makepp Rules

Kleines Beispiel

SOURCES = main.c \
          draw.c \
          camera.c \
          utils.c \
          createTexture.c \
          text.c

CFLAGS = `sdl-config --cflags` -D_REENTRANT -Wall
LDFLAGS = `sdl-config --libs` -lopengl32 -lglu32 -lSDL_ttf

OBJECTS = $(SOURCES:%.c=%.o)

.PHONY: all clean

all : Aufgabe4

Aufgabe4 : $(OBJECTS)
g++ -o $@ $(OBJECTS) $(LDFLAGS)

%.o : %.c
g++ $(CFLAGS) -c $<

clean :
rm *.o

build : clean all

PHONY: 

Links dazu:
Automatic Variables für $< oder $@ How Patterns Match für %.o oder %.c
Phony Targets für .PHONY: clean
GNU Make and the foreach() function
Display the results of foreach / eval / call expansion
How can I use macros to generate multiple Makefile targets/rules inside foreach?
In GNU Make, how do I convert a variable to lower case?
8.4 Functions for Conditionals
GNU make conditional function $(if …) inside a user-defined function always evaluates to true
GNU make: Please give an example for the 'if' function

statt:
$(foreach prog, $(PROGRAMS), $(eval $(call VARIABLE_template,$(prog))))

nun:
$(foreach prog, $(PROGRAMS), $(info $(call VARIABLE_template,$(prog))))

Leave a Reply

Your email address will not be published. Required fields are marked *