Skip to content

Commit

Permalink
Merge pull request #168 from swcarpentry/auto-vars
Browse files Browse the repository at this point in the history
Automatic variables
  • Loading branch information
gcapes authored Apr 13, 2023
2 parents 21cb0bb + 7720cd2 commit 6b3e05b
Show file tree
Hide file tree
Showing 16 changed files with 55 additions and 97 deletions.
14 changes: 7 additions & 7 deletions _episodes/04-dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,16 +217,16 @@ downstream steps.
{: .challenge}
We still have to add the `testzipf.py` script as dependency to
`results.txt`. Given the answer to the challenge above, we cannot use
`$^` in the rule.
We can however move `testzipf.py` to be the
first dependency and then use `$<` to refer to it.
In order to refer to the `.dat` files, we can just use `*.dat` for now (we will
cover a better solution later on).
`results.txt`.
Given the answer to the challenge above,
we need to make a couple of small changes so that we can still use automatic variables.
We'll move `testzipf.py` to be the first dependency and then edit the action
so that we pass all the dependencies as arguments to python using `$^`.
~~~
results.txt : testzipf.py isles.dat abyss.dat last.dat
python $< *.dat > $@
python $^ > $@
~~~
{: .language-make}
Expand Down
31 changes: 9 additions & 22 deletions _episodes/05-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,18 @@ rule]({{ page.root }}/reference.html#pattern-rule) which can be used to build an
`.dat` file from a `.txt` file in `books/`:

~~~
%.dat : books/%.txt countwords.py
python countwords.py $< $*.dat
%.dat : countwords.py books/%.txt
python $^ $@
~~~
{: .language-make}

`%` is a Make [wildcard]({{ page.root }}/reference.html#wildcard). `$*` is a special
variable which gets replaced by the [stem]({{ page.root }}/reference.html#stem) with
which the rule matched.
`%` is a Make [wildcard]({{ page.root }}/reference.html#wildcard),
matching any number of any characters.

This rule can be interpreted as:
"In order to build a file named `[something].dat` (the target)
find a file named `books/[that same something].txt` (the dependency)
and run `countwords.py [the dependency] [the target]`."
find a file named `books/[that same something].txt` (one of the dependencies)
and run `python [the dependencies] [the target]`."

If we re-run Make,

Expand Down Expand Up @@ -77,14 +76,14 @@ Our Makefile is now much shorter and cleaner:
~~~
# Generate summary table.
results.txt : testzipf.py isles.dat abyss.dat last.dat
python $< *.dat > $@
python $^ > $@
# Count words.
.PHONY : dats
dats : isles.dat abyss.dat last.dat
%.dat : books/%.txt countwords.py
python countwords.py $< $*.dat
%.dat : countwords.py books/%.txt
python $^ $@
.PHONY : clean
clean :
Expand All @@ -99,15 +98,3 @@ clean :
> contains all of our work so far.
{: .callout}

This episode has introduced pattern rules, and used the `$*` variable
in the `dat` rule in order to explain how to use it.
Arguably, a neater solution would have been to use `$@` to refer to
the target of the current rule (see below),
but then we wouldn't have learned about `$*`.

```
%.dat : books/%.txt countwords.py
python countwords.py $< $@
```
{: .language-make}

19 changes: 6 additions & 13 deletions _episodes/06-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,10 @@ COUNT_SRC=countwords.py
This is a variable [assignment]({{ page.root }}/reference.html#assignment) -
`COUNT_SRC` is assigned the value `countwords.py`.

`countwords.py` is our script and it is invoked by passing it to
`python`. We can introduce another couple of variables to represent this
execution:
We can do the same thing with the interpreter language used to run the script:

~~~
LANGUAGE=python
COUNT_EXE=$(LANGUAGE) $(COUNT_SRC)
~~~
{: .language-make}

Expand All @@ -46,11 +43,9 @@ write it, or reference it, in this way.

Here we reference the variables `LANGUAGE` and `COUNT_SRC`. This tells Make to
replace the variable `LANGUAGE` with its value `python`,
and to replace the variable `COUNT_SRC` with its value `countwords.py`. When
Make is run it will assign to `COUNT_EXE` the value `python
countwords.py`.
and to replace the variable `COUNT_SRC` with its value `countwords.py`.

Defining the variable `COUNT_EXE` in this way avoids repeating `python` in our
Defining the variable `LANGUAGE` in this way avoids repeating `python` in our
Makefile, and allows us to easily
change how our script is run (e.g. we might want to use a different
version of Python and need to change `python` to `python2` -- or we might want
Expand All @@ -59,10 +54,10 @@ to rewrite the script using another language (e.g. switch from Python to R)).
> ## Use Variables
>
> Update `Makefile` so that the `%.dat` rule
> references the variables `COUNT_SRC` and `COUNT_EXE`.
> references the variable `COUNT_SRC`.
> Then do the same for the `testzipf.py` script
> and the `results.txt` rule,
> using `ZIPF_SRC` and `ZIPF_EXE` as variable names
> using `ZIPF_SRC` as the variable name.
>
> > ## Solution
> > [This Makefile]({{ page.root }}/code/06-variables-challenge/Makefile)
Expand All @@ -79,11 +74,9 @@ the original Makefile). Let us create `config.mk`:
# Count words script.
LANGUAGE=python
COUNT_SRC=countwords.py
COUNT_EXE=$(LANGUAGE) $(COUNT_SRC)
# Test Zipf's rule
ZIPF_SRC=testzipf.py
ZIPF_EXE=$(LANGUAGE) $(ZIPF_SRC)
~~~
{: .language-make}

Expand All @@ -103,7 +96,7 @@ $ make results.txt
~~~
{: .language-bash}

We have separated the configuration of our Makefile from its rules,
We have separated the configuration of our Makefile from its rules --
the parts that do all the work. If we want to change our script name
or how it is executed we just need to edit our configuration file, not
our source code in `Makefile`. Decoupling code from configuration in
Expand Down
24 changes: 7 additions & 17 deletions _episodes/07-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ include config.mk
# Generate summary table.
results.txt : $(ZIPF_SRC) isles.dat abyss.dat last.dat
$(ZIPF_EXE) *.dat > $@
$(LANGUAGE) $^ > $@
# Count words.
.PHONY : dats
dats : isles.dat abyss.dat last.dat
%.dat : books/%.txt $(COUNT_SRC)
$(COUNT_EXE) $< $*.dat
%.dat : $(COUNT_SRC) books/%.txt
$(LANGUAGE) $^ $@
.PHONY : clean
clean :
Expand Down Expand Up @@ -132,14 +132,6 @@ clean :
~~~
{: .language-make}

Let's also tidy up the `%.dat` rule by using the automatic variable `$@` instead
of `$*.dat`:

```
%.dat : books/%.txt $(COUNT_SRC)
$(COUNT_EXE) $< $@
```
{: .language-make}

Let's check:

Expand All @@ -163,7 +155,7 @@ We can also rewrite `results.txt`:

~~~
results.txt : $(ZIPF_SRC) $(DAT_FILES)
$(ZIPF_EXE) $(DAT_FILES) > $@
$(LANGUAGE) $^ > $@
~~~
{: .language-make}

Expand Down Expand Up @@ -215,14 +207,14 @@ DAT_FILES=$(patsubst books/%.txt, %.dat, $(TXT_FILES))
# Generate summary table.
results.txt : $(ZIPF_SRC) $(DAT_FILES)
$(ZIPF_EXE) $(DAT_FILES) > $@
$(LANGUAGE) S^ > $@
# Count words.
.PHONY : dats
dats : $(DAT_FILES)
%.dat : books/%.txt $(COUNT_SRC)
$(COUNT_EXE) $< $@
%.dat : $(COUNT_SRC) books/%.txt
$(LANGUAGE) $^ $@
.PHONY : clean
clean :
Expand All @@ -242,11 +234,9 @@ Remember, the `config.mk` file contains:
# Count words script.
LANGUAGE=python
COUNT_SRC=countwords.py
COUNT_EXE=$(LANGUAGE) $(COUNT_SRC)
# Test Zipf's rule
ZIPF_SRC=testzipf.py
ZIPF_EXE=$(LANGUAGE) $(ZIPF_SRC)
~~~
{: .language-make}

Expand Down
6 changes: 3 additions & 3 deletions _episodes/08-self-doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ which `sed` can detect. Since Make uses `#` for comments, we can use
~~~
## results.txt : Generate Zipf summary table.
results.txt : $(ZIPF_SRC) $(DAT_FILES)
$(ZIPF_EXE) $(DAT_FILES) > $@
$(LANGUAGE) $^ > $@
## dats : Count words in text files.
.PHONY : dats
dats : $(DAT_FILES)
%.dat : books/%.txt $(COUNT_SRC)
$(COUNT_EXE) $< $@
%.dat : $(COUNT_SRC) books/%.txt
$(LANGUAGE) $^ $@
## clean : Remove auto-generated files.
.PHONY : clean
Expand Down
2 changes: 1 addition & 1 deletion code/04-dependencies/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Generate summary table.
results.txt : testzipf.py isles.dat abyss.dat last.dat
python $< *.dat > $@
python $^ > $@

# Count words.
.PHONY : dats
Expand Down
6 changes: 3 additions & 3 deletions code/05-patterns/Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Generate summary table.
results.txt : testzipf.py isles.dat abyss.dat last.dat
python $< *.dat > $@
python $^ > $@

# Count words.
.PHONY : dats
dats : isles.dat abyss.dat last.dat

%.dat : books/%.txt countwords.py
python countwords.py $< $*.dat
%.dat : countwords.py books/%.txt
python $^ $@

.PHONY : clean
clean :
Expand Down
8 changes: 3 additions & 5 deletions code/06-variables-challenge/Makefile
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
LANGUAGE=python
COUNT_SRC=countwords.py
COUNT_EXE=$(LANGUAGE) $(COUNT_SRC)
ZIPF_SRC=testzipf.py
ZIPF_EXE=$(LANGUAGE) $(ZIPF_SRC)

# Generate summary table.
results.txt : $(ZIPF_SRC) isles.dat abyss.dat last.dat
$(ZIPF_EXE) *.dat > $@
$(LANGUAGE) $^ > $@

# Count words.
.PHONY : dats
dats : isles.dat abyss.dat last.dat

%.dat : books/%.txt $(COUNT_SRC)
$(COUNT_EXE) $< $*.dat
%.dat : $(COUNT_SRC) books/%.txt
$(LANGUAGE) $^ $@

.PHONY : clean
clean :
Expand Down
6 changes: 3 additions & 3 deletions code/06-variables/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ include config.mk

# Generate summary table.
results.txt : $(ZIPF_SRC) isles.dat abyss.dat last.dat
$(ZIPF_EXE) *.dat > $@
$(LANGUAGE) $^ > $@

# Count words.
.PHONY : dats
dats : isles.dat abyss.dat last.dat

%.dat : books/%.txt $(COUNT_SRC)
$(COUNT_EXE) $< $*.dat
%.dat : $(COUNT_SRC) books/%.txt
$(LANGUAGE) $^

.PHONY : clean
clean :
Expand Down
2 changes: 0 additions & 2 deletions code/06-variables/config.mk
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# Count words script.
LANGUAGE=python
COUNT_SRC=countwords.py
COUNT_EXE=$(LANGUAGE) $(COUNT_SRC)

# Test Zipf's rule
ZIPF_SRC=testzipf.py
ZIPF_EXE=$(LANGUAGE) $(ZIPF_SRC)
6 changes: 3 additions & 3 deletions code/07-functions/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ DAT_FILES=$(patsubst books/%.txt, %.dat, $(TXT_FILES))

# Generate summary table.
results.txt : $(ZIPF_SRC) $(DAT_FILES)
$(ZIPF_EXE) $(DAT_FILES) > $@
$(LANGUAGE) $^ > $@

# Count words.
.PHONY : dats
dats : $(DAT_FILES)

%.dat : books/%.txt $(COUNT_SRC)
$(COUNT_EXE) $< $@
%.dat : $(COUNT_SRC) books/%.txt
$(LANGUAGE) $^ $@

.PHONY : clean
clean :
Expand Down
2 changes: 0 additions & 2 deletions code/07-functions/config.mk
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# Count words script.
LANGUAGE=python
COUNT_SRC=countwords.py
COUNT_EXE=$(LANGUAGE) $(COUNT_SRC)

# Test Zipf's rule
ZIPF_SRC=testzipf.py
ZIPF_EXE=$(LANGUAGE) $(ZIPF_SRC)
10 changes: 5 additions & 5 deletions code/09-conclusion-challenge-1/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ all : results.txt $(PNG_FILES)

## results.txt : Generate Zipf summary table.
results.txt : $(ZIPF_SRC) $(DAT_FILES)
$(ZIPF_EXE) $(DAT_FILES) > $@
$(LANGUAGE) $^ > $@

## dats : Count words in text files.
.PHONY : dats
dats : $(DAT_FILES)

%.dat : books/%.txt $(COUNT_SRC)
$(COUNT_EXE) $< $@
%.dat : $(COUNT_SRC) books/%.txt
$(LANGUAGE) $^ $@

## pngs : Plot word counts.
.PHONY : pngs
pngs : $(PNG_FILES)

%.png : %.dat $(PLOT_SRC)
$(PLOT_EXE) $< $@
%.png : $(PLOT_SRC) %.dat
$(LANGUAGE) $^ $@

## clean : Remove auto-generated files.
.PHONY : clean
Expand Down
3 changes: 0 additions & 3 deletions code/09-conclusion-challenge-1/config.mk
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
# Count words script.
LANGUAGE=python
COUNT_SRC=countwords.py
COUNT_EXE=$(LANGUAGE) $(COUNT_SRC)

# Plot word counts script.
PLOT_SRC=plotcounts.py
PLOT_EXE=$(LANGUAGE) $(PLOT_SRC)

# Test Zipf's rule
ZIPF_SRC=testzipf.py
ZIPF_EXE=$(LANGUAGE) $(ZIPF_SRC)
Loading

0 comments on commit 6b3e05b

Please sign in to comment.