歡迎您光臨本站 註冊首頁

Linux初學者Patch使用指南

←手機掃碼閱讀     火星人 @ 2014-03-09 , reply:0
 簡介

  本文的目的是向Linux新手介紹一種無價的資源,Larry Wall的patch程序.patch是用來查找文件之間差異的GNU diff命令的一個介面;diff有很多選項,但是該命令最常用的用途是用來生成一個文件,該文件中列出了內容發生改變的行,顯示兩個原始文件、修改過的行以及由於內容沒有變化而忽略掉的行.patch典型地用於把一個目錄下的源代碼文件更新到新的版本,從而就避免了下載整個新的源代碼檔案的必要.下載一個有效的patch僅僅需要下載發生變化的那些代碼行就可以了.

  patch最初源自十年前,那時網路帶寬的限制促進了patch的發展,然而和當時的很多Unix工具一樣,直到現在,patch還在廣泛應用.在Dr. Dobb之旅的2月份的程序員雜誌中,Larry Wall對早期的patch做了一些很有趣的說明:

  DDJ:順便問一下,patch和diff哪個出現的早?

  LW:從很長一段時間來說,diff出現地比較早.我想diff大約比patch早10年出現,一回想起來,我就納悶為什麼沒有人早些想到使用patch呢?

  但是我想我知道這中間的原因.這很大程度上是心理因素使然.當開發出diff時,程序員增加了一個e選項,我想就是這個選項的原因,該選項後來滋生為一個ed腳本,因此大家都會對自己說,"嗯,如果我想自動使用diff,那麼我就使用這個選項."因此從來都沒有人編寫一個計算機程序來獲取其它格式的輸出並使用這些結果.或者是那些設計diff的人員,或者是那些使用diff格式而受益的人員太沉迷其中了,你可以對那些已經修改過的內容使用diff操作並讓這些內容正常工作都是很容易的.

  現在回想起來,這個問題是顯而易見的.但是平心而論,與其說這是一個天才的靈感的閃現,還不如說這是自信心的體現.我開發出rn的第一個版本,然後繼續為它編寫補丁,這整個事情就是一團亂麻.你不可能強制用戶使用補丁,他們可以手工完成這些工作.因此,他們就會省略一些自己認為不必要的工作,他們把新的修改加諸於原來的程序之上,因此而是的程序混亂.我編寫補丁,這樣就沒有人找借口說這很難了.



  我不清楚是否事實就是如此,但是多年以來,我一直對別人講patch對於計算機文化的影響比rn和Perl的影響都要大.現在Internet的速度比原來有大幅度的提高,把整個發行版本分散到世界各地也變得更加簡單,似乎只有在開發者之間才需要傳送補丁.我已經很多年沒有傳送Perl的patch工具包了.我認為雖然patch整體上的重要性在逐漸降低,但是仍然是開發者交流思想的一種方法.但是就那一段時間而言,patch真正在相當大的程度上都影響了軟體的開發方式.

  Larry Wall針對patch對於計算機業界總體上重要性正在降低的評價可能是正確的,但是在自由軟體世界中,patch仍然是一種必不可少的工具.無處不在的patch是的新手和非程序員能夠簡單地參與軟體的alpha測試和beta測試,這對於整個計算機業界是十分有益的.

  在我留意到在Linux內核郵件列表中會周期性的出現這樣一件事情時就產生了寫這篇文章的念頭.大約每三個月就會有人張貼要求把Linux內核源代碼的發行版本獨立出來的文章,據說這是有些人只對i386的代碼和IDE的磁碟驅動感興趣,他們並不想為每個內核發行版本都下載Alpha、Sparc等等的文件和眾多的SCSI驅動程序.這篇文章後面緊跟的是一些耐心的回復文章(有些文章則並沒有耐心),大部分文章都是在討論原來的使用有關patch來更新內核源代碼.接著Linus Torvalds就會再次聲明自己沒有興趣投身於這種把內核源程序切割成小塊的繁雜的勞動,但是如果有人願意,他們可以自由地開展這項獨立的工程.到現在為止都沒有志願者出現.我並不想譴責那些內核黑客不能耐心等待,卻把生活變得複雜;我猜想直接使用內核工作可能比檢查整個內核的發行版本方案要更加有趣、更富有挑戰性.下載11M的內核源程序包可是件非常耗費時間的事情(對於那些按照時間上網的人來說,這是很昂貴的),但是內核patch才只有幾十K大小,很少會超過1M.我的硬碟上的2.1.99開發內核源程序經過patch的升級,已經升級到了2.1.119版本,我懷疑如果我緊隨內核的發展而不斷升級,那麼也許我就要完整地下載每一個發行版本了.






  使用patch

  patch附帶有一個很好的幫助,其中羅列了很多選項,但是99%的時間只要兩個選項就能滿足我們的需要:

  patch -p1 < [patchfile]

  patch -R < [patchfile] (used to undo a patch)

  -p1選項代表patchfile中文件名左邊目錄的層數,頂層目錄在不同的機器上有所不同.要使用這個選項,就要把你的patch放在要被打補丁的目錄下,然後在這個目錄中運行path -p1 < [patchfile].來自Linux內核patch的一個簡短的引用可以這樣實現:

  diff -u --recursive --new-file v2.1.118/linux/mm/swapfile.c linux/mm/swapfile. c--- v2.1.118/linux/mm/swapfile.c Wed Aug 26 11:37:45 1998 linux/mm/swapfile.c Wed Aug 26 16:01:57 1998 @@ -489,7 489,7 @@

  int swap_header_version;

  int lock_map_size = PAGE_SIZE;

  int nr_good_pages = 0; - char tmp_lock_map = 0; unsigned long tmp_lock_map = 0;

  應用來自本段中使用-p1開關拷貝的patch可以有效地減短patch定位的路徑;patch會查找當前目錄下一個名為/mm的子目錄,接著應該會在這兒發現swapfile.c文件,然後等待打補丁.在這個過程中,以破折號(「-」號,譯者注)開始的行會被一個以加號(「 」號,譯者注)開始的行代替.一個典型的patch會包含對多個文件的更新,每個部分中都由對兩個版本的文件運行diff -u命令的輸出結果組成.

  patch在操作時把自己的輸出結果顯示在屏幕上,但是這種輸出通常都滾屏太快,來不及觀看.原來準備patch的文件名為*.orig,新的patch文件會覆蓋這個初始文件名.

  打補丁的問題

  使用不同版本的patch問題來源可能不同,所有的版本在網路上都是可用的.Larry Wall近年來已經不再做很多工作來更新patch了,這可能是由於他發行的一個版本在大部分情況下都能正常運行.最近幾年以來,一直是GNU項目的FSF程序員發行新版本的patch.他們修訂有問題的patch,但是我最近一直使用沒有問題的2.5版本(這是Debian2.0的發行版本號).過去,我的2.1版本也一直運行的很好.當前的GNU patch的版本可以從GNU FTP站點上獲取,然而大部分人都只使用他們Linux發行版中所提供的版本.



  讓我們假定你已經對一個目錄下的源程序文件進行了patch修補工作,但是patch並沒有清晰地發揮作用.這可能會偶然發生,在打補丁的過程中會顯示錯誤信息,其中帶有行號,說明哪一個文件出現了問題.有時錯誤是很明顯的,例如缺少了分號,這種錯誤可以不費多大力氣就能改正.另外一種可能是從patch部分刪除了產生問題的部分,但是這樣根據所涉及到的文件的不同可能會正常工作,也可能不能正常工作了.

  另外一種常見的錯位為:假設你有一個未使用tar打包的內核源程序文件,在/linux/arch/下瀏覽各個子目錄時你會發現各種機器體系結構子目錄,例如alpah、sparc等等.如果你和大多數Linux用戶一樣,使用的是Intel的處理器(或者是Intel系列),你可以決定刪除這些目錄,這些目錄對於編譯你特殊的內核並不需要,只是白白佔用了磁碟空間.一段時間之後發行了一個新的內核patch,此時試圖進行patch操作,當它發現不能找到自己打補丁需要的Alpha或者PPC文件,就會停頓下來.幸運的是patch在這些地方允許用戶參與,它會詢問"Skip this patch?"回答"y",patch就可以按照正確的路徑繼續執行.也許你需要回答這個問題很多次,因此允許自己不需要的目錄保留在磁碟上是一種很好的方法.

  給內核打補丁的技巧

  很多Linux用戶使用patch都主要是給內核源程序打補丁,因此有一些技巧可以使用.可能最簡單的方法是使用shell腳本給內核打補丁,這可以在內核源程序樹中的/scripts子目錄中找到.這種方便的、編寫良好的腳本是由Nick Holloway在1995年編寫的;兩年以後,Adam Sulmicki增加了多種壓縮格式的支持,包括*.bz、*.bz2、compress、gzip和無格式文本(也就是已經解壓的patch).這個腳本假定在你使用新版本的patch時,你的內核源程序是在/usr/src/linux目錄中.這些預設值可以通過這種格式的命令行開關覆蓋:patch-kernel [sourcedir [patchdir] ].如果任何一部分的patch失敗,對內核打補丁的過程都會失敗,但是如果patch清晰地起作用,它就會調用find,這會刪除所有的patch留下的*.orig文件.



  如果你準備查看命令的輸出,或者可能你希望保留*.orig文件直到你確定打過補丁的源程序編譯已經通過,按照我的經驗,直接運行patch(正如前面介紹的一樣,patch位於內核源程序的最高目錄)是很可靠的.為了避免對patch進行解壓,在使用之前,可以使用這樣一個技巧:

  gzip -cd patchXX.gz | patch -p1

  或者

  bzip2 -dc patchXX.bz2 | patch -p1

  在使用patch之後,可以使用find程序來檢測被拒絕的文件:

  find . -name *.rej

  第一次使用這個命令,語法可能有些不清楚.點號(「.」)說明find應該查找當前目錄並遞規查找當前目錄之下的所有子目錄.記住,點號前後都應該有一個空格.通配符"*"號前面的反斜線把星號轉義出來,以免shell會搞混,星號是有其它意義的.如果find找到了任何的*.rej文件,它就會把文件名列印到屏幕上.如果沒有任何輸出find就退出了,那麼就差不多能確定patch正確發揮作用了.

  find的另外一個工作是刪除*.orig文件:

  find . -name *.orig -print0 | xargs -0r rm -f

  這個命令敲起來相當麻煩,可以使用一個新的shell別名來代替這個命令.在你的~/.bashrc文件中類似這樣的一行:

  alias findorig find . -name *.orig -print0 | xargs -0r rm -f

  可以允許你只輸入findorig就可以調用前面的命令.如果別名命令的定義中包含空格,那麼就必須使用單引號.為了不用先退出再重新登陸就可以使用一個新的別名,可以在命令行中敲如~/.bashrc.

  附加內容和結束語

  在撰寫本文時,我剛好把自己的機器從2.1版本使用patch升級到了2.5版本.這兩個版本都是來自現在的FSF/GNU維護人員.馬上我就注意到2.5版本默認的輸出已經改變了,屏幕上顯示的信息變少了.原來在patch檢測進行修補的行號時顯示的Larry Wall的"...hmm"不見了.2.5版本的輸出只剩下諸如"patching file [filename]"之類的信息了,而沒有早期版本顯示的那麼多信息了.無可否認,信息滾屏太快,根本無法閱讀,但是輸出可以重定向到一個文件中供以後使用.這種變化不會影響程序的功能,但是減少了人為的成分.在我看來,使用諸如原來的"...hmm"信息和源代碼中的註釋一樣,對於提醒用戶程序是顯示執行的工作的結果是很有價值的,這就像人在呼吸一樣,而不應該使用一些毫無結果的位集合.通過對patch命令行增加--verbose開關可以恢復原來的顯示內容,但是我相信很多用戶既不會注意到這個選項,也不會不辭辛勞地輸入這個選項.2.1和2.5版本的另外一個不同是除非patch給出了-b選項,否則不能創建*.orig備份文件.



  對於那些對軟體和內核"前沿"bug報告測試和提供測試報告不感興趣的人來說,patch並不是必須的,但是通常大部分Linux世界里有趣的開發都是屬於這個範疇的.獲得patch的使用方式並不困難,這種努力可以得到充分的回報.

  (譯者註:由於水平有限,錯誤疏漏之處在所難免,如果你認為本文翻譯的有問題,可以對其進行修改,請將修改後的文章給譯者(xjtufr@263.net)發送一份.)


[火星人 ] Linux初學者Patch使用指南已經有742次圍觀

http://coctec.com/docs/linux/show-post-57920.html