Python Projects with Makefiles
If you have a python script which requires a packages - e.g. graphviz
- you can automate the setup with a Makefile
.
The Makefile
will:
- Make three copies of an 8-line installer script.
- Use one of the installer script to install local packages.
- Install a symbolic link to python.
- Make a script called
activate
, which tells python to use
Context
Python coders don't like updating their projects, they just expect everyone to install the same version of everything that they have.
Historically, people dealt with this by installing only half a dozen copies of graphviz
; but now each python project uses a local environment, with a local copy of graphviz
, which means everyone gets to install a new copy of graphviz
every time they try out a project.
Downloading 40MB of software for each 40-line script you write is called 'virtual environments' because it sounds cool.
We can make it even cooler with make
, but not yet, because python - like the fae of old - will not fetch anything until you know its true name.
Setup
1command -v python
2realpath `!!`
You must reveal that true path, because python
is always a relative symbolic link, to an absolute symbolic link, which leads to a shortcut.
We can finally let make
know how to invoke python, and where it will install graphviz
.
If your python's version is '3.14', then python needs its packages placed in ${somewhere}/lib/python3.14/site-packages/
.
You must create a new, local, name for these packages, because - like the fey of old - python demands a private name in return for revealing its true name.
I'll call mine camelot
, because the path is long and arduous.
Set up the Makefiles like this:
1py_link != command -v python
2py != realpath $(py_link)
3version != basename $(py)
4
5virtenv = camelot
Now you can ask for a local pip
script, which can install the python packages:
1 [...]
2
3$(virtenv)/bin/pip:
4 $(py) -m venv $(virtenv)
Finally, list the packages you want in requirements.txt
, and make pip
install from it.
1ppkg=graphviz
2echo ${ppkg} > requirements.txt
1 [...]
2
3pkgs = $(virtenv)/lib/$(version)/site-packages/
4
5$(pkgs): $(virtenv)/bin/pip
6$(pkgs): requirements.txt
7 $(virtenv)/bin/pip install -r $<
The complete Makefile looks like this:
1all: .default
2
3py_link != command -v python
4py != realpath $(py_link)
5version != basename $(py)
6
7virtenv = camelot
8
9$(virtenv)/bin/pip:
10 $(py) -m venv $(virtenv)
11
12pkgs = $(virtenv)/lib/$(version)/site-packages/
13
14$(pkgs): $(virtenv)/bin/pip
15$(pkgs): requirements.txt
16 $(virtenv)/bin/pip install -r $<
17
18.PHONY: .default
19.default: $(pkgs)