Compiling and Installing Python 3.7 on Raspberry Pi Running Raspbian Stretch

Python3.7 final has been released near end of June 2018. Here are the instructions on how to build from source on a Raspberry Pi running Raspbian stretch.

Building Python 3.7 on Raspberry Pi

my steps

Choose a Raspberry Pi and ssh to it.

# Pi 3 B+
ssh rpihp1
screen -D -R
df -h .

A full build, test and install flow will consume about 400MB of disk space.

We are going to build from Python source code.

First, install some pre-reqs for the build:

sudo apt install -y libffi-dev libbz2-dev liblzma-dev \
    libsqlite3-dev libncurses5-dev libgdbm-dev zlib1g-dev \
    libreadline-dev libssl-dev tk-dev build-essential \
    libncursesw5-dev libc6-dev openssl git

Download, extract, configure, compile and install from the source code.

Note: It’s kinda fun to watch htop updated when the compilation is running…

C-a c
sudo apt-get install -y htop
sudo htop
C-a C-a
# ... make -j 5 -l 4 ...
C-a C-a

C-a c Means hold down Control key and type letter a, then release Control key add type letter c

C-a C-a Means hold down Control key and type letter a, then keep Control pressed and type another letter a

In a screen session:

C-a c :: will “c“reate another screen window.

C-a C-a :: will alternate switching between last two accessed windows in screen session.

C-a d :: will “d“etach from screen session, dropping you back to the shell you launched screen from.

Finally screen -D -R will reconnect to running screen session

OK. Enough with the GNU Screen short lesson. Let’s do it:

mkdir -p ~/projects/python37
cd ~/projects/python37
tar zxvf v3.7.0.tar.gz
cd cpython-3.7.0
./configure --prefix=$HOME/.local --enable-optimizations

# Throttle parallel make so that load average ('-l') stays under 4
make -j 4 -l 4  # quad core, so setting j=4+1 ('-j 5') also seemed fine
# ... This takes a while. Compiles, runs test and profiles ...
make install

Once installed, setup environment in your ~/.profile to add the new home of python3.7 to your path:

# set PATH so it includes user's private ~/.local/bin if it exists
if [ -d "$HOME/.local/bin" ] ; then

log out of all shells to get this new setting


Tkinter is included…

pi@rpihp1:~ $ python3.7
Python 3.7.0 (default, Jul  1 2018, 01:16:29)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from tkinter import *
>>> dir()
['ACTIVE', 'ALL', 'ANCHOR', 'ARC', 'BASELINE', 'BEVEL', 'BOTH', 'BOTTOM', 'BROWSE', 'BUTT', 'BaseWidget', 'BitmapImage', 'BooleanVar', 'Button', 'CASCADE', 'CENTER', 'CHAR', 'CHECKBUTTON', 'CHORD', 'COMMAND', 'CURRENT', 'CallWrapper', 'Canvas', 'Checkbutton', 'DISABLED', 'DOTBOX', 'DoubleVar', 'E', 'END', 'EW', 'EXCEPTION', 'EXTENDED', 'Entry', 'Event', 'EventType', 'FALSE', 'FIRST', 'FLAT', 'Frame', 'GROOVE', 'Grid', 'HIDDEN', 'HORIZONTAL', 'INSERT', 'INSIDE', 'Image', 'IntVar', 'LAST', 'LEFT', 'Label', 'LabelFrame', 'Listbox', 'MITER', 'MOVETO', 'MULTIPLE', 'Menu', 'Menubutton', 'Message', 'Misc', 'N', 'NE', 'NO', 'NONE', 'NORMAL', 'NS', 'NSEW', 'NUMERIC', 'NW', 'NoDefaultRoot', 'OFF', 'ON', 'OUTSIDE', 'OptionMenu', 'PAGES', 'PIESLICE', 'PROJECTING', 'Pack', 'PanedWindow', 'PhotoImage', 'Place', 'RADIOBUTTON', 'RAISED', 'READABLE', 'RIDGE', 'RIGHT', 'ROUND', 'Radiobutton', 'S', 'SCROLL', 'SE', 'SEL', 'SEL_FIRST', 'SEL_LAST', 'SEPARATOR', 'SINGLE', 'SOLID', 'SUNKEN', 'SW', 'Scale', 'Scrollbar', 'Spinbox', 'StringVar', 'TOP', 'TRUE', 'Tcl', 'TclError', 'TclVersion', 'Text', 'Tk', 'TkVersion', 'Toplevel', 'UNDERLINE', 'UNITS', 'VERTICAL', 'Variable', 'W', 'WORD', 'WRITABLE', 'Widget', 'Wm', 'X', 'XView', 'Y', 'YES', 'YView', '__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'constants', 'enum', 'getboolean', 'getdouble', 'getint', 'image_names', 'image_types', 'mainloop', 're', 'sys', 'wantobjects']

The New-in-3.7 @dataclass decorator is available

>>> from dataclasses import dataclass
>>> @dataclass
... class SimpleDataObject(object):
...   field_a: int
...   field_b: str
>>> example = SimpleDataObject(1, 'b')
>>> print(example)  # SimpleDataObject(field_a=1, field_b='b')
SimpleDataObject(field_a=1, field_b='b')
Published on July 1, 2018