How to use virtualenv in makefile

I like using something that runs only when requirements.txt changes:

This assumes that source files are under project in your project's root directory and that tests are under project/test. (You should change project to match your actually project name.)

venv: venv/touchfile

venv/touchfile: requirements.txt
    test -d venv || virtualenv venv
    . venv/bin/activate; pip install -Ur requirements.txt
    touch venv/touchfile

test: venv
    . venv/bin/activate; nosetests project/test

clean:
    rm -rf venv
    find -iname "*.pyc" -delete
  • Run make to install packages in requirements.txt.
  • Run make test to run your tests (you can update this command if your tests are somewhere else).
  • run make clean to delete all artifacts.

Normally make runs every command in a recipe in a different subshell. However, setting .ONESHELL: will run all the commands in a recipe in the same subshell, allowing you to activate a virtualenv and then run commands inside it.

Note that .ONESHELL: applies to the whole Makefile, not just a single recipe. It may change behaviour of existing commands, details of possible errors in the full documentation. This will not let you activate a virtualenv for use outside the Makefile, since the commands are still run inside a subshell.

Reference documentation: https://www.gnu.org/software/make/manual/html_node/One-Shell.html

Example:

.ONESHELL:

.PHONY: install
install:
    source path/to/virtualenv/bin/activate
    pip install -r requirements.txt

In make you can run a shell as command. In this shell you can do everything you can do in a shell you started from comandline. Example:

install:
    ( \
       source path/to/virtualenv/bin/activate; \
       pip install -r requirements.txt; \
    )

Attention must be paid to the ;and the \.

Everything between the open and close brace will be done in a single instance of a shell.