From 5eaac86a1b7d38824b2513547c97972b5c54a980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Lindi?= Date: Mon, 7 Oct 2024 09:37:54 +0200 Subject: [PATCH 1/5] Update rules. --- doc/rules.md | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/doc/rules.md b/doc/rules.md index 1026127..c5c280a 100644 --- a/doc/rules.md +++ b/doc/rules.md @@ -3,8 +3,6 @@ The rule governing the building of the hello world program was so called _explic types of rules as well, and we will be going through these now: - explicit rules - pattern rules -- static pattern rules -- suffix rules - implicit rules ## Explict rules @@ -60,6 +58,32 @@ The command `make print` will execute the `lpr` command if one of the source fi last `make print`. The automatic variable `$?` is used to print only those files that have changed. (We will discuss automatic variables in a moment) +## Pattern rules +```makefile +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ +``` +A pattern rule looks like an ordinary rule, except that its target contains the character '%'. The target +is considered a pattern for matching file names; the '%' can match any nonempty substring, while other +characters match only themselves. The shown rule '%.o : %.c' says how to make any file `stem.o` from another +file `stem.c` + +## Implicit rules +`make` has about 90 built-in implicit rules. There are built-in pattern rules for C, C++, Pascal, Fortran, +Modula, Texinfo, TEX, Emacs, Lisp, RCS and SCCS. The two last ones are version control systems. The implicit +rules database can be listed with the command: +```sh +make --print-data-base # This gives a long output! +``` +The implicit rule for building an executable from object files looks like this: +```makefile +%: %.o +# commands to execute (built-in): + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ +``` +A interesting note is that this rule is not part of the implicti rulebase on my Mac with +make version 3.81, but it exists in the implicit rulebase on Linux with make version 4.3 + ## Variables A variable have the syntax: @@ -178,3 +202,5 @@ to produce the target executable. - conditional variable - append variable - target variable +- static pattern rules +- suffix rules From f22d6bdff04d7a86ef150a1277a3dc41646e1784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Lindi?= Date: Mon, 7 Oct 2024 10:47:51 +0200 Subject: [PATCH 2/5] Add descriptions of different types of variables. --- doc/rules.md | 111 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/doc/rules.md b/doc/rules.md index c5c280a..27bd1ea 100644 --- a/doc/rules.md +++ b/doc/rules.md @@ -1,13 +1,80 @@ -# Rules +# Variables, Functions, Rules and a exampel with vpath +In following we will go through `make` variables, functions and rules. We will also visit an upated +example of the `hello world` program. + +## Variables +A variable is a name defined in a makefile to represent a string of text, called the variable's +value. These values are substitued by explicit request into targets, prerequisites, recipes, and +other parts of the makefile. By convention are variables that are internal to the makefile lowercased. +Variables that might be set from the command line are uppercased. + +### Variable References +A variable name must be surrounded by $() or ${} to be recognized by make. Variables are case-sensitive, +hence $(CC) and $(cc) refer to two different variables. +```makefile +objects = program.o foo.o utils.o +program : $(objects) + cc -o program $(objects) + +$(objects) : defs.h +``` +One type of variable that do not require parentheses is the single character variable. + +### Simple Variable +A *simply expanded* variable is defined using ':=' assignment operator. Any make variable references +in the righthand side are expanded and the resulting text saved as the value of the variable upon +reading the line from the `makefile`. The variable is not updated again however many times it is +referenced. +```makefile +MAKE_DEPEND := $(CC) -M +``` + +### Recursive Variable +The variable `$(object)` in the example above is a *recursively expanded* variable. Variables of this +sort are defined by using '='. For a *recursive variable* the righthandside is read without being +expanded. The expansion of the variable happens when it is used. The variable is re-evaluated upon +every time it is used. Consequently, the content of a *recursive variable* may change during +the course of a `makefile`. + +### Conditional Variable +```makefile +# Put all generated files in the directory $(PROJECT_DIR)/bin. +OUTPUT_DIR ?= $(PROJECT_DIR)/bin +``` +The '?=' operator is called the *conditional variable assignment operator*. Here the the assignment is +performed only if the variable does not yet hava a value. + +### Automatic variables +There are seven automatic variables. Automatic variables are set by `make` after a rules is matched. +They provide access to elements from the target and prerequisite lists. It this way you don't have +to explictily specify any filenames. + +| Variable | Function | +| -------- | -------- | +| $@ | The filename representing the target | +| $% | The filename element of an archive member specification | +| $< | The filename of the first prerequisite | +| $? | The names of all prerequisites that are newer than the target, separated by spaces | +| $^ | The filenames all the prerequisites, separated by spaces | +| $+ | Similar to $^ except that $+ include duplicates | +| $* | The stem of the target filename. | + +These seven variables have variants that get just the file's directory name or just the file name within +the directory. The variant variables names are formed by appending 'D' or 'F'. These variant variables are +more than one character long and so must be enclosed in parentheses, i.e. $(@D), $(@F). +See [GNU Make Automatic variables](https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html) + + +## Rules The rule governing the building of the hello world program was so called _explicit_ rule. There are other types of rules as well, and we will be going through these now: - explicit rules - pattern rules - implicit rules -## Explict rules +### Explict rules -### wildcards +#### wildcards `make` supports wildcards, also known as globbing.`make`'s wildcards are identical to the Bourne shell's. Instead of listing all the files in a program explicitly, you can use wildcards together with automatic variables (We will going through automatic variables in a moment): @@ -42,7 +109,7 @@ Many _makefiles_ include a set of standard phony targes. The table list these: | `check` | Run any tests associated with this application | | | | -### empty targets +#### empty targets An _empty target_ is similar to phony targets; it is used to hold recipes for an action that you request explicitly. The purpose of the empty target file is to record when the rule's recipe was last executed. It does so because one of the commands in the recipe is a `touch` command to update the target file. @@ -58,7 +125,7 @@ The command `make print` will execute the `lpr` command if one of the source fi last `make print`. The automatic variable `$?` is used to print only those files that have changed. (We will discuss automatic variables in a moment) -## Pattern rules +### Pattern rules ```makefile %.o : %.c $(CC) $(CFLAGS) -c $< -o $@ @@ -68,7 +135,7 @@ is considered a pattern for matching file names; the '%' can match any nonempty characters match only themselves. The shown rule '%.o : %.c' says how to make any file `stem.o` from another file `stem.c` -## Implicit rules +### Implicit rules `make` has about 90 built-in implicit rules. There are built-in pattern rules for C, C++, Pascal, Fortran, Modula, Texinfo, TEX, Emacs, Lisp, RCS and SCCS. The two last ones are version control systems. The implicit rules database can be listed with the command: @@ -85,37 +152,7 @@ A interesting note is that this rule is not part of the implicti rulebase on my make version 3.81, but it exists in the implicit rulebase on Linux with make version 4.3 -## Variables -A variable have the syntax: -```makefile -$(variable-name) -``` -A variable name must be surrounded by $() or ${} to be recognized by make. Variables are case-sensitive, -hence $(CC) and $(cc) refer to two different variables. One type of variable that do -not require parentheses is the single character variable. By convention are variables that are internal -to the makefile lowercased. Variables that might be set from the command line are uppercased. - -### Automatic variables -There are seven automatic variables. Automatic variables are set by `make` after a rules is matched. -They provide access to elements from the target and prerequisite lists. It this way you don't have -to explictily specify any filenames. - -| Variable | Function | -| -------- | -------- | -| $@ | The filename representing the target | -| $% | The filename element of an archive member specification | -| $< | The filename of the first prerequisite | -| $? | The names of all prerequisites that are newer than the target, separated by spaces | -| $^ | The filenames all the prerequisites, separated by spaces | -| $+ | Similar to $^ except that $+ include duplicates | -| $* | The stem of the target filename. | - -These seven variables have variants that get just the file's directory name or just the file name within -the directory. The variant variables names are formed by appending 'D' or 'F'. These variant variables are -more than one character long and so must be enclosed in parentheses, i.e. $(@D), $(@F). -See [GNU Make Automatic variables](https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html) - -### vpath +### An updated "Hello World!" example - introducing vpath In the following example we have reworked "Hello world"-example. The source files reside in a subdirectory `src`. The printf statement is moved to a function hello(), which is defined in a new file `module.c`. From 2c451b8760fdbad53b706c5fda41c80bd41611de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Lindi?= Date: Mon, 7 Oct 2024 13:52:08 +0200 Subject: [PATCH 3/5] Descripe append and target variable. --- doc/rules.md | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/doc/rules.md b/doc/rules.md index 27bd1ea..9c4df39 100644 --- a/doc/rules.md +++ b/doc/rules.md @@ -42,7 +42,30 @@ the course of a `makefile`. OUTPUT_DIR ?= $(PROJECT_DIR)/bin ``` The '?=' operator is called the *conditional variable assignment operator*. Here the the assignment is -performed only if the variable does not yet hava a value. +performed only if the variable does not yet have a value. + +### Append variable +The append assignment operator is '+='. This operator appends text to a variable. This operator is +particularly useful for collecting values into a variable incrementally. +```makefile +CPPFLAGS += -DUSE_NEW_MALLOC=1 +``` + +### Target variable +You can define a variable for a specific target, such that the variable is valid only for the target: +```makefile +gui.o: CPPFLAGS += -DUSE_NEW_MALLOC=1 +gui.o: gui.h +``` +While the *gui.o* target is being processed, the valu of CPPFLAGS will contain -DUSE_NEW_MALLOC=1 in +addition to its original contents. When the *gui.o* target is finished, CPPFLAGS will be set back to +its original value. The general syntax for target-specific variables is: +```makefile +target...: variable = value +target...: variable := value +target...: variable += value +target...: variable ?= value +``` ### Automatic variables There are seven automatic variables. Automatic variables are set by `make` after a rules is matched. @@ -234,10 +257,5 @@ One of them is how to make a executable from binary object files: This tells `make` to invoke the linker to link all the prerequisites together with possible other libraries to produce the target executable. -- simple expanded variable -- recursively expanded variable -- conditional variable -- append variable -- target variable -- static pattern rules -- suffix rules +- macro +- functions From 4f4db51086f449a86a65d370e6680c7500d73641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Lindi?= Date: Mon, 7 Oct 2024 14:26:42 +0200 Subject: [PATCH 4/5] Add description of macro. --- doc/rules.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/rules.md b/doc/rules.md index 9c4df39..f3a8653 100644 --- a/doc/rules.md +++ b/doc/rules.md @@ -88,6 +88,23 @@ more than one character long and so must be enclosed in parentheses, i.e. $(@D), See [GNU Make Automatic variables](https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html) +## Macro +```makefile +BIN := /usr/bin +PRINTF := $(BIN)/printf +DF := $(BIN)/df +AWK :- $(BIN)/awk + +define free-space + $(PRINTF) "Free disk space " + $(DF) . | $(AWK) 'NR == 2 { print $$4 }' +endef +``` +With `define - endef` command we can define a multiline variable, a variable that contains a script. +In the above example we have two-line script. With `define` the variable can contain embedded newlines. +Conseqeuently, we call it a macro to disguish from a single line variable. + + ## Rules The rule governing the building of the hello world program was so called _explicit_ rule. There are other types of rules as well, and we will be going through these now: From b7c98333ea0ce37693fd3e26e10289d12891e753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Lindi?= Date: Mon, 7 Oct 2024 15:15:59 +0200 Subject: [PATCH 5/5] Add description of functions. --- doc/rules.md | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/doc/rules.md b/doc/rules.md index f3a8653..001c707 100644 --- a/doc/rules.md +++ b/doc/rules.md @@ -105,6 +105,40 @@ In the above example we have two-line script. With `define` the variable can con Conseqeuently, we call it a macro to disguish from a single line variable. +## Functions +There is a range of functions define in `make`. Functions for transforming text is described in the +[GNU Make documentation](https://www.gnu.org/software/make/manual/make.html#Functions). Functions are called +just like variables, but often have arguments in addtion: +```makefile +$(function-name arguments) +``` +You can also define your own functions. Own-defined functions are invoked ved the `call` command. Here is +an example from Managing Projects with GNU Make, defining a function to terminate a process: +```makefile +AWK := awk +KILL := kill +KILL_FLAGS := -f +PS := ps +PS_FLAGS := -W +PS_FIELDS := "9 47 100" + +# $(call kill-program, awk-pattern) +define kill-program + @ $(PS) $(PS_FLAGS) | \ + $(AWK 'BEGIN { FIELDWIDTHS = $(PS_FIELDS) } \ + /$1/ { \ + print "Killing " $$3; \ + system( "$(KILL) $(KILL_FLAGS) " $$1 ) \ + }' +endef +``` +The function is called with the `call` command. Here we kill a vim process before compile a C-file: +```makefile +%.o: %c + $(call kill-program, vim) + $(CC) $(CFLAGS) -c $< -o $@ + + ## Rules The rule governing the building of the hello world program was so called _explicit_ rule. There are other types of rules as well, and we will be going through these now: @@ -273,6 +307,3 @@ One of them is how to make a executable from binary object files: This tells `make` to invoke the linker to link all the prerequisites together with possible other libraries to produce the target executable. - -- macro -- functions