Skip to content

Commit 01833f2

Browse files
committed
Add some more detailed explanation on make features
- recursively expanded variables are commonly misused in make - some notes on particularities of whitespace in make
1 parent 8461c1b commit 01833f2

File tree

1 file changed

+100
-4
lines changed

1 file changed

+100
-4
lines changed

learn/building_programs/build_tools.md

Lines changed: 100 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ action has to be performed.
215215
In the end, we will have a look at a complete ``Makefile``.
216216

217217
```make
218-
# Disable all of make's implicit rules (similar to Fortran's implicit none)
218+
# Disable all of make's built-in rules (similar to Fortran's implicit none)
219219
MAKEFLAGS += --no-builtin-rules --no-builtin-variables
220220
# configuration
221221
FC := gfortran
@@ -247,7 +247,7 @@ clean:
247247
```
248248

249249
Since you are starting with ``make`` we highly recommend to always include
250-
the first line, like with Fortrans ``implicit none`` we do not want to have
250+
the first line, like with Fortran's ``implicit none`` we do not want to have
251251
implicit rules messing up our ``Makefile`` in surprising and harmful ways.
252252

253253
Next, we have a configuration section where we define variables, in case you
@@ -264,15 +264,17 @@ Also, we slightly changed the build rule for the object files to account for
264264
appending the ``.o`` suffix instead of substituting it.
265265
Notice that we still need to explicitly define the interdependencies in the
266266
``Makefile``. We also added a dependency for the object files on the ``Makefile``
267-
itself, in case you change the compiler, this will allow you to savely rebuild.
267+
itself, in case you change the compiler, this will allow you to safely rebuild.
268268

269269
Now you know enough about ``make`` to use it for building small projects.
270+
If you plan to use ``make`` more extensively, we have compiled a few tips
271+
for you as well.
270272

271273
{% capture note %}
272274

273275
In this guide, we avoided and disabled a lot of the commonly used ``make``
274276
features that can be particularly troublesome if not used correctly, we highly
275-
recommend staying away from the buildin rules and variables if you do not feel
277+
recommend staying away from the builtin rules and variables if you do not feel
276278
confident working with ``make``, but explicitly declare all variables and rules.
277279

278280
You will find that ``make`` is capable tool to automate short interdependent
@@ -284,6 +286,100 @@ completely or in parts.
284286
{% include note.html title="Note" content=note %}
285287

286288

289+
### Recursively expanded variables
290+
291+
Commonly seen in many projects are recursively expanded variables (declared with
292+
``=`` instead of ``:=``). Recursive expansion of your variables allows out-of-order
293+
declaration and other neat tricks with ``make``, since they are defined as rules,
294+
which are expanded at runtime, rather than being defined while parsing.
295+
296+
For example, declaring and using your Fortran flags with this snippet will work
297+
completely fine:
298+
299+
```make
300+
all:
301+
echo $(FFLAGS)
302+
303+
FFLAGS = $(include_dirs) -O
304+
include_dirs += -I./include
305+
include_dirs += -I/opt/some_dep/include
306+
```
307+
308+
You should find the expected (or maybe unexpected) printout after running ``make``
309+
310+
echo -I./include -I/opt/some_dep/include -O
311+
-I./include -I/opt/some_dep/include -O
312+
313+
{% include note.html content="appending with ``+=`` to an undefined variable will produce a recursively expanded variable with this state being inherited for all further appending." %}
314+
315+
While, it seems like an interesting feature to use, it tends to lead to
316+
surprising and expected outcomes. Usually, when defining variables like your
317+
compiler, there is little reason to actually use the recursive expansion at all.
318+
319+
The same can easily be archived using the ``:=`` declaration:
320+
321+
```make
322+
all:
323+
echo $(FFLAGS)
324+
325+
include_dirs := -I./include
326+
include_dirs += -I/opt/some_dep/include
327+
FFLAGS := $(include_dirs) -O
328+
```
329+
330+
{% include important.html content="always think of a ``Makefile`` as a whole set of rules, it must be parsed completely before any rule can be evaluated." %}
331+
332+
You can use whatever kind of variables you like most, mixing them should be done
333+
carefully, of course. It is important to be aware of the differences between the
334+
two kinds and the respective implications.
335+
336+
337+
### Comments and whitespace
338+
339+
There are some caveats with whitespace and comments, which might pop up from
340+
time to time when using ``make``. First, ``make`` does not know of any data
341+
type except for strings and the default separator is just a space.
342+
This means ``make`` will give a hard time trying to build a project which
343+
has spaces in file names. If you encounter such case, renaming the file
344+
is possibly the easiest solution at hand.
345+
346+
Another common problem is leading and trailing whitespace, once introduced,
347+
``make`` will happily carry it along and it does in fact make a difference
348+
when comparing strings in ``make``.
349+
350+
Those can be introduced by comments like
351+
352+
```make
353+
prefix := /usr # path to install location
354+
install:
355+
echo "$(prefix)/lib"
356+
```
357+
358+
While the comment will be correctly removed by ``make``, the trailing two spaces
359+
are now part of the variable content. Run ``make`` and check that this is indeed
360+
the case:
361+
362+
```
363+
echo "/usr /lib"
364+
/usr /lib
365+
```
366+
367+
To solve this issue, you can either move the comment, or strip the whitespace with
368+
the ``strip`` function instead. Alternatively, you could try to ``join`` the
369+
strings.
370+
371+
```make
372+
prefix := /usr # path to install location
373+
install:
374+
echo "$(strip $(prefix))/lib"
375+
echo "$(join $(join $(prefix), /), lib)"
376+
```
377+
378+
All in all, none of this solutions will make your ``Makefile`` more readable,
379+
therefore, it is prudent to pay extra attention to whitespace and comments when
380+
writing and using ``make``.
381+
382+
287383
## The meson build system
288384

289385
After you have learned the basics of ``make``, which we call a low-level build

0 commit comments

Comments
 (0)