March 5, 2023

CentOS 7にPython 3.10とPython3.11をソースからインストール

CentOS 7.9で標準リポジトリからyum installできるPython3パッケージは3.6.8

$ sudo yum install python3 -y
$ which python3
/usr/bin/python3
$ python3 -V
Python 3.6.8

SCLからインストールできるものでも3.8.13

$ sudo yum install centos-release-scl -y
$ sudo yum install rh-python38 -y
$ /opt/rh/rh-python38/root/usr/bin/python -V
Python 3.8.13

Python 3.8と3.9はステータスがsecurityに入っているので、3.10と3.11をソースからインストールしてみる。

※ Python 3.10と3.11のrpmを作るならこちら

用意したもの

CentOS 7.9を最小構成でセットアップしたVM

手順

パッケージ追加

ビルドに必要なパッケージインストール

$ sudo yum install gcc zlib-devel libffi-devel -y

このまま進むと以下のモジュールがnot foundだと言われるので、必要なものがあればパッケージ追加しておく。

The necessary bits to build these optional modules were not found:
_bz2                  _curses               _curses_panel
_dbm                  _gdbm                 _lzma
_sqlite3              _tkinter              _uuid
readline
To find the necessary bits, look in setup.py in detect_modules() for the module's name.
modulerpm
_bz2bzip2-devel
_curesncurses-devel
_cures_panel
_dbmgdbm-devel
_gdbm
_lzmaxz-devel
_sqlite3sqlite-devel
_tkintertk-devel ※1
_uuidlibuuid-devel
readlinereadline-devel

※1 Python 3.11.2では解消しなかった

自分はJupyterLabを使いたいのでsqlite-develを入れた。

$ sudo yum install sqlite-devel -y

OpenSSL 1.1.1追加

Python 3.10からOpenSSLは1.1.1が必須になったので、標準リポジトリのOpenSSL 1.0.2kだと以下が出て終わってしまう。

Could not build the ssl module!
Python requires a OpenSSL 1.1.1 or newer

EPELからインストールするか、rpmを自作してインストールする。
EPELのOpenSSLは1.1.1kなので、ここではrpmを自作してOpenSSL 1.1.1tを使うことにする。

$ sudo yum localinstall openssl-opt-1.1.1t-1.el7.x86_64.rpm -y

ダウンロード

$ cd ~
$ curl -OL https://www.python.org/ftp/python/3.10.10/Python-3.10.10.tgz
$ curl -OL https://www.python.org/ftp/python/3.11.2/Python-3.11.2.tgz

展開

$ find ./ -name "Python-3.*.tgz" -exec tar xzf {} \;

configure

公式ドキュメントのrecommended↓に従ってオプション追加

Configuring Python using --enable-optimizations --with-lto (PGO + LTO) is recommended for best performance.

$ cd ~/Python-3.10.10
$ ./configure \
--with-openssl=/opt/openssl/ \
--with-openssl-rpath=auto \
--prefix=/opt/python3 \
--enable-optimizations \
--with-lto

$ cd ~/Python-3.11.2
$ ./configure \
--with-openssl=/opt/openssl/ \
--with-openssl-rpath=auto \
--prefix=/opt/python3 \
--enable-optimizations \
--with-lto

build

  • -jオプションはCPUの数に応じて調整する
  • Python 3.11.2で--enable-optimizationsを付けるとビルドに失敗することがあるので、whileで成功するまでループさせた
  • --enable-optimizationsを諦めて普通にmakeするという手もある
$ cd ~/Python-3.10.10
$ make -j4

$ cd ~/Python-3.11.2
$ i=0; while true; do ((++i)) && make clean && make -j4 && echo "count=$i" && break; done

install

公式ドキュメントの警告に従ってaltinstall

警告
make install は python3 バイナリを上書きまたはリンクを破壊してしまうかもしれません。そのため、make install の代わりに _exec_prefix_/bin/python_version_ のみインストールする make altinstall が推奨されています。

$ cd ~/Python-3.10.10
$ sudo make altinstall

$ cd ~/Python-3.11.2
$ sudo make altinstall

alternatives

alternativesで3.10と3.11を切り替えられるように登録する

$ sudo alternatives --install /usr/local/bin/python3 python3 /opt/python3/bin/python3.10 1
$ sudo alternatives --install /usr/local/bin/python3 python3 /opt/python3/bin/python3.11 2
$ sudo alternatives --list | grep python3
python3 auto    /opt/python3/bin/python3.11

切り替えは以下のコマンドで番号を選択する

$ sudo alternatives --config python3

確認

