23

How can I activate virtualenv in a Makefile?

I have tried:

venv:
    @virtualenv venv

active:
    @source venv/bin/activate

And I've also tried:

active:
    @. venv/bin/activate

and it doesn't activate virtualenv.

captncraig
  • 19,430
  • 11
  • 95
  • 139
Regis Santos
  • 2,609
  • 6
  • 34
  • 60
  • 4
    I think what's he is asking is that if a do `make` my shell will use this environment. You'll see the `(venv)` in from of your hostname. – Pobe Sep 08 '17 at 16:22

4 Answers4

12

Here's how to do it:

You can execute a shell command in a Makefile using ();

E.g.

echoTarget: 
    (echo "I'm an echo")

Just be sure to put a tab character before each line in the shell command. i.e. you will need a tab before (echo "I'm an echo")

Here's what will work for activating virtualenv:

activate:
    ( \
       source path/to/virtualenv/activate; \
       pip install -r requirements.txt; \
    )
wizurd
  • 3,131
  • 3
  • 29
  • 47
  • 9
    `/bin/sh: 1: source: not found` – Regis Santos Nov 21 '15 at 04:20
  • try changing "source" to this: bash -c "source path/to/virtualenv/bin/activate"; – wizurd Nov 21 '15 at 04:31
  • 1
    This might install the requirements for the given environment but the user still has to initiate the environment via a shell command. This does not fix the problem. `make` somehow needs to run as the current shell process (if i understand correctly). – Pobe Sep 08 '17 at 16:26
  • 4
    Try using `. venvpath/bin/activate` in place of `source` – eternaltyro Nov 22 '18 at 01:23
  • 2
    `make` might be using `sh` instead of `bash`. `source` is a bash-ism while `.` is the standard POSIX way, hence more portable. This is why it might make a difference. – Marcello Romani Mar 10 '19 at 23:21
  • 2
    Just found a SO answer which explains how to use `bash` `Makefile`s https://stackoverflow.com/questions/589276/how-can-i-use-bash-syntax-in-makefile-targets – Marcello Romani Mar 10 '19 at 23:27
  • @Pobe is right. Even that the requirements are properly installed into venv, it is not activated in the current shell that `make` was run – artu-hnrq Jan 27 '21 at 02:46
3

UPD Mar 14 '21

One more variant for pip install inside virtualenv:

# Makefile

all: install run

install: venv
    : # Activate venv and install smthing inside
    . venv/bin/activate && pip install -r requirements.txt
    : # Other commands here

venv:
    : # Create venv if it doesn't exist
    : # test -d venv || virtualenv -p python3 --no-site-packages venv
    test -d venv || python3 -m venv venv

run:
    : # Run your app here, e.g
    : # determine if we are in venv,
    : # see https://stackoverflow.com/q/1871549
    . venv/bin/activate && pip -V

    : # Or see @wizurd's answer to exec multiple commands
    . venv/bin/activate && (\
      python3 -c 'import sys; print(sys.prefix)'; \
      pip3 -V \
    )

clean:
    rm -rf venv
    find -iname "*.pyc" -delete

So you can run make with different 'standard' ways:

  • make - target to default all
  • make venv - to just create virtualenv
  • make install - to make venv and execute other commands
  • make run - to execute your app inside venv
  • make clean - to remove venv and python binaries
viktorkho
  • 365
  • 2
  • 11
1

Makefiles can't activate an environment directly. This is what worked for me:

activate:
    bash -c "venv/bin/activate"

If you get a permission denied error make venv/bin/activate executable:

chmod +x venv/bin/activate
  • `activate` should be sourced, not executed. How does `source venv/bin/activate` work for you, instead of your `bash -c...` line? – Gauthier Apr 16 '20 at 08:44
0

When it is time to execute recipes to update a target, they are executed by invoking a new sub-shell for each line of the recipe. --- GNU Make

Since each line of the recipe executes in a separate sub-shell, we should run the python code in the same line of the recipe.

Simple python script for showing the current source of python environment (filename: whichpy.py):

import sys
print(sys.prefix)

Running python virtual environment (Make recipes run on sh instead of bash, using . to activate the virtual environment is the correct syntax):

test:
    . pyth3.6/bin/activate && python3.6 whichpy.py
    . pyth3.6/bin/activate; python3.6 whichpy.py

Both the above 2 recipes are acceptable and we are free to use backslash/newline to separate one recipe into multiple lines.