Skip to content

Commit 675b1e6

Browse files
committed
Make edits
1 parent 4123473 commit 675b1e6

File tree

1 file changed

+113
-47
lines changed

1 file changed

+113
-47
lines changed

07-Building-with-Make.md

Lines changed: 113 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ You go to fetch ingredients from the refrigerator, but alas! It is empty.
99
Someone else has been eating all your sandwiches while you were engrossed in regular expressions.
1010

1111
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.
1313

1414
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.
1515
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
2929
Isn't there a Better Way?"
3030

3131
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]
3333
"Wow!" you exclaim through a mouthful of pickle, "This is yet another problem solved by GNU Make!"
3434

3535
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]
3636
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:
3838

3939
```makefile
4040

@@ -98,23 +98,24 @@ It has other uses, too: this book is built with `make`!
9898

9999
### A bit about compiling and linking
100100

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
106107
with the appropriate addresses.
107108

108109
You can separate these steps: `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]
110111

111112
To link a bunch of object files together, you call `g++` again[^confusing] like so: `g++ file1.o file2.o -o myprogram`.
112113
`g++` notices that you have given it a bunch of object files, so instead of going through the compilation process,
113114
it prepares a detailed list[^twice] explaining to the linker which files and libraries you used and how to combine them together.
114115
It sets the list next to your object files[^milk2] and waits for the linker.
115116
When the linker arrives, it paws through your object files, eats all the cookies,
116-
and then through a terrifying process not entirely understood by humans[^exaggerating],
117-
leaves you a beautiful executable wrapped up under your tree[^lovecraft].
117+
and then through a terrifying process not entirely understood by humans,[^exaggerating]
118+
leaves you a beautiful executable wrapped up under your tree.[^lovecraft]
118119

119120
<!-- copyright
120121
![How Executables are Made](07/compile.png){width=70%}
@@ -147,9 +148,9 @@ Here, `program` is the target name. In a makefile, every target name is followed
147148
On the next line, indented one tab, is the command that, when run, produces a file named `program`.
148149

149150
**NOTE:** Unlike most programs, `make` *requires* that you use tabs, not spaces, to indent.[^tabs]
150-
If you use spaces, you'll get a very strange error message. So make sure to set your editor to put actual tabs in your makefiles.
151+
If you use spaces, you'll get a very strange error message. So, make sure to set your editor to put actual tabs in your makefiles.
151152

152-
Once you've put this rule in your makefile, you can tell `make` to build `program` by running `make program`.[^execute]
153+
Once you've put this rule in your makefile, you can tell `make` to build your `program` executable by running `make program` in your shell.[^execute]
153154
You can also just run `make`; if you don't specify a target name, `make` will build the first target in your makefile.
154155

155156
Now, if you edit your code and run `make program` again, you'll notice a problem:
@@ -159,11 +160,12 @@ $ make program
159160
make: 'program' is up to date.
160161
```
161162
162-
Well, that's no good. `make` determines if it needs to re-build a target by looking at when the associated file was last modified and comparing that
163-
with the modification times of the files the target depends on.
164-
In this case, our `program` has no dependencies, so `make` doesn't think anything needs to happen!
163+
Well, that's no good. Why doesn't `make` want to build our program again?
164+
`make` determines if it needs to re-build a target by comparing when the target was last modified to
165+
the modification times of the files the target depends on.
166+
We haven't listed any dependencies for the `program` target, so `make` doesn't think anything needs to happen!
165167
166-
Let's fix that. Since `make` is not omniscient[^yet], we need to explicitly state what each file depends on.
168+
Let's fix that. Since `make` is not omniscient,[^yet] we need to explicitly state what files each target depends on.
167169
For our example, let's suppose we have a classic CS 1570 assignment with a `main.cpp` file, a `funcs.cpp` file, and an associated `funcs.h` header.
168170
Whenever any one of these files change, we want to recompile `program`.
169171
We specify these dependencies after the colon following the target name:
@@ -176,8 +178,8 @@ program: main.cpp funcs.h funcs.cpp
176178
Now when we change those files and run `make`, it will re-build `program`!
177179

178180
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.
181183
Continuing our example, we add two new targets for our object files, `main.o` and `funcs.o`:
182184

183185
```makefile
@@ -207,14 +209,19 @@ But now you know everything you need to get started using `make` to `make life-e
207209

208210
### Phony Targets
209211

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.)
211216
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.
214217

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`!"
218225

