Create a Docker Container:

For convenience, we'll build the RPM inside a CentOS 7 docker container.

1. Create the CentOS 7 container:

docker run -dt --name centos7 centos:7 bash

2. Enter the container:

docker exec -it centos7 bash

Install and configure CCache:

Since compiling can take a while and it's highly likely we make a mistake, let's install CCache.

If something goes wrong and we have to recompile, this will save us a lot of time.

To install ccache, we first need to install the EPEL repository:

1. Install the EPEL repository:

yum -y install epel-release

2. Install CCache:

yum -y install ccache

3. Configure ccache:

ln -s /usr/bin/ccache /usr/local/bin/gcc
ln -s /usr/bin/ccache /usr/local/bin/g++
ln -s /usr/bin/ccache /usr/local/bin/cc
ln -s /usr/bin/ccache /usr/local/bin/c++

Compile Python:

Now let's download the source code for the version of Python we want to build.

At the time of writing this the most recent version is 3.9.5.

1. Download and extract the source code tarball:

cd /tmp/
curl -LO https://www.python.org/ftp/python/3.9.5/Python-3.9.5.tar.xz
tar -xf Python-3.9.5.tar.xz

2. Install compile dependencies:

yum -y install openssl-devel ncurses-devel libffi-devel xz-devel libuuid-devel tk-devel gdbm-devel sqlite-devel bzip2-devel readline-devel gcc make

3. Configure and build Python:

cd Python-3.9.5
./configure --prefix=$HOME/python3.9 --enable-shared
make -j$(nproc)
make install

4. Cleanup any unneeded files:

rm -rf /tmp/Python-*

5. Use sed to replace the location of the interpreter for the Python scripts:

cd ~/python3.9/bin

6. CentOS expects to find the libpython3.9.so.1.0 under the /lib64 directory. Let's create a symlink to handle that:

cd ~/python3.9
mkdir lib64 && cd lib64
ln -s ../lib/libpython3.9.so.1.0 .

Use FPM to create the RPM:

We are now ready to package Python into an RPM. To do this we are going to use FPM.

To use FPM we need a newer version of Ruby.

To get a newer version of Ruby we use rbenv:

1. Install rbenv:

yum -y install git
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
cd ~/.rbenv && src/configure && make -C src
source ~/.bashrc

2. Install Ruby 3.0.1 using rbenv:

rbenv install 3.0.1

3. Make Ruby 3.0.1 the default Ruby:

rbenv global 3.0.1

4. Install the FPM gem:

gem install fpm --no-document

5. Build the RPM:

cd /root/python3.9/
yum -y install rpm-build
fpm --verbose -v 3.9.5 -n python3 -s dir -t rpm .=/usr/

6. Attempt to install it:

yum -y install python3*.rpm

7. Run some quick tests to make sure it all worked:

python3 --version
Python 3.9.5
pip3 -V
pip 21.1.1 from /usr/lib/python3.9/site-packages/pip (python 3.9)