如何安裝與升級軟體
2种方法
l 直接以原始碼透過編譯來安裝與升級。即直接以 Tarball 在自己的機器上面進行偵測、編譯、 安裝。
l 直接以編譯好的 binary program 來安裝與升級。即使用RPM/YUM来安装(Debian 使用dpkg/ APT)。
本篇文章只讲解如何使用Tarball来安装软件。概括而言,使用Tarball来安装的步骤是:
1. 下载原始檔:將 tarball 檔案在 /usr/local/src 目錄下解壓縮;
2. 查閱 INSTALL 與 README 等相關檔案內容
3. 执行命令“./configure”来自動偵測程式 (configure 或 config) 偵測作業環境,同时建立 Makefile 這個檔案
4. 执行命令“make”来編譯原始檔,并生成可执行文件
5. 执行命令“make install”来把可执行文件安装到你的系统里
要知详细讲解,请继续往下阅读
如何判断一个文件是不是可执行文件
要看它是不是二進位檔案(binary program)。可以通过"file" command来判断
example:
> file /bin/bash
> file /etc/init.d/syslog
如果是 binary 而且是可以執行的時候,他就會顯示執行檔類別 (ELF 32-bit LSB executable), 同時會說明是否使用動態函式庫 (shared libs),而如果是一般的 script ,那他就會顯示出 text executables 之類的字樣!
如何自己生成一个可执行文件
用vim/vi编写的c程序需要通过linux上c编译器gcc来编译成可执行文件.
在編譯的過程當中還會產生所謂的目標檔 (Object file),這些檔案是以 *.o 的副檔名樣式存在的!至於 C 語言的原始碼檔案通常以 *.c 作為副檔名。
什麼是 make 與 configure
使用類似 gcc 的編譯器來進行編譯的過程並不簡單,因為一套軟體並不會僅有一支程式,而是有一堆程式碼檔案。所以除了每個主程式與副程式均需要寫上一筆編譯過程的指令外,還需要寫上最終的連結程序。 程式碼小的時候還好,如果是類似 WWW 伺服器軟體 (例如 Apache) ,或者是類似核心的原始碼,動則數百 MBytes 的資料量,編譯指令會寫到瘋掉~這個時候,我們就可以使用 make 這個指令的相關功能來進行編譯過程的指令簡化了!
當執行 make 時,make 會在當時的目錄下搜尋 Makefile (or makefile) 這個文字檔,而 Makefile 裡面則記錄了原始碼如何編譯的詳細資訊! make 會自動的判別原始碼是否經過變動了,而自動更新執行檔
咦!make 是一支程式,會去找 Makefile ,那 Makefile 怎麼寫? 通常軟體開發商都會寫一支偵測程式來偵測使用者的作業環境,以及該作業環境是否有軟體開發商所需要的其他功能,該偵測程式偵測完畢後,就會主動的建立這個 Makefile 的規則檔案啦!通常這支偵測程式的檔名為 configure 或者是 config 。
那為什麼要偵測作業環境呢?不同linux版本的核心所使用的系統呼叫可能不相同,而且每個軟體所需要的相依的函式庫也不相同, 同時,軟體開發商不會僅針對 Linux 開發,而是會針對整個 Unix-Like 做開發啊! 所以他也必須要偵測該作業系統平台有沒有提供合適的編譯器才行!所以當然要偵測環境啊!一般來說,偵測程式會偵測的資料大約有底下這些:
是否有適合的編譯器可以編譯本軟體的程式碼;是否已經存在本軟體所需要的函式庫,或其他需要的相依軟體;作業系統平台是否適合本軟體,包括 Linux 的核心版本;核心的表頭定義檔 (header include) 是否存在 (驅動程式必須要的偵測)。至於 make 與 configure 運作流程, 妳要進行的任務其實只有兩個,一個是執行 configure 來建立 Makefile , 成功之後再以 make 來呼叫所需要的資料來編譯即可!
由於不同的 Linux distribution 的函式庫檔案所放置的路徑,或者是函式庫的檔名訂定, 或者是預設安裝的編譯器,以及核心的版本都不相同,因此理論上,妳無法在 CentOS 5.x 上面編譯出 binary program 後,還將他拿到 SuSE 上面執行,這個動作通常是不可能成功的! 因為呼叫的目標函式庫位置可能不同 , 核心版本更不可能相同!所以同一套軟體要在不同的平台上面執行時, 必須要重複編譯!
Tarball
所謂的 Tarball 檔案,其實就是將軟體的所有原始碼檔案先以 tar 打包,然後再以壓縮技術來壓縮. Tarball檔案解壓縮後通常就會有:
原始程式碼檔案;偵測程式檔案 (可能是 configure 或 config 等檔名);本軟體的簡易說明與安裝說明 (INSTALL 或 README)。
使用傳統程式語言進行編譯的簡單範例
下面通过一个hello world程序来了解整个编译的过程,从而了解Tarball安装的原理。
(先确认你的linux已经安装了gcc,如果没有,则通过“yum groupinstall "Development Tools"”来安装)
* 編輯程式碼
[root@www ~]# vim hello.c <==用 C 語言寫的程式副檔名建議用 .c
#include <stdio.h>
int main(void){
printf("Hello World/n");
}
* 編譯與測試執行
[root@www ~]# gcc hello.c [root@www ~]# ll hello.c a.out -rwxr-xr-x 1 root root 4725 Jun 5 02:41 a.out <==此時會產生這個檔名 -rw-r--r-- 1 root root 72 Jun 5 02:40 hello.c [root@www ~]# ./a.out Hello World <==呵呵!成果出現了!
直接以 gcc 編譯原始碼,並且沒有加上任何參數,則執行檔的檔名會被自動設定為 a.out 這個檔案名稱! 所以妳就能夠直接執行 ./a.out 這個執行檔啦
如果我想要產生目標檔 (object file) 來進行其他的動作,而且執行檔的檔名也不要用預設的 a.out ,那該如何是好?其實妳可以將上面的第 2 個步驟改成這樣
[root@www ~]# gcc -c hello.c [root@www ~]# ll hello* -rw-r--r-- 1 root root 72 Jun 5 02:40 hello.c -rw-r--r-- 1 root root 868 Jun 5 02:44 hello.o <==就是被產生的目標檔 [root@www ~]# gcc -o hello hello.o [root@www ~]# ll hello* -rwxr-xr-x 1 root Jun 5 02:47 hello <==這就是可執行檔! -o 的結果 -rw-r--r-- 1 root root 72 Jun 5 02:40 hello.c -rw-r--r-- 1 root root 868 Jun 5 02:44 hello.o [root@www ~]# ./hello Hello World
上面命令得到 hello 及 hello.o 兩個檔案, 真正可以執行的是 hello 這個 binary program 喔! 或許你會覺得,只要一個動作作出 a.out 就好了,幹嘛還要先製作目標檔再做成執行檔呢?由於我們的原始碼檔案有時並非僅只有一個檔案,所以我們無法直接進行編譯。 這個時候就需要先產生目標檔,然後再以連結製作成為 binary 可執行檔。
例如有2个files: thanks.c and thanks_2.c,thanks.c会call thanks_2,那么我们在编译时应该为:
[root@www ~]# gcc -c thanks.c thanks_2.c [root@www ~]# ll thanks* -rw-r--r-- 1 root root 76 Jun 5 16:13 thanks_2.c -rw-r--r-- 1 root root 856 Jun 5 16:13 thanks_2.o <==編譯產生的! -rw-r--r-- 1 root root 92 Jun 5 16:11 thanks.c -rw-r--r-- 1 root root 908 Jun 5 16:13 thanks.o <==編譯產生的! [root@www ~]# gcc -o thanks thanks.o thanks_2.o [root@www ~]# ll thanks* -rwxr-xr-x 1 root Jun 5 16:17 thanks <==最終結果會產生這玩意兒注意:如果你更新了 thanks_2.c 這個檔案的內容,則你只要重新編譯 thanks_2.c 來產生新的 thanks_2.o ,然後再以連結製作出新的 binary 可執行檔即可!而不必重新編譯其他沒有更動過的原始碼檔案。
* 呼叫連結函式庫
下面是一个求正弦值的例子
[root@www ~]# vim sin.c #include <stdio.h> int main(void){ float value; value = sin ( 3.14 / 2 ); printf("%f/n",value); }
当你使用下列命令编译的时
[root@www ~]# gcc sin.c sin.c: In function 'main': sin.c:5: warning: incompatible implicit declaration of built-in function 'sin' /tmp/ccsfvijY.o: In function `main': sin.c:(.text+0x1b): undefined reference to `sin' collect2: ld returned 1 exit status 注意看到上面最後一行,會有個錯誤訊息,代表沒有编译成功!這是因為 C 語言裡面的 sin 函示是寫在 libm.so 這個函式庫中,而我們並沒有在原始碼裡面將這個函式庫功能加進去。因此需要加入額外函式庫連結的方式 [root@www ~]# gcc sin.c -lm -L/lib -L/usr/lib <==重點在 -lm [root@www ~]# ./a.out <==嘗試執行新檔案!
使用 gcc 編譯時所加入的那個 -lm 是有意義的,他可以拆開成兩部份來看:
-l :是『加入某個函式庫(library)』的意思, m :則是 libm.so 這個函式庫,其中, lib 與副檔名(.a 或 .so)不需要寫-L :表示要连接的函式庫 libm.so 請到 /lib 或 /usr/lib 裡面搜尋。注意的是,由於 Linux 預設是將函式庫放置在 /lib 與 /usr/lib 當中,所以你沒有寫 -L/lib 與 -L/usr/lib 也沒有關係的另外,留意到#include <stdio.h>这行代码,它是將一些定義資料由 stdio.h 這個檔案讀入,這包括 printf 的相關設定。這個檔案其實是放置在 /usr/include/stdio.h 的!那麼萬一這個檔案並非放置在這裡呢?那麼我們就可以使用底下的方式來定義出要讀取的 include 檔案放置的目錄:
[root@www ~]# gcc sin.c -lm -I/usr/include
-I/path 後面接的路徑( Path )就是設定要去搜尋相關的 include 檔案的目錄啦!不過,同樣的,預設值是放置在 /usr/include 底下,除非你的 include 檔案放置在其他路徑,否則也可以略過這個項目
用 make 進行巨集編譯
如果你的software的源代码很多,如果直接用gcc来编译要进行很多步骤。能不能一個步驟就給他完成上面所有的動作呢?那就利用 make 這個工具吧!先試看看在這個目錄下建立一個名為 makefile 的檔案,內容如下
# 1. 先編輯 makefile 這個規則檔,內容只要作出 main 這個執行檔 [root@www ~]# vim makefile main: main.o haha.o sin_value.o cos_value.o gcc -o main main.o haha.o sin_value.o cos_value.o -lm # 注意:第二行的 gcc 之前是 <tab> 按鍵產生的空格喔! # 2. 嘗試使用 makefile 制訂的規則進行編譯的行為: [root@www ~]# rm -f main *.o <==先將之前的目標檔去除 [root@www ~]# make cc -c -o main.o main.c cc -c -o haha.o haha.c cc -c -o sin_value.o sin_value.c cc -c -o cos_value.o cos_value.c gcc -o main main.o haha.o sin_value.o cos_value.o -lm # 此時 make 會去讀取 makefile 的內容,並根據內容直接去給他編譯相關的檔案囉! # 3. 在不刪除任何檔案的情況下,重新執行一次編譯的動作: [root@www ~]# make make: `main' is up to date. # 看到了吧!是否很方便呢!只會進行更新 (update) 的動作而已。或許你會說:『如果我建立一個 shell script 來將上面的所有動作都集結在一起,不是具有同樣的效果嗎?』 效果當然不一樣,以上面的測試為例,我們僅寫出 main 需要的目標檔,結果 make 會主動的去判斷每個目標檔相關的原始碼檔案,並直接予以編譯,最後再直接進行連結的動作!真的是很方便啊!此外,如果我們更動過某些原始碼檔案,則 make 也可以主動的判斷哪一個原始碼與相關的目標檔檔案有更新過,並僅更新該檔案,如此一來,將可大大的節省很多編譯的時間呢!要知道,某些程式在進行編譯的行為時,會消耗很多的 CPU 資源呢!所以說, make 有這些好處:
簡化編譯時所需要下達的指令;若在編譯完成之後,修改了某個原始碼檔案,則 make 僅會針對被修改了的檔案進行編譯,其他的 object file 不會被更動;最後可以依照相依性來更新 (update) 執行檔。make 裡面最需要注意的大概就是那個規則檔案,也就是 makefile 這個檔案的語法
makefile 的基本語法與變數
基本的 makefile 規則是
標的(target): 目標檔1 目標檔2 <tab> gcc -o 欲建立的執行檔 目標檔1 目標檔2標的 (target) 就是我們想要建立的資訊,而目標檔就是具有相關性的 object files ,那建立執行檔的語法就是以 <tab> 按鍵開頭的那一行!特別給他留意喔,『命令列必須要以 tab 按鍵作為開頭』才行!他的規則基本上是這樣的:
在 makefile 當中的 # 代表註解;<tab> 需要在命令行 (例如 gcc 這個編譯器指令) 的第一個字元;標的 (target) 與相依檔案(就是目標檔)之間需以『:』隔開。例如,下面的makefile例子就包含了2个target: main and clean。
# 1. 先編輯 makefile 來建立新的規則,此規則的標的名稱為 clean : [root@www ~]# vi makefile main: main.o haha.o sin_value.o cos_value.o gcc -o main main.o haha.o sin_value.o cos_value.o -lm clean: rm -f main main.o haha.o sin_value.o cos_value.o # 2. 以新的標的 (clean) 測試看看執行 make 的結果: [root@www ~]# make clean <==就是這裡!透過 make 以 clean 為標的 rm -rf main main.o haha.o sin_value.o cos_value.o
如果我們想要建立 main 的話,輸入『make main』,如果想要清除有的沒的,輸入『make clean』即可啊!而如果想要先清除目標檔再編譯 main 這個程式的話,就可以這樣輸入:『make clean main』
你可能留意到,上面的makefile 裡面怎麼重複的資料這麼多啊!沒錯!所以我們可以再藉由 shell script 那時學到的『變數』來更簡化 makefile 喔:
[root@www ~]# vi makefile LIBS = -lm OBJS = main.o haha.o sin_value.o cos_value.o main: ${OBJS} gcc -o main ${OBJS} ${LIBS} clean: rm -f main ${OBJS}與 bash shell script 的語法有點不太相同,變數的基本語法為:
變數與變數內容以『=』隔開,同時兩邊可以具有空格;變數左邊不可以有 <tab> ,例如上面範例的第一行 LIBS 左邊不可以是 <tab>;變數與變數內容在『=』兩邊不能具有『:』;在習慣上,變數最好是以『大寫字母』為主;運用變數時,以 ${變數} 或 $(變數) 使用;在該 shell 的環境變數是可以被套用的,例如提到的 CFLAGS 這個變數!在指令列模式也可以給予變數。由於 gcc 在進行編譯的行為時,會主動的去讀取 CFLAGS 這個環境變數,所以,你可以直接在 shell 定義出這個環境變數,也可以在 makefile 檔案裡面去定義,更可以在指令列當中給予這個咚咚呢!例如:
[root@www ~]# CFLAGS="-Wall" make clean main # 這個動作在上 make 進行編譯時,會去取用 CFLAGS 的變數內容!也可以在 makefile 檔案裡面去定義:
[root@www ~]# vi makefile LIBS = -lm OBJS = main.o haha.o sin_value.o cos_value.o CFLAGS = -Wall main: ${OBJS} gcc -o main ${OBJS} ${LIBS} clean: rm -f main ${OBJS}咦!我可以利用指令列進行環境變數的輸入,也可以在檔案內直接指定環境變數,那萬一這個 CFLAGS 的內容在指令列與 makefile 裡面並不相同時,以那個方式輸入的為主?呵呵!問了個好問題啊! 環境變數取用的規則是這樣的:
make 指令列後面加上的環境變數為優先;makefile 裡面指定的環境變數第二;shell 原本具有的環境變數第三。此外,還有一些特殊的變數需要瞭解的喔:
$@:代表目前的標的(target)所以我也可以將 makefile 改成:
[root@www ~]# vi makefile LIBS = -lm OBJS = main.o haha.o sin_value.o cos_value.o CFLAGS = -Wall main: ${OBJS} gcc -o $@ ${OBJS} ${LIBS} <==那個 $@ 就是 main ! clean: rm -f main ${OBJS}
Tarball 安裝的基本步驟
取得原始檔:將 tarball 檔案在 /usr/local/src 目錄下解壓縮;取得步驟流程:進入新建立的目錄底下,去查閱 INSTALL 與 README 等相關檔案內容 (很重要的步驟!);相依屬性軟體安裝:根據 INSTALL/README 的內容察看並安裝好一些相依的軟體 (非必要);建立 makefile (命令“./configure”):以自動偵測程式 (configure 或 config) 偵測作業環境,並建立 Makefile 這個檔案;編譯(命令“make”):以 make 這個程式並使用該目錄下的 Makefile 做為他的參數設定檔,來進行 make (編譯或其他) 的動作;安裝(命令“make install”):以 make 這個程式,並以 Makefile 這個參數設定檔,依據 install 這個標的 (target) 的指定來安裝到正確的路徑!大部分的 tarball 軟體之安裝的指令下達方式:
./configure這個步驟就是在建立 Makefile 這個檔案囉!通常程式開發者會寫一支 scripts 來檢查你的 Linux 系統、相關的軟體屬性等等,這個步驟相當的重要, 因為未來你的安裝資訊都是這一步驟內完成的!另外,這個步驟的相關資訊應該要參考一下該目錄下的 README 或 INSTALL 相關的檔案!make cleanmake 會讀取 Makefile 中關於 clean 的工作。這個步驟不一定會有,但是希望執行一下,因為他可以去除目標檔案!因為誰也不確定原始碼裡面到底有沒有包含上次編譯過的目標檔案 (*.o) 存在,所以當然還是清除一下比較妥當的。 至少等一下新編譯出來的執行檔我們可以確定是使用自己的機器所編譯完成的嘛!makemake 會依據 Makefile 當中的預設工作進行編譯的行為!編譯的工作主要是進行 gcc 來將原始碼編譯成為可以被執行的 object files ,但是這些 object files 通常還需要一些函式庫之類的 link 後,才能產生一個完整的執行檔!使用 make 就是要將原始碼編譯成為可以被執行的可執行檔,而這個可執行檔會放置在目前所在的目錄之下, 尚未被安裝到預定安裝的目錄中;make install通常這就是最後的安裝步驟了,make 會依據 Makefile 這個檔案裡面關於 install 的項目,將上一個步驟所編譯完成的資料給他安裝到預定的目錄中,就完成安裝啦!請注意,上面的步驟是一步一步來進行的,而其中只要一個步驟無法成功,那麼後續的步驟就完全沒有辦法進行的! 因此,要確定每一的步驟都是成功的才可以!舉個例子來說,萬一今天你在 ./configure 就不成功了,那麼就表示 Makefile 無法被建立起來,要知道,後面的步驟都是根據 Makefile 來進行的,既然無法建立 Makefile,後續的步驟當然無法成功囉!
另外,如果在 make 無法成功的話,那就表示原始檔案無法被編譯成可執行檔,那麼 make install 主要是將編譯完成的檔案給他放置到檔案系統中的,既然都沒有可用的執行檔了,怎麼進行安裝? 所以囉,要每一個步驟都正確無誤才能往下繼續做!此外,如果安裝成功, 並且是安裝在獨立的一個目錄中,例如 /usr/local/packages 這個目錄中好了,那麼你就必需手動的將這個軟體的 man page 給他寫入 /etc/man.config 裡面去。
(important) Tarball 軟體安裝的建議事項 (如何移除?升級?)
為什麼Tarball 要在 /usr/local/src 裡面解壓縮呢?基本上,在預設的情況下,原本的 Linux distribution 釋出安裝的軟體大多是在 /usr 裡面的,而使用者自行安裝的軟體則建議放置在 /usr/local 裡面。
我們曉得幾乎每個軟體都會提供線上說明的服務,那就是 info 與 man 的功能。在預設的情況下, man 會去搜尋 /usr/local/man 裡面的說明文件, 因此,如果我們將軟體安裝在 /usr/local 底下的話,那麼自然安裝完成之後, 該軟體的說明文件就可以被找到了。
通常我們會建議大家將自己安裝的軟體放置在 /usr/local 下,至於原始碼 (Tarball)則建議放置在 /usr/local/src (src 為 source 的縮寫)底下。
再來看一看 Linux distribution 預設的安裝軟體的路徑會用到哪些?我們以 apache 這個軟體來說明的話:
/etc/httpd/usr/lib/usr/bin/usr/share/man我們會發現軟體的內容大致上是擺在 etc, lib, bin, man 等目錄當中,分別代表『設定檔、函式庫、執行檔、線上說明檔』。 好了,那麼你是以 tarball 來安裝時呢?如果是放在預設的 /usr/local 裡面,由於 /usr/local 原本就預設這幾個目錄了,所以你的資料就會被放在:
/usr/local/etc/usr/local/bin/usr/local/lib/usr/local/man但是如果你每個軟體都選擇在這個預設的路徑下安裝的話, 那麼所有的軟體的檔案都將放置在這四個目錄當中,未來再想要升級或移除的時候,就會比較難以追查檔案的來源囉! 而如果你在安裝的時候選擇的是單獨的目錄,例如我將 apache 安裝在 /usr/local/apache 當中,那麼你的檔案目錄就會變成:
/usr/local/apache/etc/usr/local/apache/bin/usr/local/apache/lib/usr/local/apache/man單一軟體的檔案都在同一個目錄之下,那麼要移除該軟體就簡單的多了! 只要將該目錄移除即可視為該軟體已經被移除囉!以上面為例,我想要移除 apache 只要下達『rm -rf /usr/local/apache』 就算移除這個軟體啦!當然囉,實際安裝的時候還是得視該軟體的 Makefile 裡頭的 install 資訊才能知道到底他的安裝情況為何的。因為例如 sendmail 的安裝就很麻煩......
這個方式雖然有利於軟體的移除,但不曉得你有沒有發現,我們在執行某些指令的時候,與該指令是否在 PATH 這個環境變數所記錄的路徑有關,以上面為例,我的 /usr/local/apache/bin 肯定是不在 PATH 裡面的,所以執行 apache 的指令就得要利用絕對路徑了,否則就得將這個 /usr/local/apache/bin 加入 PATH 裡面。另外,那個 /usr/local/apache/man 也需要加入 man page 搜尋的路徑當中!
除此之外, Tarball 在升級的時候也是挺困擾的,怎麼說呢?我們還是以 apache 來說明好了。WWW 伺服器為了考慮互動性,所以通常會將 PHP+MySQL+Apache 一起安裝起來 (詳細的資訊請參考伺服器架設篇) ,果真如此的話,那麼每個軟體在安裝的時候『都有一定的順序與程序!』 因為他們三者之間具有相關性,所以安裝時必需要三者同時考慮到他們的函式庫與相關的編譯參數。
假設今天我只要升級 PHP 呢?有的時候因為只有涉及動態函式庫的升級,那麼我只要升級 PHP 即可!其他的部分或許影響不大。但是如果今天 PHP 需要重新編譯的模組比較多,那麼可能會連帶的,連 Apache 這個程式也需要重新編譯過才行!真是有點給他頭痛的!沒辦法啦!使用 tarball 確實有他的優點啦,但是在這方面,確實也有他一定的傷腦筋程度。
由於 Tarball 在升級與安裝上面具有這些特色,亦即 Tarball 在反安裝上面具有比較高的難度 (如果你沒有好好規劃的話~),所以,為了方便 Tarball 的管理,通常鳥哥會這樣建議使用者:
最好將 tarball 的原始資料解壓縮到 /usr/local/src 當中;安裝時,最好安裝到 /usr/local 這個預設路徑下;考慮未來的反安裝步驟,最好可以將每個軟體單獨的安裝在 /usr/local 底下;為安裝到單獨目錄的軟體之 man page 加入 man path 搜尋:如果你安裝的軟體放置到 /usr/local/software/ ,那麼 man page 搜尋的設定中,可能就得要在 /etc/man.config 內的 40~50 行左右處,寫入如下的一行:MANPATH /usr/local/software/man
這樣才可以使用 man 來查詢該軟體的線上文件囉!
一個簡單的範例、利用 ntp 來示範如何Tarball安装
从http://www.ntp.org/downloads.html下载最新的ntp tarball file
1解壓縮下載的 tarball ,並參閱 README/INSTALL 檔案
[root@www ~]# cd /usr/local/src <==切換目錄 [root@www src]# tar -zxvf /root/ntp-4.2.4p7.tar.gz <==解壓縮到此目錄 ntp-4.2.4p7/ <==會建立這個目錄喔! ntp-4.2.4p7/libopts/ ....(底下省略).... [root@www src]# cd ntp-4.2.4p7/ [root@www ntp-4.2.4p7]# vi INSTALL <==記得 README 也要看一下!
2 檢查 configure 支援參數,並實際建置 makefile 規則檔
[root@www ntp*]# ./configure --help | more <==查詢可用的參數有哪些 --prefix=PREFIX install architecture-independent files in PREFIX --enable-all-clocks + include all suitable non-PARSE clocks: --enable-parse-clocks - include all suitable PARSE clocks: # 上面列出的是比較重要的,或者是你可能需要的參數功能! [root@www ntp*]# ./configure --prefix=/usr/local/ntp / > --enable-all-clocks --enable-parse-clocks <==開始建立makefile checking for a BSD-compatible install... /usr/bin/install -c ....(中間省略).... config.status: creating Makefile <==現在知道這個重要性了吧? config.status: executing depfiles commands
configure 設定參數較重要的就是那個 --prefix=/path 了,--prefix 後面接的路徑就是『這個軟體未來要安裝到那個目錄去?』如果你沒有指定 --prefix=/path 這個參數,通常預設參數就是 /usr/local
最後開始編譯與安裝
[root@www ntp*]# make clean; make [root@www ntp*]# make check [root@www ntp*]# make install
利用 patch 更新原始碼
如果升级到新版本,是否需要下載全新版本更新原本的舊程式呢?
事實上,新版本发布时所謂的『更新原始碼』常常是只有更改部分檔案的小部分內容而已。既然如此的話, 那麼我們是否可以就那些被更動的檔案來進行修改就可以了,也就是說, 舊版本到新版本間沒有更動過的檔案就不要理他,僅將有修訂過的檔案部分來處理即可。
沒有更動過的檔案的目標檔 (object file) 根本就不需要重新編譯,而且有更動過的檔案又可以利用 make 來自動 update (更新),如此一來,我們原先的設定 (makefile 檔案裡面的規則) 將不需要重新改寫或偵測!可以節省很多寶貴的時間
因此linux提供了patch 這個指令,很多的軟體開發商在更新了原始碼之後,幾乎都會釋出所謂的 patch file,也就是直接將原始碼 update 而已的一個方式喔!
例如upgrade from v1.1 to v1.2,软件开发商会提供一个patch file (e.g. xxx_1.1_to_1.2.patch file), 然后通过patch命令来upgrade。
patch 的基本語法如下:
patch -p數字 < patch_file
特別留意那個『 -p數字』,那是與 patch_file 裡面列出的檔名有關的資訊。假如在 “patch_file”的值为:
/home/guest/example/expatch.old
那麼當我下達『 patch -p0 < patch_file 』時,則更新的檔案是『 /home/guest/example/expatch.old 』,如果『 patch -p1 < patch_file』,則更新的檔案為『home/guest/example/expatch.old』,如果『patch -p4 < patch_file』則更新『expatch.old』,也就是說, -pxx 那個 xx 代表『拿掉幾個斜線(/)』的意思!這樣可以理解了嗎?好了,根據剛剛上頭的資料,我們可以發現比較的檔案是在 main-0.1/xxx 與 main-0.2/xxx , 所以說,如果你是在 main-0.1 底下,並且想要處理更新時,就得要拿掉一個目錄 (因為並沒有 main-0.2 的目錄存在, 我們是在當前的目錄進行更新的!),因此使用的是 -p1 才對喔!所以:
注意:使用patch命令只是更新了原始碼,並非軟體就更新!你還是得要將該軟體進行編譯後,才會是最終正確的軟體喔!此外,如果你 patch 錯誤呢?沒關係的!我們的 patch 是可以還原的啊!透過『 patch -R < ../main_0.1_to_0.2.patch 』就可以還原啦!
例題:
如果我有一個很舊版的軟體,這個軟體已經更新到很新的版本,例如核心,那麼我可以使用 patch file 來更新嗎?
答:
這個問題挺有趣的,首先,你必須要確定舊版本與新版本之間『確實有釋出 patch file 』才行,以 kernel 2.2.xx 及 2.4.xx 來說,這兩者基本上的架構已經不同了,所以兩者間是無法以 patch file 來更新的。不過, 2.4.xx 與 2.4.yy 就可以更新了。不過,因為 kernel 每次推出的 patch 檔案都僅針對前一個版本而已,所以假設要由 kernel 2.4.20 升級到 2.4.26 ,就必須要使用 patch 2.4.21, 2.4.22, 2.4.23, 2.4.24, 2.4.25, 2.4.26 六個檔案來『依序更新』才行喔!當然,如果有朋友幫你比對過 2.4.20 與 2.4.26 ,那你自然就可以使用該 patch file 來直接一次更新囉!
函式庫管理
函式庫又依照是否被編譯到程式內部而分為動態與靜態函式庫
靜態函式庫的特色:
副檔名:(副檔名為 .a)編譯行為:這類函式庫在編譯的時候會直接整合到執行程式當中,所以利用靜態函式庫編譯成的檔案會比較大一些;獨立執行的狀態:這類函式庫最大的優點,就是編譯成功的可執行檔可以獨立執行,而不需要再向外部要求讀取函式庫的內容 升級難易度:雖然執行檔可以獨立執行,但因為函式庫是直接整合到執行檔中, 因此若函式庫升級時,整個執行檔必須要重新編譯才能將新版的函式庫整合到程式當中。 也就是說,在升級方面,只要函式庫升級了,所有將此函式庫納入的程式都需要重新編譯!動態函式庫的特色:
副檔名:(副檔名為 .so)編譯行為:動態函式庫在編譯的時候,在程式裡面只有一個『指向 (Pointer)』的位置而已。也就是說,動態函式庫的內容並沒有被整合到執行檔當中,而是當執行檔要使用到函式庫的機制時, 程式才會去讀取函式庫來使用。由於執行檔當中僅具有指向動態函式庫所在的指標而已, 並不包含函式庫的內容,所以他的檔案會比較小一點。獨立執行的狀態:這類型的函式庫所編譯出來的程式不能被獨立執行, 因為當我們使用到函式庫的機制時,程式才會去讀取函式庫,所以函式庫檔案『必須要存在』才行升級難易度:雖然這類型的執行檔無法獨立運作,然而由於是具有指向的功能, 所以,當函式庫升級後,執行檔根本不需要進行重新編譯的行為,因為執行檔會直接指向新的函式庫檔案 (前提是函式庫新舊版本的檔名相同喔!)。目前的 Linux distribution 比較傾向於使用動態函式庫,因為如同上面提到的最重要的一點,就是函式庫的升級方便!
那麼這些函式庫放置在哪裡呢?絕大多數的函式庫都放置在:/usr/lib, /lib 目錄下! 此外,Linux 系統裡面很多的函式庫其實 kernel 就提供了,那麼 kernel 的函式庫放在哪裡?呵呵!就是在 /lib/modules 裡面啦!
ldconfig 與 /etc/ld.so.conf
如果我們將常用到的動態函式庫先載入記憶體當中 (快取, cache),這樣就可以增進動態函式庫的讀取速度?這個時候就需要 ldconfig 與 /etc/ld.so.conf 的協助了。
如何將動態函式庫載入快取記憶體當中呢?
首先,我們必須要在 /etc/ld.so.conf 裡面寫下『 想要讀入快取記憶體當中的動態函式庫所在的目錄』,注意喔, 是目錄而不是檔案;接下來則是利用 ldconfig 這個執行檔將 /etc/ld.so.conf 的資料讀入快取當中;同時也將資料記錄一份在 /etc/ld.so.cache 這個檔案當中吶!
範例:假設我的 MySQL 資料庫函式庫在 /usr/lib/mysql 當中,如何讀進 cache ?
[root@www ~]# vi /etc/ld.so.conf
include ld.so.conf.d/*.conf
/usr/lib/mysql <==這一行新增的啦!
[root@www ~]# ldconfig <==畫面上不會顯示任何的資訊,正常的!
[root@www ~]# ldconfig -p <==列出目前有的所有函式庫資料內容530 libs found in cache `/etc/ld.so.cache'
libz.so.1 (libc6) => /usr/lib/libz.so.1
libxslt.so.1 (libc6) => /usr/lib/libxslt.so.1
#函式庫名稱 => 該函式庫實際路徑
程式的動態函式庫解析: ldd
如何判斷某個可執行的 binary 檔案含有什麼動態函式庫?很簡單,使用 ldd命令
例如我想要知道 /usr/bin/passwd 這個程式含有的動態函式庫有哪些,使用下列命令
[root@www ~]# ldd /usr/bin/passwd
未來如果你常常升級安裝 RPM 的軟體時 ,應該常常會發現那個『 相依屬性』的問題吧!沒錯!我們可以先以 ldd 來視察『相依函式庫』之間的相關性!以先取得瞭解
檢驗軟體正確性
如果检查我们下载的软件是否被人修改过?如何判斷檔案的正確性?這個時候就有 md5sum 與 sha1sum 這個檔案指紋来验证。
例如,台灣高速網路中心所提供的 CentOS 5.3 原版光碟下載點:
http://ftp.twaren.net/Linux/CentOS/5.3/isos/i386/
同時提供了 CentOS 5.3 所有光碟/DVD 的 ISO 檔案 MD5 編碼,透過這個編碼的比對, 我們就可以曉得下載的檔案是否有問題。那麼萬一 CentOS 提供的光碟映象檔被下載之後,讓有心人士偷偷修改過,再轉到 Internet 上面流傳,那麼你下載的這個檔案就不是原廠提供的!
md5sum / sha1sum
目前有多種機制可以計算檔案的指紋碼,我們選擇使用較為廣泛的 MD5 與 SHA1 加密機制來處理。 同樣的,我們以高速電腦中心談到的 CentOS 5.3 的網路安裝映像檔來處理試看看好了。在上面的連結網址上面,妳會看到幾個檔案:
CentOS-5.3-i386-netinstall.iso:CentOS 5.3 的網路安裝映像檔;md5sum.txt: MD5 指紋編碼sha1sum.txt: SHA1 指紋編碼如果妳下載了 CentOS-5.3-i386-netinstall.iso 後,再以 md5sum 與 sha1sum 去檢驗這個檔案時,檔案所回傳的指紋碼應該要與網站上面提供的檔案指紋碼相同才對!我們由網站上面提供的指紋碼知道這個映像檔的指紋為:
MD5 : 6ae4077a9fc2dcedca96013701bd2a43SHA1: a0c640ae0c68cc0d9558cf4f8855f24671b3dadb [root@www ~]# md5sum/sha1sum [-bct] filename [root@www ~]# md5sum/sha1sum [--status|--warn] --check filename 選項與參數: -b :使用 binary 的讀檔方式,預設為 Windows/DOS 檔案型態的讀取方式; -c :檢驗檔案指紋; -t :以文字型態來讀取檔案指紋。 範例一:將剛剛的檔案下載後,測試看看指紋碼 [root@www ~]# wget / > http://ftp.twaren.net/Linux/CentOS/5.3/isos/i386/CentOS-5.3-i386-netinstall.iso [root@www ~]# md5sum CentOS-5.3-i386-netinstall.iso 6ae4077a9fc2dcedca96013701bd2a43 CentOS-5.3-i386-netinstall.iso [root@www ~]# sha1sum CentOS-5.3-i386-netinstall.iso a0c640ae0c68cc0d9558cf4f8855f24671b3dadb CentOS-5.3-i386-netinstall.iso好了,那麼如何應用這個東西呢?基本上,你必須要在你的 Linux 系統上為你的這些重要的檔案進行指紋資料庫的建立 (好像在做戶口調查!),將底下這些檔案建立資料庫:
/etc/passwd/etc/shadow( 假如你不讓使用者改密碼了 )/etc/group/usr/bin/passwd/sbin/portmap/bin/login ( 這個也很容易被駭! )/bin/ls/bin/ps/usr/bin/top這幾個檔案最容易被修改了!因為很多木馬程式執行的時候,還是會有所謂的『執行序, PID』為了怕被 root 追查出來,所以他們都會修改這些檢查排程的檔案,如果你可以替這些檔案建立指紋資料庫 (就是使用 md5sum 檢查一次,將該檔案指紋記錄下來,然後常常以 shell script 的方式由程式自行來檢查指紋表是否不同了!),那麼對於檔案系統會比較安全啦!