219226
Let's make a `clean` target for our example from the last section.
220227
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:
239246
Now when you run `make clean`, it will delete any object files, as well as your compiled program.[^anger]
240247
There are a few pieces to this target:
241248

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.
243250
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.
247255
3. The `@` in front of a command tells `make` to not print the command to the screen when `make` executes it.
248256
We use it here so the output of `make clean` doesn't clutter up the screen.
249257

250258
### Variables
251259

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]).
254263

255264
Here's the syntax for variables:
256265

257-
- `var=value` sets `var` to `value.
266+
- `var=value` sets the variable `var` to `value`.
258267
- `${var}` or `$(var)` accesses the value of `var`.[^vars]
259268
- The line `target: var=thing` sets the value of `var` to `thing` when building `target` and its dependencies.
260269

@@ -291,30 +300,31 @@ clean:
291300
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.
292301
(We'll talk about the `-g` flag in the next chapter. It's quite cool.)
293302

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,
295304
you will want to run `make clean` first so that `make` will rebuild all your code with the appropriate compiler flags.
296305

297306
### Pattern Targets
298307

299308
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.
302311

303312
Before we set up a pattern target, we need some way to identify the files we want to compile.
304313
`make` supports a wide variety of fancy variable assignment statements that are incredibly handy in combination with pattern targets.
305314

306315
You can store the files that match a glob expression using the `wildcard` function:
307316
`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`.
309318
310319
Once you have your list of C`++` files, you may want a list of their associated object files.
311320
You can do pattern substitution on a list of filenames like so:
312321
`objects=$(cppfiles:%.cpp=%.o)`.
313322
This will turn your list of files ending in `.cpp` into a list of files ending in `.o` instead!
314323
315324
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.
317326
327+
Hmm, but how would we write a command for this target? `g++` still needs to know the actual names of our files!
318328
`make` has several special variables that you can use in any target, but are especially handy for pattern targets:
319329
320330
- `$@`: The name of the target.
@@ -335,17 +345,28 @@ program: ${OBJECTS}
335345
g++ -c $<
336346
```
337347

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, we create three variables: `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.
341352

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.
343355

344-
`make` has a few flags that come in handy from time to time:
356+
How do we get these object files? From the pattern rule at the end!
357+
The rule `%.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!
345360

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+
In all honesty, this is something of a hack: 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!
349370

350371
\newpage
351372
## Questions
@@ -377,6 +398,51 @@ funcs.o: funcs.cpp funcs.h
377398

378399
## Quick Reference
379400

401+
### Useful `make` Flags
402+
403+
`make` has a few flags that come in handy from time to time:
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+
Do not forget: you must use tabs, not spaces, to indent commands in makefiles!
412+
413+
#### Targets
414+
415+
Creating a target:
416+
```make
417+
target-name: list of dependencies
418+
command-that-produces target-name from list of dependencies
419+
```
420+
421+
Pattern targets:
422+
```
423+
%.o: %.cpp
424+
command that produces a .o file from a .cpp file
425+
```
426+
427+
Telling make that a target doesn't produce a file:
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+
- The line `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.
439+
440+
Special variables in targets (known as [automatic variables](https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html)):
441+
442+
- `$@`: The name of the target.
443+
- `$<`: The name of the first dependency.
444+
- `$^`: The names of all the dependencies.
445+
380446
## Further Reading
381447

382448
- [The GNU Make Manual](https://www.gnu.org/software/make/manual/html_node/index.html)
@@ -415,10 +481,10 @@ Fortunately some other poor soul (i.e., your compiler maintainer) has figured th
415481
Maybe re-doing the whole process from scratch will fix things.
416482
(It probably won't, but hey, it's worth a shot!)
417483
[^retval]: In other words, a non-zero return value from that command.
418-
[^headers]: This is because header files might be included in several places.
419-
If you're interested in more accurately calculating dependencies, check out the `makedepend` program.
420484
[^cores]: The general rule of thumb for the fastest builds is to use one more job than you have CPU cores.
421485
This makes sure there's always a job ready to run even if some of them need to load files off the hard drive.
422486
[^tofu]: Or tofu and potatoes, if that's your thing.
423487
[^vars]: Be careful not to confuse this with `bash`'s `$()`, which executes whatever is between the parentheses.
424488
[^execute]: Don't try to execute the makefile itself. `bash` is confused enough without trying to interpret `make`'s syntax!
489+
[^hope]: I hope so, at least...I've been stuck in this basement compiling the Linux kernel by hand for the past 82 years!
490+
[^clang]: And that it has nice error messages!

0 commit comments

Comments
 (0)