You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -9,7 +9,7 @@ You go to fetch ingredients from the refrigerator, but alas! It is empty.
9
9
Someone else has been eating all your sandwiches while you were engrossed in regular expressions.
10
10
11
11
You hop on your velocipede[^bike] and pedal down to the local bodega only to discover that they, too, are out of sandwich fixin's.
12
-
Just as you feared -- you are left with no choice other than to derive a sandwich from first principles.
12
+
Just as you feared --- you are left with no choice other than to derive a sandwich from first principles.
13
13
14
14
A day of cycling rewards you with the necessities: brisket, salt, vinegar, cucumbers, yeast, rye, wheat, caraway seeds, sugar, mustard seed, garlic cloves, red bell peppers, dill, and peppercorns.
15
15
Fortunately you didn't have to tow a cow home!
@@ -29,12 +29,12 @@ And whenever I eat my way through what I've prepared, I'll have to do it all ove
29
29
Isn't there a Better Way?"
30
30
31
31
A bite of crunchy pickle is accompanied by a revelation.
32
-
If the human brain is a computer, then this sandwich is code[^code]: without it, your brain could compute nothing![^torture]
32
+
If the human brain is a computer, then this sandwich is code:[^code] without it, your brain could compute nothing![^torture]
33
33
"Wow!" you exclaim through a mouthful of pickle, "This is yet another problem solved by GNU Make!"
34
34
35
35
Using the powers of `git`, you travel into the future, read the rest of this chapter, then head off your past self before they pedal headfirst down the road of wasted time.[^time]
36
36
Instead of this hippie artisanal handcrafted sandwich garbage, you sit your past self down at their terminal and whisper savory nothings[^nothings] in their ear.
37
-
They -- you -- crack open a fresh editor and pen the pastrami of your dreams:
37
+
They --- you --- crack open a fresh editor and pen the pastrami of your dreams:
38
38
39
39
```makefile
40
40
@@ -98,23 +98,24 @@ It has other uses, too: this book is built with `make`!
98
98
99
99
### A bit about compiling and linking
100
100
101
-
Before we can set up a makefile for a C`++` project, we need to talk about compiling and linking code.
102
-
"Compiling" refers to the process of turning C`++` code into machine instructions.
103
-
Each `.cpp` file gets compiled separately, so if you use something defined in another file or library -- for example, `cin` --
104
-
the compiler leaves itself a note saying "later on when you figure out where `cin` is, put its address here".
105
-
Once your code is compiled, the linker then goes through all your compiled code and any libraries you have used and fills in all the notes
101
+
Before we can set up a makefile for a C`++` project, we need to talk about *compiling* and *linking* code.
102
+
*Compiling* refers to the process of turning C`++` code into machine instructions.
103
+
Each `.cpp` file gets compiled separately, so if you use something defined in another file or library --- for example, `cin` ---
104
+
the compiler doesn't know exactly what memory address that thing will end up at.
105
+
So, instead of putting in a memory address, it leaves itself a note saying "later on when you figure out where `cin` is, put its address here".
106
+
Once your code is compiled, the *linker* then goes through all your compiled code and any libraries you have used and fills in all the notes
106
107
with the appropriate addresses.
107
108
108
109
Youcanseparatethesesteps: `g++ -c file.cpp` just does the compilation step to `file.cpp` and produces a file named `file.o`.
109
-
This is a so-called *object file*; it consists of assembly code and cookies left out for the linker.[^milk]
110
+
This is a so-called **object file**; it consists of assembly code and cookies left out for the linker.[^milk]
Now when we change those files and run `make`, it will re-build `program`!
177
179
178
180
This is all well and good, you say, but what about all those promises of sweet, sweet incremental compilation the previous section suggested?
179
-
Not to worry! You can tell `make` about each one of your targets and dependencies and it will do the work of running each compilation and linking step
180
-
as needed.
181
+
Not to worry: you can have one target depend on files produced by other targets!
182
+
Then, `make` will do the work of running each compilation and linking step as needed.
181
183
Continuing our example, we add two new targets for our object files, `main.o` and `funcs.o`:
182
184
183
185
```makefile
@@ -207,14 +209,19 @@ But now you know everything you need to get started using `make` to `make life-e
207
209
208
210
### Phony Targets
209
211
210
-
Building files is great and all, but sometimes there are commands that you want to run often that you'd really rather not type out each time.
212
+
Building files is great and all, but there's more to life than just compiling code.[^hope]
213
+
Sometimes you'll have a somewhat-complicated command that you'll want to run often --- for example,
214
+
commands to clean up all the files `make` generates in your current directory.
215
+
(We'll also want something similar to run unit tests later on in this book.)
211
216
You *could* write a shell script, but you've already got a makefile; why not use that?
212
-
The most common example of this is commands to clean up all the files `make` generates in your current directory.
213
-
In this case, you don't want to generate any new files, and you don't want to lie to `make` because you're an honest upstanding citizen.
214
217
215
-
Fortunately, `make` supports this through something called *phony targets*.
216
-
You can tell `make`, "Hey, this target isn't actually a file; just run the commands listed here whenever I ask you to build this target,"
217
-
and `make` will be like, "Sure thing, boss! Look at me, not being confused at all about why there's no file named 'clean'!"
218
+
However, `make` expects targets to generate files, so if you make a target named `clean` that just deletes stuff,
219
+
it's possible for `make` to get a little confused.
220
+
You don't want to generate any new files, and you don't want to lie to `make` because you're an honest upstanding citizen.
221
+
222
+
Fortunately, `make` supports targets that don't produce files through something called *phony targets*.
223
+
You can tell `make`, "Hey, this target doesn't actually produce a file; just run the commands listed here whenever I ask you to build this target,"
224
+
and `make` will be like, "Sure thing, boss! Look at me, not being confused at all about why there's no file named `clean`!"
218
225
219
226
Let's make a `clean` target for our example from the last section.
220
227
Having a target named `clean` that gets rid of all the compiled files in your current directory is good `make` etiquette.
@@ -239,22 +246,24 @@ clean:
239
246
Now when you run `make clean`, it will delete any object files, as well as your compiled program.[^anger]
240
247
Thereareafewpiecestothistarget:
241
248
242
-
1. There is a special target named `.PHONY`. Every target `.PHONY` depends on is a phony target that gets run every time you ask `make` to build it.
249
+
1. There is a special target named `.PHONY`. Every target `.PHONY` depends on is a *phony target* that gets run every time you ask `make` to build it.
243
250
2. The `-` in front of a command tells `make` to ignore errors[^retval] from that command.
244
-
Normally when a program exits with an error, `make` bails out under the assumption that if that command failed, anything that depended on it probably won't work either.
245
-
Rather than trying anyway, it stops and lets you know what command failed so you can fix it.
246
-
In this case, we don't care if there isn't a file named `program` to delete; we just want to delete them if they exist.
251
+
Normally when a program exits with an error, `make` bails out under the assumption that if that command failed,
252
+
anything that was supposed to run after it probably won't work either.
253
+
Rather than trying anyway, it stops and lets you know what command failed so you can fix whatever is broken.
254
+
In this case, we don't care if there isn't a file named `program` to delete; we just want to delete it if it exists.
247
255
3. The `@` in front of a command tells `make` to not print the command to the screen when `make` executes it.
248
256
We use it here so the output of `make clean` doesn't clutter up the screen.
249
257
250
258
### Variables
251
259
252
-
When writing more complex makefiles, you will want to use variables so that you can easily change targets in the future.
253
-
It is common to use variables to hold lists of files, compiler flags, and even programs!
260
+
Variables come in handy in a number of places in makefiles.
261
+
Maybe you don't want to have to manually list out every object file,
262
+
or maybe you want to make it easy to switch which compiler you're using (I hear all the cool kids are using `clang++`[^clang]).
254
263
255
264
Here'sthesyntaxforvariables:
256
265
257
-
- `var=value` sets `var` to `value.
266
+
- `var=value` sets the variable `var` to `value`.
258
267
- `${var}` or `$(var)` accesses the value of `var`.[^vars]
259
268
-Theline`target: var=thing` sets the value of `var` to `thing` when building `target` and its dependencies.
260
269
@@ -291,30 +300,31 @@ clean:
291
300
Note that the `debug` target doesn't actually have any commands to run; it just changes the `CFLAGS` variable and then builds the `program` target.
292
301
(We'll talk about the `-g` flag in the next chapter. It's quite cool.)
293
302
294
-
As an aside, since `make` only tracks the modification times of files, when switching from doing a debug build to a release build or vice-versa,
303
+
**Note**: since `make` only tracks the modification times of files, when switching from doing a debug build to a release build or vice-versa,
295
304
you will want to run `make clean` first so that `make` will rebuild all your code with the appropriate compiler flags.
296
305
297
306
### Pattern Targets
298
307
299
308
You've probably noticed that our example so far has had an individual target for each object file.
300
-
If you had more files, adding all those targets would be a lot of work.
301
-
Instead of writing each of these out manually, `make` supports pattern targets that can save you a lot of work.
309
+
If you had a lot more files, adding all those targets by hand would be a lot of work.
310
+
Instead of writing each of these out manually, `make` has *pattern targets* that can save you a lot of work.
302
311
303
312
Before we set up a pattern target, we need some way to identify the files we want to compile.
304
313
`make` supports a wide variety of fancy variable assignment statements that are incredibly handy in combination with pattern targets.
`cppfiles=$(wildcard*.cpp)`<!--* my markdown highlighter doesn't understand verbatim blocks so this shuts it up about italics-->
308
-
stores the name of every file ending in `.cpp` in a variable named `cppfiles`.
317
+
stores the name of every file in the current directory ending in `.cpp` in a variable named `cppfiles`.
309
318
310
319
Once you have your list of C`++` files, you may want a list of their associated object files.
311
320
You can do pattern substitution on a list of filenames like so:
312
321
`objects=$(cppfiles:%.cpp=%.o)`.
313
322
This will turn your list of files ending in `.cpp` into a list of files ending in `.o` instead!
314
323
315
324
When writing a pattern rule, as with substitution, you use `%` for the variable part of the target name.
316
-
For example: `%.o: %.cpp` creates a target that builds a `.o` file from a matching `.cpp` file.
325
+
For example: `%.o: %.cpp` creates a target that builds a file ending in `.o` from a matching `.cpp` file.
317
326
327
+
Hmm, but how would we write a command for this target? `g++` still needs to know the actual names of our files!
318
328
`make` has several special variables that you can use in any target, but are especially handy for pattern targets:
319
329
320
330
- `$@`: The name of the target.
@@ -335,17 +345,28 @@ program: ${OBJECTS}
335
345
g++ -c $<
336
346
```
337
347
338
-
Now our `program` target depends on all the object files which are calculated from the names of all the `.cpp` files in the current directory.
339
-
The target for each object file depends on the associated `.cpp` file as well as all the headers.[^headers]
340
-
With this pattern rule, you won't need to update your makefile if you add more files to your program later!
348
+
Let's walk through this example step by step.
349
+
First,wecreatethreevariables: `SOURCES` will keep track of all our `.cpp` files,
350
+
`OBJECTS` contains the names of the object files we want to produce from our `.cpp` files,
351
+
and `HEADERS` contains all our header files.
341
352
342
-
### Useful `make` Flags
353
+
The `program` target now depends on all our object files.
354
+
To produce the `program` executable, we tell `g++` to link all our object files into a `program` executable.
343
355
344
-
`make`hasafewflagsthatcomeinhandyfromtimetotime:
356
+
How do we get these object files? From the pattern rule at the end!
357
+
Therule`%.o: %.cpp ${HEADERS}` says "to make a file named `whatever.o`, you need a file named `whatever.cpp` and every header file in the current directory".
358
+
To produce `whatever.o`, we compile the first dependency (which will be `whatever.cpp`) with `g++`.
359
+
With this pattern rule, you won't need to update your makefile if you add more files to your program later!
345
360
346
-
- `-j3` runs up to 3 jobs in parallel.[^cores]
347
-
- `-B` makes targets even if they seem up-to-date. Useful if you forget a dependency or don't want to run `make clean`!
348
-
- `-f <filename>` uses a different makefile other than one named `makefile` or `Makefile`.
361
+
Why have every object file depend on all headers?
362
+
Inallhonesty,thisissomethingofahack: we don't have a simple way to automatically figure out exactly which headers each `.cpp` file `#include`s.
363
+
So, we just make it so any header change causes everything to recompile.
364
+
Typically this is a fine assumption --- in practice, you spend most of your time editing `.cpp` files, and when you do change a header
365
+
(say, changing the type of a function parameter), that usually requires changes in a bunch of places anyway.
366
+
If you're interested in more accurately calculating dependencies, check out the `makedepend` program!
367
+
368
+
Another upside of using patterns in makefiles is being able to easily copy an existing makefile into a new project.
369
+
Done right, you'll have to change the program name (and if you make a variable for that, it's a change in one place) and little else!
349
370
350
371
\newpage
351
372
## Questions
@@ -377,6 +398,51 @@ funcs.o: funcs.cpp funcs.h
377
398
378
399
## Quick Reference
379
400
401
+
### Useful `make` Flags
402
+
403
+
`make`hasafewflagsthatcomeinhandyfromtimetotime:
404
+
405
+
- `-j3` runs up to 3 jobs (i.e., builds 3 targets) in parallel.[^cores]
406
+
- `-B` makes targets even if they seem up-to-date. Useful if you forget a dependency or don't want to run `make clean`!
407
+
- `-f <filename>` uses a different makefile other than one named `makefile` or `Makefile`.
408
+
409
+
### Syntax
410
+
411
+
Donotforget: you must use tabs, not spaces, to indent commands in makefiles!
412
+
413
+
#### Targets
414
+
415
+
Creatingatarget:
416
+
```make
417
+
target-name: list of dependencies
418
+
command-that-produces target-name from list of dependencies
419
+
```
420
+
421
+
Patterntargets:
422
+
```
423
+
%.o: %.cpp
424
+
command that produces a .o file from a .cpp file
425
+
```
426
+
427
+
Tellingmakethatatargetdoesn'tproduceafile:
428
+
```make
429
+
.PHONY: target-name
430
+
```
431
+
432
+
#### Variables
433
+
434
+
- `var=value` sets the variable `var` to `value`.
435
+
- `${var}` or `$(var)` accesses the value of `var`.[^vars]
436
+
-Theline`target: var=thing` sets the value of `var` to `thing` when building `target` and its dependencies.
437
+
- `txtfiles = $(wildcard *.txt)` stores the name of every file matching the glob `*.txt` in the `txtfiles` variable.
438
+
-`cowfiles=$(txtfiles:%.txt=%.cow)` turns every `.txt` filename in `txtfiles` into a corresponding name ending in `.cow` instead.
0 commit comments