Installing Python from Source (Linux)
A guide to installing any version of Python on Linux including 3.7, 3.8, 3.9, and 3.10.
Package repositories are great, but when it comes to Python they usually only distribute one particular version. If you're a serious Python developer, then at some point you'll need a version that's not available through the package manager and you'll have little choice but to install one from source. But have no fear! It's not as daunting as it may seem, even if youre doing it for the first time.
1. Download Source Code
Head over to https://www.python.org/downloads/ and grab yourself the tarball and signature for whichever version of Python you'll be installing. I haven't installed 3.10 yet so that's the version I'll install in this guide, but the steps are identical for all supported versions.
Verify that the checksum is correct
$ md5sum Python-3.10.0.tar.xz
3e7035d272680f80e3ce4e8eb492d580 Python-3.10.0.tar.xz
and that the signature matches.
$ gpg --verify Python-3.10.0.tar.xz.asc
gpg: assuming signed data in 'Python-3.10.0.tar.xz'
gpg: Signature made Mon 04 Oct 2021 09:56:39 AM AKDT
gpg: using RSA key CFDCA245B1043CF2A5F97865FFE87404168BD847
gpg: Good signature from "Pablo Galindo Salgado <pablogsal@gmail.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: A035 C8C1 9219 BA82 1ECE A86B 64E6 28F8 D684 696D
Subkey fingerprint: CFDC A245 B104 3CF2 A5F9 7865 FFE8 7404 168B D847
See the GPG getting started guide for details on how to import public keys into your chain of trust. Links to the signers keys are found at the bottom of the Python downloads page.
Now extract the tarball and change directory to the extracted folder.
$ tar -xf Python-3.10.0.tar.xz
$ cd Python-3.10.0
2. Install Development Packages
Python is able to build without installing any additional dependencies, however, interpreter history and some builtin modules won't work unless you install some extra packages. Don't worry though, you can uninstall them again after the build has completed.
Ubuntu:
$ sudo apt install build-essential pkg-config \
libbz2-dev libffi-dev libgdbm-dev liblzma-dev \
libncurses5-dev libreadline6-dev libsqlite3-dev \
libssl-dev tk-dev uuid-dev zlib1g-dev
CentOS / RHEL:
$ sudo yum install yum-utils
$ sudo yum-builddep python3
Fedora:
$ sudo dnf install dnf-plugins-core
$ sudo dnf builddep python3
Arch:
$ sudo pacman -Sy gcc make pkgconf bzip2 libffi \
gdbm lib32-xz ncurses readline sqlite \
openssl tk lib32-util-linux zlib
3. Compile and Install
Python is compiled in typical C fashion by running a configure
script followed by make
. When running configure
, you have the opportunity to customize some compile options. Here is what I would recommend:
$ ./configure --enable-optimizations \
--enable-shared \
--enable-loadable-sqlite-extensions \
--prefix /usr/local \
LDFLAGS=-Wl,-rpath=/usr/local/lib
--enable-optimizations
will enable Profile-Guided Optimizations (PGO) which will may cause the build to take significantly longer, but will result in a better optimized binary.--enable-shared
will build a shared Python library. Python builds distributed through a package manager typically have this enabled as you will need it for any software that expects to be able to link to Python.--enable-loadable-sqlite-extensions
will compile the_sqlite
module to support loadable extensions. If you don't enable this, you may encounter import errors when trying to import dependencies that use the builtinsqlite
module.--prefix
determines where Python will be installed during the final step.LDFLAGS
is used to add a non-standard search path for the shared library. This is only necessary if you set--prefix
to a non-standard directory (such as/opt
).
Now compile the code with Make. You can make use of multiple cores by passing the -j
flag to get Make to run tasks in parallel.
$ make -j8
Depending on the version of Python you're installing, this could take anywhere between 5 and 45 minutes (Python 3.7 runs an especially large test suite which takes a long time).
Test that the build worked by running the python
executable. Since we built it using a shared library and we have not properly installed it to the system yet, we need to tell the dynamic linker to search the current directory for the libpython*.so
file by setting the LD_LIBRARY_PATH
environment variable.
$ LD_LIBRARY_PATH=. ./python
Python 3.10.0 (default, Nov 15 2021, 20:19:38) [GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print("Hello, World!")
Hello, World!
Finally, install Python as an alternate installation
$ sudo make altinstall
and verify that it worked
$ python3.10
Python 3.10.0 (default, Nov 15 2021, 20:19:38) [GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print("Hello, World!")
Hello, World!
That's it! If you have any questions or comments, send them to contact@askaholic.io!
Troubleshooting
If you get to the final step and you see this error when trying to run python
$ python3.10
python3.10: error while loading shared libraries: libpython3.10.so.1.0: cannot open shared object file: No such file or directory
then you probably need to add the LDFLAGS
argument to your configure command. Luckily you don't need to recompile everything, just the final produced binary.
$ ./configure ... LDFLAGS=-Wl,-rpath=/usr/local/lib
$ rm ./python
$ make
$ sudo make altinstall