$ which python3
/usr/local/bin/python3
$ ls -l /usr/local/bin/python3
lrwxrwxrwx. 1 root root 25  3月  4 17:42 /usr/local/bin/python3 -> /etc/alternatives/python3
$ python3 -V
Python 3.11.2 # alternativesで3.10.10を選んだ時は3.10.10になる

OpenSSLバージョン確認

$ /opt/python3/bin/python3.10 -c 'import ssl; print(ssl.OPENSSL_VERSION)'
OpenSSL 1.1.1t  7 Feb 2023
$ /opt/python3/bin/python3.11 -c 'import ssl; print(ssl.OPENSSL_VERSION)'
OpenSSL 1.1.1t  7 Feb 2023

試行錯誤の経緯

上の手順ができるまでの試行錯誤のメモを書いておく

パッケージ追加

zlib-devel(zlibパッケージではなくzlib-devel)を入れないと、make altinstallで以下が出てエラー終了した

Python 3.10.10

Traceback (most recent call last):
  File "<frozen zipimport>", line 570, in _get_decompress_func
ModuleNotFoundError: No module named 'zlib'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<frozen zipimport>", line 618, in _get_data
  File "<frozen zipimport>", line 573, in _get_decompress_func
zipimport.ZipImportError: can't decompress data; zlib not available

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<string>", line 6, in <module>
  File "/home/nissy/Python-3.10.10/Lib/runpy.py", line 220, in run_module
    mod_name, mod_spec, code = _get_module_details(mod_name)
  File "/home/nissy/Python-3.10.10/Lib/runpy.py", line 146, in _get_module_details
    return _get_module_details(pkg_main_name, error)
  File "/home/nissy/Python-3.10.10/Lib/runpy.py", line 110, in _get_module_details
    __import__(pkg_name)
  File "<frozen zipimport>", line 196, in get_code
  File "<frozen zipimport>", line 752, in _get_module_code
  File "<frozen zipimport>", line 620, in _get_data
