1. 程式人生 > 實用技巧 >linux 下從原始碼安裝 Python——小白踩坑記

linux 下從原始碼安裝 Python——小白踩坑記

實驗室伺服器使用的系統為 Ubuntu 16.04,自帶的 python 版本為 Python 2.7.12 和 Python 3.5.2,命令列下使用$ python命令來啟動 python 時預設是 python2.7。而我想使用 Python 3.8,因此嘗試從原始碼安裝 Python,並更改預設的$ python命令指向。

注:如果想要安裝某個非系統自帶的 Python 版本,切忌衝動刪除系統自帶的 Python 2.7 和 Python 3.5,某些系統應用可能依賴於這些 Python 環境的呼叫,防止系統出錯!

1. 官網下載 python 原始碼

在官網這裡下載你想要的 linux 環境下的 python 原始碼,如我下載的是下圖第一個 Gzipped source tarball,其實二選一就好。

我下載完成後是一個叫 Python-3.8.3.tgz 的檔案,在下載目錄裡使用tar -xvf Python-3.8.3.tgz 命令解壓檔案包,目錄裡多出一個 Python-3.8.3 的資料夾,cd 命令進入該資料夾。

上述操作總結起來如下:

wget https://www.python.org/ftp/python/3.8.3/Python-3.8.3.tgz
tar -xvf Python-3.8.3.tgz
cd Python-3.8.3

2. 安裝依賴

Python 原始碼編譯、安裝過程中需要用到一些工具,你的系統裡可能有、可能沒有這些工具,保險起見,使下以下命令先把這些依賴安裝好吧。

這一步其實可以放在最開始執行。

  1. Ubuntu/Debian 系列:
    sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl
    
  2. Fedora/CentOS/RHEL 等可參考:
    sudo yum install zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel xz xz-devel libffi-devel
    

3. 編譯並安裝 python

注意根據第 1 節最後的 cd 命令,我們現在是在 python 的原始碼資料夾裡進行操作。

3.1 指定 python 的安裝目錄

作為 CS 小白,我還是要區別一下 python 的“原始碼目錄”和“安裝目錄”兩個概念的,畢竟是第一次在 linux 下從原始碼安裝軟體。

要知道,當前我們所在的目錄Python-3.8.3是由最開始下載的原始碼壓縮包解壓出來的,因此這個目錄裡是 python 這個軟體開源的原始碼,故稱之為原始碼目錄;而安裝目錄是說我們這個 python 軟體要安裝在系統的哪個地方,你啟動 python 的時候實際是從這裡啟動的。

類比下 windows 的話就是:原始碼目錄是你下載的那個安裝程式xxx.exe所在的目錄,還記得一些大型軟體(如 office 2016)安裝的時候通常是一個資料夾裡有一個setup.exe的程式嗎(當然,很多軟體你下載下來的安裝包其實就一個單獨的.exe 可執行檔案就沒了),windows 下就是直接點選這個xxx.exe進行安裝的,這就是所謂的原始碼目錄;那麼顯而易見,安裝目錄就是你在執行xxx.exe進行安裝的時候選擇的安裝地址,譬如說經常是C:\Program Files\等等。真正的軟體元件肯定是在安裝目錄裡,軟體需要從這裡啟動,而你平常習慣的在 windows 桌面/開始選單裡點選的圖示就是從安裝目錄裡延伸出的快捷方式。

迴歸主題,我選擇的 python 安裝目錄是/opt/python3.8,因此通過如下命令先建立這個資料夾:

mkdir /opt/python3.8

3.2 執行./configure

python 原始碼目錄裡有一個 configure 可執行檔案,這個命令的作用是生成一個 MakeFile 檔案,此 Makefile 檔案用來被之後的 make 命令所使用進行原始碼編譯(Linux 需要按照 Makefile 所指定的順序來編譯 (build) 程式元件)。

configure 通常有一些引數選項,最常見的是--prefix,用來指定安裝目錄。此外,要注意的是,python3.4 以後自帶了 pip,為了在之後能夠成功使用這個 pip 進行 python 庫的安裝,最好加上--with-ssl 引數。--with-ssl 這個引數不加的話 python 的安裝過程不受影響,只是當你想要用 pip 安裝 python 庫的時候會報錯,發現它無法連線到 pypi,跟 pip 連不上網沒啥區別。

總之,使用如下命令:

./configure --with-ssl --prefix=/opt/python3.8

3.3 make 編譯

make命令實際就是編譯原始碼,其根據 Makefile 檔案執行編譯指令並生成可執行檔案。

make

3.4 使用 make install 進行安裝

當 make 的原始碼編譯無誤,使用make install就是進行軟體的安裝,似乎也要根據 Makefile 檔案以及根據 make 生成的可執行檔案進行執行,原理尚不明確,現在確定的是其現實意義是把軟體安裝到configure命令指定的目錄,對我而言就是/opt/python3.8

