Python 3.11をCentOS 7にインストールする

Python 3.10以降でpipを使うにはopenssl 1.1が必要となりましたが、古いCentOS 7などではopenssl 1.1がデフォルトで入っていないのと、Python3.10や3.11を使うにはソースコードからインストールする必要があり（rpmは配布されていないと思う）、かつよくネット上に転がっている方法でインストールしようとするとssl対応してくれないままインストールが進んでしまうため、そうならないための方法を記します。

https://aifx.tech/centos7-python/ のサイトも参考になります。

## 環境

- CentOS Linux release 7.8.2003 (Core)
- gccはデフォルトのまま

## OpenSSL 1.1のインストール

管理者権限で入れられる場合はこちらを使います。

```bash
# CentOS 7でepel-releaseを使うようにする
yum install epel-release
# 
yum groupinstall "development tools"
yum install bzip2-devel gdbm-devel libffi-devel libuuid-devel ncurses-devel \
  openssl11 openssl11-devel readline-devel sqlite-devel xz-devel \
  zlib-devel tk-devel --enablerepo=epel
```

## Python 3.11のインストール

環境

- gcc 4.8.5 (CentOS 7デフォルト)

Python 3のビルドに必要なものがあれば先にインストールしておく

```bash
$ yum -y install gcc zlib-devel libffi-devel bzip2-devel \
ncurses-devel gdbm-devel xz-devel sqlite-devel tk-devel \
libuuid-devel readline-devel
```

CentOS 8, Rocky/Almalinux 8でnis moduleをONにするには以下のものを入れておく

```bash
dnf config-manager --set-enabled powertools
dnf -y install libnsl2-devel
```

先程のページには
> EPELからインストールした OpenSSL 1.1.1 は、標準の場所と異なる場所にインストールされるため、Python のビルドがうまくいきません。このため、シンボリックリンクを張ります。

とあります。これはその通りなのですが、ここではシンボリックリンクを貼らずに別の方法を採用します。

ウェブからソースコードをダウンロードして解凍

```bash
wget https://www.python.org/ftp/python/3.11.6/Python-3.11.6.tar.xz
tar xvf Python-3.11.6.tar.xz
cd Python-3.11.6
# tkinterをつけたい場合必要となる
# ちなみにCentOS 8やRocky/Almalinux 8では"-ltk8.6 -ltkstub8.6 -ltcl8.6"とする
export TCLTK_LIBS="-ltk8.5 -ltkstub8.5 -ltcl8.5"
# configure処理
INSTALL_PREFIX="/path/to/your/destination/python/3.11.6"
# CentOS 7で必要
CPPFLAGS="(pkg−config−−cflagsopenssl11)"LDFLAGS="(pkg-config --libs openssl11)" \

./configure --prefix=${INSTALL_PREFIX} --enable-ipv6 \
--enable-loadable-sqlite-extensions --with-system-ffi --with-lto \
--enable-optimizations

## checking whether compiling and linking against OpenSSL works... yes　となっていることを確認する
## ここで_sslがmissingでないことを確認する

# make
make -j8
# make installではなくmake altinstallを使う。
make altinstall
```

- ポイントは`pkg-config --cflags openssl`ではなく`pkg-config --cflags openssl11`の結果をCPPFLAGSに代入しているところです。CentOSのみyumで入れたopenssl11を見つけに行くためにopensslではなくopenssl11と書かなければならない。
- tkinterを使いたい場合は環境変数`TCLTK_LIBS`を設定する必要があります。
- このconfigure後に生成される`Modules/Setup`をいじる必要はない。
- Python 3.10や3.12でもできると思います。

インストール後、そのpython3.11をターミナルから起動してみて`import ssl`を試します。

```bash
$ python3.11 # /path/to/your/destination/python/3.11.6/bin/python3.11
Python 3.11.6 (main, Oct 18 2023, 01:32:53) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl
>>>
```

エラーが出なければ成功です。`python3.11 -m pip install <なんらかのライブラリ>`をしてみましょう。

## Environment Modulesの設定方法

先の方法ではシンボリックリンクを貼っていなかったため、環境変数`LD_LIBRARY_PATH`と`C_INCLUDE_PATH`を設定しないと一部のスクリプトを使ったときに`error while loading shared libraries: libssl.so.1.1.1k: cannot open shared object file: No such file or directory'`というエラーが出ます（うろ覚え）。これは先程インストールしたopenssl11にはデフォルトで環境変数LIBRARY_PATHが設定されていないためです。これの解決のためにそれらの環境変数を設定しておく必要があります。

めんどくさい場合は上記のシンボリックリンクを貼る方法で解決できるはずです。[Environment Modules](https://qiita.com/Ag_smith/items/f268ad27165a60aecd35)を使っている場合は以下のように書けばOKです。

```tcl
#%Module1.0######################################################################
# modulefile for python 3.11
#
proc ModulesHelp {} {
        global version modroot
        puts stderr "Python 3.11"
}

conflict python3.8 python3.9 python3.10

set modroot /path/to/your/destination/python/3.11.6

setenv          PYTHONSTARTUP   ""
setenv          PYTHONHOME      $modroot
prepend-path    PYTHONPATH      $modroot/lib:$modroot/lib/python3.11:$modroot/lib/python3.11/lib-dynload:$modroot/lib/python3.11/site-packages
prepend-path    PATH            $modroot/bin
prepend-path    LD_LIBRARY_PATH $modroot/lib:/usr/lib64/openssl11/lib
prepend-path    C_INCLUDE_PATH  /usr/include/openssl11
prepend-path    MANPATH         $modroot/share/man
```



## 参考にしたサイト

- [pyenv Common build problems](https://github.com/pyenv/pyenv/wiki/Common-build-problems#error-the-python-ssl-extension-was-not-compiled-missing-the-openssl-lib)