zipimport.ZipImportError: can't decompress data; zlib not available
Traceback (most recent call last):
  File "/home/nissy/Python-3.10.10/Lib/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/home/nissy/Python-3.10.10/Lib/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/nissy/Python-3.10.10/Lib/ensurepip/__main__.py", line 5, in <module>
    sys.exit(ensurepip._main())
  File "/home/nissy/Python-3.10.10/Lib/ensurepip/__init__.py", line 287, in _main
    return _bootstrap(
  File "/home/nissy/Python-3.10.10/Lib/ensurepip/__init__.py", line 203, in _bootstrap
    return _run_pip([*args, *_PACKAGE_NAMES], additional_paths)
  File "/home/nissy/Python-3.10.10/Lib/ensurepip/__init__.py", line 104, in _run_pip
    return subprocess.run(cmd, check=True).returncode
  File "/home/nissy/Python-3.10.10/Lib/subprocess.py", line 526, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['/home/nissy/Python-3.10.10/python', '-W', 'ignore::DeprecationWarning', '-c', '\nimport runpy\nimport sys\nsys.path = [\'/tmp/tmprraifvlv/setuptools-65.5.0-py3-none-any.whl\', \'/tmp/tmprraifvlv/pip-22.3.1-py3-none-any.whl\'] + sys.path\nsys.argv[1:] = [\'install\', \'--no-cache-dir\', \'--no-index\', \'--find-links\', \'/tmp/tmprraifvlv\', \'--root\', \'/\', \'--upgrade\', \'setuptools\', \'pip\']\nrunpy.run_module("pip", run_name="__main__", alter_sys=True)\n']' returned non-zero exit status 1.
make: *** [altinstall] エラー 1

Python 3.11.2

Traceback (most recent call last):
  File "<frozen zipimport>", line 576, in _get_decompress_func
ModuleNotFoundError: No module named 'zlib'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<frozen zipimport>", line 624, in _get_data
  File "<frozen zipimport>", line 579, in _get_decompress_func
zipimport.ZipImportError: can't decompress data; zlib not available

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<string>", line 6, in <module>
  File "<frozen runpy>", line 222, in run_module
  File "<frozen runpy>", line 148, in _get_module_details
  File "<frozen runpy>", line 112, in _get_module_details
  File "<frozen zipimport>", line 195, in get_code
  File "<frozen zipimport>", line 758, in _get_module_code
  File "<frozen zipimport>", line 626, in _get_data
zipimport.ZipImportError: can't decompress data; zlib not available
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/nissy/Python-3.11.2/Lib/ensurepip/__main__.py", line 5, in <module>
    sys.exit(ensurepip._main())
             ^^^^^^^^^^^^^^^^^
  File "/home/nissy/Python-3.11.2/Lib/ensurepip/__init__.py", line 286, in _main
    return _bootstrap(
           ^^^^^^^^^^^
  File "/home/nissy/Python-3.11.2/Lib/ensurepip/__init__.py", line 202, in _bootstrap
    return _run_pip([*args, *_PACKAGE_NAMES], additional_paths)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/nissy/Python-3.11.2/Lib/ensurepip/__init__.py", line 103, in _run_pip
    return subprocess.run(cmd, check=True).returncode
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/nissy/Python-3.11.2/Lib/subprocess.py", line 571, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['/home/nissy/Python-3.11.2/python', '-W', 'ignore::DeprecationWarning', '-c', '\nimport runpy\nimport sys\nsys.path = [\'/tmp/tmpz7f_vc6_/setuptools-65.5.0-py3-none-any.whl\', \'/tmp/tmpz7f_vc6_/pip-22.3.1-py3-none-any.whl\'] + sys.path\nsys.argv[1:] = [\'install\', \'--no-cache-dir\', \'--no-index\', \'--find-links\', \'/tmp/tmpz7f_vc6_\', \'--root\', \'/\', \'--upgrade\', \'setuptools\', \'pip\']\nrunpy.run_module("pip", run_name="__main__", alter_sys=True)\n']' returned non-zero exit status 1.
make: *** [altinstall] エラー 1

libffi-develはビルド時の↓の解消に必要だった

Python 3.10.10

building '_ctypes' extension
gcc -pthread -fPIC -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -std=c99 -Wextra -Wno-unused-result -Wno-unused-parameter -Wno-missing-field-initializers -Werror=implicit-function-declaration -fvisibility=hidden -I./Include/internal -I./Include -I. -I/usr/local/include -I/home/nissy/Python-3.10.10/Include -I/home/nissy/Python-3.10.10 -c /home/nissy/Python-3.10.10/Modules/_ctypes/_ctypes.c -o build/temp.linux-x86_64-3.10/home/nissy/Python-3.10.10/Modules/_ctypes/_ctypes.o -DPy_BUILD_CORE_MODULE
/home/nissy/Python-3.10.10/Modules/_ctypes/_ctypes.c:107:17: 致命的エラー: ffi.h: そのようなファイルやディレクトリはありません
 #include <ffi.h>
                 ^
コンパイルを停止しました。

略

Failed to build these modules:
_ctypes

Python 3.11.2

building '_ctypes' extension
gcc -pthread -fPIC -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -std=c11 -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Werror=implicit-function-declaration -fvisibility=hidden -I./Include/internal -I./Include -I. -I/usr/local/include -I/home/nissy/Python-3.11.2/Include -I/home/nissy/Python-3.11.2 -c /home/nissy/Python-3.11.2/Modules/_ctypes/_ctypes.c -o build/temp.linux-x86_64-3.11/home/nissy/Python-3.11.2/Modules/_ctypes/_ctypes.o
/home/nissy/Python-3.11.2/Modules/_ctypes/_ctypes.c:118:17: 致命的エラー: ffi.h: そのようなファイルやディレクトリはあり ません
 #include <ffi.h>
                 ^
コンパイルを停止しました。

略

Failed to build these modules:
_ctypes

configure

Python-3.10.10では--enable-optimizationsを付けても問題なくビルドできるけど、Python-3.11.2ではビルド中に↓のエラーに遭遇する確率が結構高いので外した。

Fatal Python error: init_import_site: Failed to import the site module
Python runtime state: initialized
Traceback (most recent call last):
  File "/home/nissy/Python-3.11.2/Lib/site.py", line 73, in <module>
    import os
  File "/home/nissy/Python-3.11.2/Lib/os.py", line 29, in <module>
    from _collections_abc import _check_methods
SystemError: <built-in function compile> returned NULL without setting an exception


--enable-optimizations を付けても、何度か make clean && make -j4 を繰り返すとたまにビルドに成功することがあってよく分からない。

OS再起動してmake clean && make -j4 すると、Python 3.11.2で--enable-optimizationsを付けてもビルド成功率が割と高い気がする 。 ↓
--enable-optimizations付きでconfigure後、↓を実行して放置しておけば、いつかはビルドに成功する。
何度か試したけど、多くても4回くらいで成功した。

$ cd ~/Python-3.11.2; i=0; while true; do ((++i)) && make clean && make -j4 && echo "count=$i" && break; done

© 2020 nissy-lab.com