make install因為是軟體安裝,因此通常需要 sudo 許可權。

sudo make install

4. 配置環境

至此 python 的安裝過程其實已經完成,在安裝目錄裡使用./bin/python3即可開啟安裝好的 python 可執行檔案並進入 python 命令行了:

但是每次要從安裝目錄裡啟動 python 很不方便,我們想要達到的是在 shell 中隨時隨地喚醒這個 python,這便需要進行相關的環境配置。

4.1 刪除原有的軟連結

開頭的時候提到,我的系統中預設的 python 命令開啟的是系統自帶的 python2.7,現在要更改這個命令讓它開啟的是新安裝的 python3.8,這需要我們先理解命令列(shell)中的命令是怎麼執行的:

  • 在 shell 中,執行的所有命令如 cd、ls、ps、python 等,分為“內建命令”和“外部命令”。內建命令是 shell 自帶的命令,好比程式語言不需要使用函式庫而自帶的那些函式,如print()函式;外部命令是為了豐富 shell 的功能而自己安裝的一些命令,好比你程式設計時使用的第三方庫,當然,有些外部命令是你安裝 linux 系統時就已經自帶的命令,好比程式語言的標準庫,雖然是“自帶的”但依然是“外部命令”。
  • python 毫無疑問是外部命令,那麼外部命令是怎麼執行呢?這就要提到平常經常見到的PATH概念了。當 shell 中輸入一個命令時,shell 首先檢驗它是不是內建命令,當內建命令中找不到這條命令時,shell 就搜尋你的PATH,這個東西就是一個儲存了你的外部命令所在路徑的集合,shell 在這些路徑中尋找你輸入的命令對應的那個可執行檔案,找得到就在 shell 中執行,找不到就報錯。
  • 於是,shell 中 python 命令的執行過程為:在PATH儲存的那麼路徑裡(包含很多路徑,其中一個是/usr/bin/)尋找一個名為python的可執行檔案,一般情況下,有這麼一個檔案:/usr/bin/python,找到它以後執行,就打開了 python。

現在我們使用ls -l /usr/bin/python檢視這個檔案的詳細資訊,發現它是一個執行 python2.7 的軟連結(相當於 windows 裡的快捷方式),把它刪掉,這樣在 shell 中直接輸入 python 就再也打不開任何 python 環境了,它成了一個無效命令。

總結一下,這步操作的命令過程為:

ls -l /usr/bin/python
sudo rm /usr/bin/python

4.2 建立新的軟連結

使用軟連結建立命令ln -s把新安裝的 python 連結到上步刪除的舊的軟連結所在目錄即可。即:

ln -s /opt/python3.8/bin/python3 /usr/bin/python

此時在任意工作目錄的 shell 中任意輸入 python,即可開啟新安裝的 python 3.8 了。

chuan@workstation:~$ python
Python 3.8.3 (default, Jun 21 2020, 16:34:59)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

4.3 配置 pip 命令

你的系統可能也自帶了 pip 或 pip2、pip3 等命令,由於自帶的 pip 關聯的肯定是原有的 python 環境,此時盲目使用 pip install 一些庫的話,這些庫其實被安裝到了系統自帶的 python 環境裡了,在你新安裝的 python3.8 里根本無法匯入這些庫,這就尷尬了。

這個 pip 其實和之前被刪除的 python 軟連結一樣,是一個在相同目錄下的 pip 軟連結,和更改 python 命令一樣,刪除掉原來的 pip 被建立一個新的 pip 軟連結即可。為了讓 pip 關聯的是新下載的 python3.8,新的 pip 應該來自 python3.8 自帶的那個 pip,其路徑為./opt/python3.8/bin/pip3。話不多說,程式碼如下:

sudo rm /usr/bin/pip
ln -s /opt/python3.8/bin/pip3 /usr/bin/pip

5. 前方告捷,嘿嘿

6. 附記

新安裝的 pip 在安裝第三方庫時還是有一個小小的報錯,提示什麼資料夾許可權不明確/不足以及:

Could not install packages due to an EnvironmentError: [Errno 13] Permission denied

根據百度,出現這個報錯之後,在 pip install 之後加個--user 可解決,如下:

pip install --user numpy

第一次加過--user 之後便不再有報錯,但不明所以的是這樣之後 pip 安裝的第三方庫的目錄被定在了~/.local/,原來似乎不存在這個資料夾。不過這並沒有造成後續什麼問題,暫且不管了,挖個坑後續再研究。

另外,不知道能不能選擇直接把一個已安裝的 pip 繫結到指定的 python 環境,而不用這麼折騰,未完待續吧......