Automation Using Makefiles
Makefiles provide an easy way to group multiple terminal commands into a single command using make <command>
. This gives a brief overview with just enough information to write your first Makefile.
Why Make?
Apparently Make was originally developed to build executable programs, but I have seen an number of examples of people using Make to manage Python workflows. In this example, let's say we have a Python script in several repositories that we use to update files in each respective repository. From the command line, we can easily cd
into each and python build.py
to run the update script and then commit the changes. Using a Makefile, however, we can automate all of that into a single command: make publish
. Let's take a look at how to do this.
Writing a Makefile
To start, our entire Makefile is below (and available for download here):.
PY?=python3
help:
@echo ' '
@echo 'Makefile to update websites on MAG GitHub pages '
@echo ' '
@echo 'Usage: '
@echo ' make data MILE_file_copy and update_utilization '
@echo ' make html regenerate the websites '
@echo ' make publish regenerate websites, then publish to GitHub '
@echo ' '
data:
python ../MILE_Data/MILE_file_copy.py
cd ../Aircraft-Data/Utilization/Scripts; python update_utilization.py
html: data
cd ../CommercialData/scripts; python build.py
cd ../MarketView/scripts; python build.py
cd ../FleetView/scripts; python build.py
publish: html
@echo ' '
cd ../CommercialData; git pull origin master
cd ../CommercialData; git add -A
cd ../CommercialData; git commit -m "auto-regenerate from make"
cd ../CommercialData; git push origin master
@echo ' '
cd ../MarketView; git pull origin master
cd ../MarketView; git add -A
cd ../MarketView; git commit -m "auto-regenerate from make"
cd ../MarketView; git push origin master
@echo ' '
cd ../FleetView; git pull origin master
cd ../FleetView; git add -A
cd ../FleetView; git commit -m "auto-regenerate from make"
cd ../FleetView; git push origin master
Let's break this down to understand how to construct a Makefile. A Makefile has this basic structure (see the complete Make documentation, particularly section 2.1):
target … : prerequisites …
recipe
…
…
target
is name of the make command we are constructing. In our Makefile,data: ...
means we can enter the commandmake data
from the command line.prerequisites
are targets to call before calling ourrecipe
. In our Makefile, when we callmake publish
,make html
will be automatically be executed first because it is a prerequisite.recipe
is the group of commands our make command performs. Each line is a command, but commands can be given on the same line separated by;
. When we callmake data
in our Makefile, the first command run is executingpython ../MILE_Data/MILE_file_copy.py
, and so on until all commands are completed.
We can now define Make commands, group tasks we want to perform, and define prerequisites as necessary. As with anything there is much more to learn about Makefiles, but this is enough to get you started.
A Note on Directories
The cwd
of Python when run from a Makefile will by default be the directory that contains the Makefile. This may be an issue if you are running Python scripts that assume a cwd
where they are located. To address this, you can enter the appropriate directory and execute the script on the same line in the Makefile, for example: cd ../MarketView/scripts; python build.py
Executing Makefiles
Back to our example, the previous process required us to:
cd
into each repo- run
python build.py
update files - commit the changes
- repeat for each
Using this Makefile, the process now is simply:
cd
in to the directory containingMakefile
make publish
Conclusion
Whenever you find yourself doing the same rote task often it may be a good time to ask yourself if some simple automation is appropriate. For anything you perform at the command line, Makefiles can be a lightweight automation solution.