詳解如何用源代碼安裝軟體,以及如何卸載它
簡介:這篇文章詳細介紹了在 Linux 中怎麼用源代碼安裝程序,以及怎麼去卸載用源代碼安裝的程序。
Linux 發行版的一個最大的優點就是它的包管理器和相關的軟體庫。通過它們提供的資源和工具,你才能夠以完全自動化的方式在你的計算機上下載和安裝軟體。
但是,儘管付出了很多的努力,包維護者仍然沒法照顧好每種情況,也不可能將所有的可用軟體都打包進去。因此,仍然存在需要你自已去編譯和安裝一個新軟體的情形。對於我來說,到目前為止,最主要的原因是,我編譯一些軟體是我需要去運行一個特定的版本。或者是我想去修改源代碼或使用一些想要的編譯選項。
如果你也屬於後一種情況,那你已經知道你應該怎麼做了。但是,對於絕大多數的 Linux 用戶來說,第一次從源代碼中編譯和安裝一個軟體看上去像是一個入門儀式:它讓很多人感到恐懼;但是,如果你能克服困難,你將可能進入一個全新的世界,並且,如果你做到了,那麼你將成為社區中享有特權的一部分人。
A. 在 Linux 中從源代碼開始安裝軟體
這正是我們要做的。因為這篇文章的需要,我要在我的系統上安裝 NodeJS 8.1.1。它是個完全真實的版本。這個版本在 Debian 倉庫中沒有:
sh$ apt-cache madison nodejs | grep amd64
nodejs | 6.11.1~dfsg-1 | http://deb.debian.org/debian experimental/main amd64 Packages
nodejs | 4.8.2~dfsg-1 | http://ftp.fr.debian.org/debian stretch/main amd64 Packages
nodejs | 4.8.2~dfsg-1~bpo8+1 | http://ftp.fr.debian.org/debian jessie-backports/main amd64 Packages
nodejs | 0.10.29~dfsg-2 | http://ftp.fr.debian.org/debian jessie/main amd64 Packages
nodejs | 0.10.29~dfsg-1~bpo70+1 | http://ftp.fr.debian.org/debian wheezy-backports/main amd64 Packages
第 1 步:從 GitHub 上獲取源代碼
像大多數開源項目一樣,NodeJS 的源代碼可以在 GitHub:https://github.com/nodejs/node 上找到。
所以,我們直接開始吧。
如果你不熟悉 GitHub,git 或者提到的其它 版本管理系統包含了這個軟體的源代碼,以及多年來對該軟體的所有修改的歷史。甚至可以回溯到該軟體的最早版本。對於開發者來說,保留它的歷史版本有很多好處。如今對我來說,其中一個好處是可以得到任何一個給定時間點的項目源代碼。更準確地說,我可以得到我所要的 8.1.1 發布時的源代碼。即便從那之後他們有了很多的修改。
在 GitHub 上,你可以使用 「branch」 (分支)按鈕導航到這個軟體的不同版本。「分支」 和 「標籤」 是 Git 中一些相關的概念。總的來說,開發者創建 「分支」 和 「標籤」 來在項目歷史中對重要事件保持跟蹤,比如當他們啟用一個新特性或者發布一個新版本時。在這裡先不詳細介紹了,你現在只需要知道我在找被標記為 「v8.1.1」 的版本。
在選擇了 「v8.1.1」 標籤後,頁面被刷新,最顯著的變化是標籤現在作為 URL 的一部分出現。另外,你可能會注意到文件改變日期也有所不同。你現在看到的源代碼樹是創建了 v8.1.1 標籤時的代碼。在某種意義上,你也可以認為像 git 這樣的版本管理工具是一個時光穿梭機,允許你在項目歷史中來回穿梭。
此時,我們可以下載 NodeJS 8.1.1 的源代碼。你不要忘記去點那個建議的大的藍色按鈕來下載一個項目的 ZIP 壓縮包。對於我來說,為講解的目的,我從命令行中下載並解壓這個 ZIP 壓縮包。但是,如果你更喜歡使用一個 GUI 工具,不用擔心,你可以取代下面的命令方式:
wget https://github.com/nodejs/node/archive/v8.1.1.zip
unzip v8.1.1.zip
cd node-8.1.1/
下載一個 ZIP 包就可以,但是如果你希望「像個專家一樣」,我建議你直接使用 git
工具去下載源代碼。它一點也不複雜 — 並且如果你是第一次使用該工具,它將是一個很好的開端,你以後將經常用到它:
# first ensure git is installed on your system
sh$ sudo apt-get install git
# Make a shallow clone the NodeJS repository at v8.1.1
sh$ git clone --depth 1
--branch v8.1.1
https://github.com/nodejs/node
sh$ cd node/
順便說一下,如果你有任何問題,這篇文章的第一部分只是做一個總體介紹而已。後面,為了幫你排除常見問題,我們將基於 Debian 和基於 RedHat 的發行版更詳細地解釋。
不管怎樣,在你使用 git
或者作為一個 ZIP 壓縮包下載了源代碼後,在當前目錄下就有了同樣的源代碼文件:
sh$ ls
android-configure BUILDING.md common.gypi doc Makefile src
AUTHORS CHANGELOG.md configure GOVERNANCE.md node.gyp test
benchmark CODE_OF_CONDUCT.md CONTRIBUTING.md lib node.gypi tools
BSDmakefile COLLABORATOR_GUIDE.md deps LICENSE README.md vcbuild.bat
第 2 步:理解程序的構建系統
構建系統就是我們通常所說的「編譯源代碼」,其實,編譯只是從源代碼中生成一個可使用的軟體的其中一個階段。構建系統是一套工具,用於自動處置不同的任務,以便可以僅通過幾個命令就能構建整個軟體。
雖然概念很簡單,實際上編譯做了很多事情。因為不同的項目或者編程語言也許有不同的要求,或者因為編程者的好惡,或者因為支持的平台、或者因為歷史的原因,等等等等 … 選擇或創建另外一個構建系統的原因幾乎數不清。這方面有許多種不同的解決方案。
NodeJS 使用一種 GNU 風格的構建系統。這在開源社區中這是一個很流行的選擇。由此開始,你將進入一段精彩的旅程。
寫出和調優一個構建系統是一個非常複雜的任務。但是,作為 「終端用戶」 來說,GNU 風格的構建系統使用兩個工具讓他們免於此難:configure
和 make
。
configure
文件是個項目專用的腳本,它將檢查目標系統的配置和可用功能,以確保該項目可以被構建,並最終吻合當前平台的特性。
一個典型的 configure
任務的重要部分是去構建 Makefile
。這個文件包含了有效構建項目所需的指令。
另一方面,make
工具,這是一個可用於任何類 Unix 系統的 POSIX 工具。它將讀取項目專用的 Makefile
然後執行所需的操作去構建和安裝你的程序。
但是,在 Linux 的世界中,你仍然有一些定製你自己專用的構建的理由。
./configure --help
configure -help
命令將展示你可用的所有配置選項。再強調一下,這是非常的項目專用。說實話,有時候,在你完全理解每個配置選項的作用之前,你需要深入到項目中去好好研究。
不過,這裡至少有一個標準的 GNU 自動化工具選項是你該知道的,它就是眾所周知的 --prefix
選項。它與文件系統的層次結構有關,它是你軟體要安裝的位置。
第 3 步:文件系統層次化標準(FHS)
大部分典型的 Linux 發行版的文件系統層次結構都遵從 文件系統層次化標準(FHS)。
這個標準說明了你的系統中各種目錄的用途,比如,/usr
、/tmp
、/var
等等。
當使用 GNU 自動化工具 和大多數其它的構建系統 時,它會把新軟體默認安裝在你的系統的 /usr/local
目錄中。這是依據 FHS 中 「/usr/local
層級是為系統管理員本地安裝軟體時使用的,它在系統軟體更新覆蓋時是安全的。它也可以用於存放在一組主機中共享,但又沒有放到 /usr 中的程序和數據」,因此,它是一個非常好的選擇。
/usr/local
層級以某種方式複製了根目錄,你可以在 /usr/local/bin
這裡找到可執行程序,在 /usr/local/lib
中找到庫,在 /usr/local/share
中找到架構無關的文件,等等。
使用 /usr/local
樹作為你定製安裝的軟體位置的唯一問題是,你的軟體的文件將在這裡混雜在一起。尤其是你安裝了多個軟體之後,將很難去準確地跟蹤 /usr/local/bin
和 /usr/local/lib
中的哪個文件到底屬於哪個軟體。它雖然不會導致系統的問題。畢竟,/usr/bin
也是一樣混亂的。但是,有一天你想去卸載一個手工安裝的軟體時它會將成為一個問題。
要解決這個問題,我通常喜歡安裝定製的軟體到 /opt
子目錄下。再次引用 FHS:
「
/opt
是為安裝附加的應用程序軟體包而保留的。包安裝在
/opt
下的軟體包必須將它的靜態文件放在單獨的/opt/<package>
或者/opt/<provider>
目錄中,此處<package>
是所說的那個軟體名的名字,而<provider>
處是提供者的 LANANA 註冊名字。」(LCTT 譯註:LANANA 是指 The Linux Assigned Names And Numbers Authority。 )
因此,我們將在 /opt
下創建一個子目錄,用於我們定製的 NodeJS 安裝。並且,如果有一天我想去卸載它,我只是很簡單地去刪除那個目錄:
sh$ sudo mkdir /opt/node-v8.1.1
sh$ sudo ln -sT node-v8.1.1 /opt/node
# What is the purpose of the symbolic link above?
# Read the article till the end--then try to answer that
# question in the comment section!
sh$ ./configure --prefix=/opt/node-v8.1.1
sh$ make -j9 && echo ok
# -j9 means run up to 9 parallel tasks to build the software.
# As a rule of thumb, use -j(N+1) where N is the number of cores
# of your system. That will maximize the CPU usage (one task per
# CPU thread/core + a provision of one extra task when a process
# is blocked by an I/O operation.
在你運行完成 make
命令之後,如果有任何的除了 「ok」 以外的信息,將意味著在構建過程中有錯誤。當我們使用一個 -j
選項去運行並行構建時,在構建系統的大量輸出過程中,檢索錯誤信息並不是件很容易的事。
在這種情況下,只能是重新開始 make
,並且不要使用 -j
選項。這樣錯誤將會出現在輸出信息的最後面:
sh$ make
最終,編譯結束後,你可以運行這個命令去安裝你的軟體:
sh$ sudo make install
然後測試它:
sh$ /opt/node/bin/node --version
v8.1.1
B. 如果在源代碼安裝的過程中出現錯誤怎麼辦?
我上面介紹的大多是你能在文檔完備的項目的「構建指令」頁面上看到。但是,本文的目標是讓你從源代碼開始去編譯你的第一個軟體,它可能要花一些時間去研究一些常見的問題。因此,我將再次重新開始一遍整個過程,但是,這次是在一個最新的、最小化安裝的 Debian 9.0 和 CentOS 7.0 系統上。因此,你可能看到我遇到的錯誤以及我怎麼去解決它。
從 Debian 9.0 中 「Stretch」 開始
itsfoss@debian:~$ git clone --depth 1
--branch v8.1.1
https://github.com/nodejs/node
-bash: git: command not found
這個問題非常容易去診斷和解決。去安裝這個 git
包即可:
itsfoss@debian:~$ sudo apt-get install git
itsfoss@debian:~$ git clone --depth 1
--branch v8.1.1
https://github.com/nodejs/node && echo ok
[...]
ok
itsfoss@debian:~/node$ sudo mkdir /opt/node-v8.1.1
itsfoss@debian:~/node$ sudo ln -sT node-v8.1.1 /opt/node
現在沒有問題了。
itsfoss@debian:~/node$ ./configure --prefix=/opt/node-v8.1.1/
WARNING: failed to autodetect C++ compiler version (CXX=g++)
WARNING: failed to autodetect C compiler version (CC=gcc)
Node.js configure error: No acceptable C compiler found!
Please make sure you have a C compiler installed on your system and/or
consider adjusting the CC environment variable if you installed
it in a non-standard prefix.
很顯然,編譯一個項目,你需要一個編譯器。NodeJS 是使用 C++ 語言 寫的,我們需要一個 C++ 編譯器。在這裡我將安裝 g++
,它就是為這個目的寫的 GNU C++ 編譯器:
itsfoss@debian:~/node$ sudo apt-get install g++
itsfoss@debian:~/node$ ./configure --prefix=/opt/node-v8.1.1/ && echo ok
[...]
ok
itsfoss@debian:~/node$ make -j9 && echo ok
-bash: make: command not found
還差一個其它工具。同樣的癥狀。同樣的解決方案:
itsfoss@debian:~/node$ sudo apt-get install make
itsfoss@debian:~/node$ make -j9 && echo ok
[...]
ok
itsfoss@debian:~/node$ sudo make install
[...]
itsfoss@debian:~/node$ /opt/node/bin/node --version
v8.1.1
成功!
請注意:我將一次又一次地安裝各種工具去展示怎麼去診斷編譯問題,以及展示怎麼去解決這些問題。但是,如果你搜索關於這個主題的更多文檔,或者讀其它的教程,你將發現,很多發行版有一個 「meta-packages」,它包羅了安裝一些或者全部的用於編譯軟體的常用工具。在基於 Debian 的系統上,你或許遇到過 build-essentials 包,它就是這種用作。在基於 Red Hat 的發行版中,它將是 「Development Tools」 組。
在 CentOS 7.0 上
[itsfoss@centos ~]$ git clone --depth 1
--branch v8.1.1
https://github.com/nodejs/node
-bash: git: command not found
命令沒有找到?可以用 yum
包管理器去安裝它:
[itsfoss@centos ~]$ sudo yum install git
[itsfoss@centos ~]$ git clone --depth 1
--branch v8.1.1
https://github.com/nodejs/node && echo ok
[...]
ok
[itsfoss@centos ~]$ sudo mkdir /opt/node-v8.1.1
[itsfoss@centos ~]$ sudo ln -sT node-v8.1.1 /opt/node
[itsfoss@centos ~]$ cd node
[itsfoss@centos node]$ ./configure --prefix=/opt/node-v8.1.1/
WARNING: failed to autodetect C++ compiler version (CXX=g++)
WARNING: failed to autodetect C compiler version (CC=gcc)
Node.js configure error: No acceptable C compiler found!
Please make sure you have a C compiler installed on your system and/or
consider adjusting the CC environment variable if you installed
it in a non-standard prefix.
你知道的:NodeJS 是使用 C++ 語言寫的,但是,我的系統缺少合適的編譯器。Yum 可以幫到你。因為,我不是一個合格的 CentOS 用戶,我實際上是在互聯網上搜索到包含 g++ 編譯器的包的確切名字的。這個頁面指導了我:https://superuser.com/questions/590808/yum-install-gcc-g-doesnt-work-anymore-in-centos-6-4 。
[itsfoss@centos node]$ sudo yum install gcc-c++
[itsfoss@centos node]$ ./configure --prefix=/opt/node-v8.1.1/ && echo ok
[...]
ok
[itsfoss@centos node]$ make -j9 && echo ok
[...]
ok
[itsfoss@centos node]$ sudo make install && echo ok
[...]
ok
[itsfoss@centos node]$ /opt/node/bin/node --version
v8.1.1
再次成功!
C. 從源代碼中對要安裝的軟體做一些改變
從源代碼中安裝一個軟體,可能是因為你的分發倉庫中沒有一個可用的特定版本。或者因為你想去 修改 那個程序。也可能是修復一個 bug 或者增加一個特性。畢竟,開源軟體這些都可以做到。因此,我將抓住這個機會,讓你親自體驗怎麼去編譯你自己的軟體。
在這裡,我將在 NodeJS 源代碼上做一個微小改變。然後,我們將看到我們的改變將被納入到軟體的編譯版本中:
用你喜歡的 文本編輯器(如,vim、nano、gedit、 … )打開文件 node/src/node.cc
。然後,嘗試找到如下的代碼片段:
if (debug_options.ParseOption(argv[0], arg)) {
// Done, consumed by DebugOptions::ParseOption().
} else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) {
printf("%sn", NODE_VERSION);
exit(0);
} else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
PrintHelp();
exit(0);
}
它在 文件的 3830 行 附近。然後,修改包含 printf
的行,將它替換成如下內容:
printf("%s (compiled by myself)n", NODE_VERSION);
然後,返回到你的終端。在繼續之前,為了對強大的 Git 支持有更多的了解,你可以去檢查一下,你修改是文件是否正確:
diff --git a/src/node.cc b/src/node.cc
index bbce1022..a5618b57 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -3828,7 +3828,7 @@ static void ParseArgs(int* argc,
if (debug_options.ParseOption(argv[0], arg)) {
// Done, consumed by DebugOptions::ParseOption().
} else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) {
- printf("%sn", NODE_VERSION);
+ printf("%s (compiled by myself)n", NODE_VERSION);
exit(0);
} else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
PrintHelp();
在你前面改變的那行之前,你將看到一個 「-」 (減號標誌)。而在改變之後的行前面有一個 「+」 (加號標誌)。
現在可以去重新編譯並重新安裝你的軟體了:
make -j9 && sudo make install && echo ok
[...]
ok
這個時候,可能失敗的唯一原因就是你改變代碼時的輸入錯誤。如果就是這種情況,在文本編輯器中重新打開 node/src/node.cc
文件並修復錯誤。
一旦你完成了新修改版本的 NodeJS 的編譯和安裝,就可以去檢查你的修改是否包含到軟體中:
itsfoss@debian:~/node$ /opt/node/bin/node --version
v8.1.1 (compiled by myself)
恭喜你!你對開源程序做出了你的第一個改變!
D. 讓 shell 找到我們定製構建的軟體
到目前為止,你可能注意到,我通常啟動我新編譯的 NodeJS 軟體是通過指定到該二進位文件的絕對路徑。
/opt/node/bin/node
這是可以正常工作的。但是,這樣太麻煩。實際上有兩種辦法可以去解決這個問題。但是,去理解它們,你必須首先明白,你的 shell 定位可執行文件是通過在環境變數 PATH
中指定的目錄裡面查找的。
itsfoss@debian:~/node$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
在這個 Debian 系統上,如果你不指定一個精確的目錄做為命令名字的一部分,shell 將首先在 /usr/local/bin
中查找可執行程序;如果沒有找到,然後進入 /usr/bin
中查找;如果沒有找到,然後進入 /bin
查找;如果沒有找到,然後進入 /usr/local/games
查找;如果沒有找到,然後進入 /usr/games
查找;如果沒有找到,那麼,shell 將報告一個錯誤,「command not found」。
由此,我們可以知道有兩種方法去確保命令可以被 shell 訪問到:將它(該二進位程序)增加到已經配置好的 PATH
目錄中,或者將包含可執行程序的目錄添加到 PATH
中。
從 /usr/local/bin 中添加一個鏈接
只是從 /opt/node/bin
中 拷貝 NodeJS 二進位可執行文件到 /usr/local/bin
是一個錯誤的做法。因為,如果這麼做,該可執行程序將無法定位到在 /opt/node/
中的需要的其它組件。(軟體以它自己的位置去定位它所需要的資源文件是常見的做法)
因此,傳統的做法是去使用一個符號鏈接:
itsfoss@debian:~/node$ sudo ln -sT /opt/node/bin/node /usr/local/bin/node
itsfoss@debian:~/node$ which -a node || echo not found
/usr/local/bin/node
itsfoss@debian:~/node$ node --version
v8.1.1 (compiled by myself)
這一個簡單而有效的解決辦法,尤其是,如果一個軟體包是由好幾個眾所周知的可執行程序組成的,因為,你將為每個用戶調用的命令創建一個符號鏈接。例如,如果你熟悉 NodeJS,你知道應用的 npm
組件,也應該從 /usr/local/bin
做個符號鏈接。我把這個留給你做練習。
修改 PATH
首先,如果你嘗試過前面的解決方案,請先移除前面創建的節點符號鏈接,去從一個乾淨的狀態開始:
itsfoss@debian:~/node$ sudo rm /usr/local/bin/node
itsfoss@debian:~/node$ which -a node || echo not found
not found
現在,這裡有一個改變你的 PATH
的魔法命令:
itsfoss@debian:~/node$ export PATH="/opt/node/bin:${PATH}"
itsfoss@debian:~/node$ echo $PATH
/opt/node/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
簡單說就是,我用環境變數 PATH
之前的內容前綴了一個 /opt/node/bin
替換了其原先的內容。因此,你可以想像一下,shell 將先進入到 /opt/node/bin
目錄中查找可執行程序。我們也可以使用 which
命令去確認一下:
itsfoss@debian:~/node$ which -a node || echo not found
/opt/node/bin/node
itsfoss@debian:~/node$ node --version
v8.1.1 (compiled by myself)
鑒於 「符號鏈接」 解決方案是永久的,只要創建到 /usr/local/bin
的符號鏈接就行了,而對 PATH
的改變僅影響到當前的 shell。你可以自己做一些研究,如何做到對 PATH
的永久改變。給你一個提示,可以將它寫到你的 「profile」 中。如果你找到這個解決方案,不要猶豫,通過下面的評論區共享給其它的讀者!
E. 怎麼去卸載剛才從源代碼中安裝的軟體
因為我們定製編譯的 NodeJS 軟體全部在 /opt/node-v8.1.1
目錄中,卸載它不需要做太多的工作,僅使用 rm
命令去刪除那個目錄即可:
sudo rm -rf /opt/node-v8.1.1
注意:sudo
和 rm -rf
是 「非常危險的雞尾酒」!一定要在按下回車鍵之前多檢查幾次你的命令。你不會得到任何的確認信息,並且如果你刪除了錯誤的目錄它是不可恢復的 …
然後,如果你修改了你的 PATH
,你可以去恢復這些改變。它一點也不複雜。
如果你從 /usr/local/bin
創建了一個符號鏈接,你應該去刪除它們:
itsfoss@debian:~/node$ sudo find /usr/local/bin
-type l
-ilname "/opt/node/*"
-print -delete
/usr/local/bin/node
等等? 依賴地獄在哪裡?
作為最終的討論,如果你讀過有關的編譯定製軟體的文檔,你可能聽到關於 依賴地獄 的說法。那是在你能夠成功編譯一個軟體之前,對那種煩人情況的一個別名,你必須首先編譯一個前提條件所需要的庫,它又可能要求其它的庫,而這些庫有可能與你的系統上已經安裝的其它軟體不兼容。
發行版的軟體包維護者的部分工作,就是實際去地解決那些依賴地獄,確保你的系統上的各種軟體都使用了兼容的庫,並且按正確的順序去安裝。
在這篇文章中,我特意選擇了 NodeJS 去安裝,是因為它幾乎沒有依賴。我說 「幾乎」 是因為,實際上,它 有 依賴。但是,這些源代碼的依賴已經預置到項目的源倉庫中(在 node/deps
子目錄下),因此,在你動手編譯之前,你不用手動去下載和安裝它們。
如果你有興趣了解更多關於那個問題的知識和學習怎麼去處理它。請在下面的評論區告訴我,它將是更高級別的文章的好主題!
作者簡介:
充滿激情的工程師,職業是教師,我的目標是:熱心分享我所教的內容,並讓我的學生自己培養它們的技能。你也可以在我的網站上聯繫到我。
via: https://itsfoss.com/install-software-from-source-code/
作者:Sylvain Leroux 譯者:qhwdw 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive