怎樣為linux核心打補丁(轉)

BSDLite發表於2007-08-15
怎樣為linux核心打補丁(轉)[@more@]在Linux核心郵件列表中一個經常被問到的問題就是怎樣為Linux核心打一個補丁,或者更具體一點說,
存在這麼多的主幹/分支,一個補丁到底要打在哪個版本的基礎核心上。希望這篇文件能夠為你解釋明白這
一點。
除了解釋怎樣應用以及解除安裝補丁以外,在這裡還提供了一個不同核心樹(以及如何為它們打上特
定補丁)的簡要介紹。
什麼是補丁?
----------
一個補丁就是一個文字文件,這個文件包含了在兩個不同版本的原始碼樹之間的變化。
補丁是透過diff應用程式來建立的。
為了正確地打上一個補丁,你需要知道這個補丁是從哪個基礎版本產生出來的以及這個補丁將要把
目前的原始碼樹變化到什麼新的版本。這些資訊或者會出現在補丁檔案的原資料中,或者可能
從檔名中推斷出來。
怎樣打補丁和解除安裝補丁
-------------------
可以使用patch程式來打一個補丁。patch程式讀取一個diff(或者patch)檔案,然後把檔案中
描述的變化內容應用到程式碼樹上。
Linux核心中的補丁是相對於儲存核心原始碼目錄的父目錄而生成的。
這就意味著:patch檔案中的檔案路徑包含了它所基於的核心原始檔目錄的名字(或者像是"a/"和"b/"
之類的其它名字)。
由於這很可能和你本地機器上的核心原始碼目錄的名字不匹配(但是對於檢視一個沒有標籤的補丁所
基於的核心版本是非常有用的)。你應該切換到你的核心原始碼目錄,並且在打補丁的時候去掉patch
中檔名字路徑的第一個分量(patch命令的-p1引數可以完成這個任務)。
為了解除安裝掉一個以前已經打上的補丁,使用-R引數來打補丁。
file:///D|/applying-patches.txt(第 1/9 頁)2006-8-15 18:22:12
file:///D|/applying-patches.txt
於是,如果你使用如下的命令來打補丁:
patch -p1 < ../patch-x.y.z
那麼你可以像下面這樣來解除安裝掉這個補丁:
patch -R -p1 < ../patch-x.y.z
我怎樣把一個patch/diff檔案加到一個patch中去?
-------------------------------------------
這個可以透過很多種不同的方法來辦到(像是Linux以及其它的類Unix作業系統一樣)。
在下面所有的例子中,我把這個檔案(未壓縮)以下面的語法透過標準輸入加入到patch中:
patch -p1 < path/to/patch-x.y.z
如果你只是想能夠照著下面的例子而並不想知道其它的打補丁的方法的話,那麼你就可以
不閱讀這一節餘下的內容了。
也可以透過patch的-i引數來獲得檔案的名字,就像下面這樣:
patch -p1 -i path/to/patch-x.y.z
如果你的patch檔案是使用gzip或者bzip2來壓縮的,那麼你在使用之前就不必解壓縮了,你可以
像下面這樣把它加入到patch檔案中:
zcat path/to/patch-x.y.z.gz | patch -p1
bzcat path/to/patch-x.y.z.bz2 | patch -p1
如果你想在打補丁之前,手動解壓縮這個patch檔案,那麼你就可以對這個檔案進行gunzip
或者bunzip2操作---就像下面這樣:
gunzip patch-x.y.z.gz
bunzip2 patch-x.y.z.bz2
這個將會給你一個無格式的文字patch-x.y.z檔案,這時候你就可以把這個東西以你喜歡的方式通
過標準輸入或者是-i引數來加入到patch中。
一些其它的比較好的引數是-s,這個引數使patch保持無輸出而不是輸出錯誤,這將阻止錯誤在
螢幕上滾動的速度太快。--dry-run引數使得patch命令僅僅列印出來一個將要打的patch的列表
,沒有真正的做任何變動。最後,-verbose告訴patch命令列印出正在進行的工作的更多資訊。
打補丁時候的常見錯誤
-------------------
當用patch命令來打一個補丁的時候,它試圖以不同的方法來驗證這個檔案的完整性。
檢查這個檔案是一個有效的patch檔案並且檢查這些被改變周圍的程式碼是不是和提供的
file:///D|/applying-patches.txt(第 2/9 頁)2006-8-15 18:22:12
file:///D|/applying-patches.txt
上下文相匹配。這些僅僅是patch所作的兩個最基本的完整性檢查。
如果patch遇到了一些看起來不正確的事情,那麼它有兩種選擇。它可以拒絕應用這些改變並且
異常中斷或者它試圖找到一個方法來使patch命令僅僅做一些比較小的改變。
一個patch試圖修正錯誤的例子就是:如果所有的上下文都匹配,被改變的行匹配,但是這些行的
行號不匹配。這是可能發生的,例如,如果patch在一個檔案的中間做了一些改變,但是出於一些
原因在檔案的開頭處一些行被新增了進來或者被刪除了。在這種情況下,一切看起來都很好,它只
是簡單地上下移動一點,這時候patch通常會修正這些行號並且打上這個補丁。
任何時候,只要patch在打補丁的時候需要改動檔案的一些內容,它就會告訴你說:
這個補丁打得有點兒混亂。你應該對這些改變保持一些警惕,因為即使補丁很可能被正確
地打上了,但是情況並不總是這樣,有些情況下結果會是錯誤的。
當patch命令遇到一個變化而不能進行使用一種模糊的方法進行彌補的時候,它就會徹底地
放棄這個動作,並且留下來一個以.rej為副檔名的檔案。你可以閱讀這個檔案來檢視到底是
什麼改變不能進行下去,從而在你願意的情況下來手動修補它。
如果你的核心原始碼上沒有應用任何第三方的補丁,只是一些來自kernel.org的補丁,並且你打這些補丁
的順序是正確的,而且你自己沒有對這些原始檔進行改動過,那麼你應該就不會看到一個補丁
對這個檔案的模糊的改變或者是一些拒絕訊息。如果你確實看到了這些訊息的話,那麼將有非常高的
危險性,這說明或者是你的本地的原始碼書或者是補丁檔案在某些方面被玷汙了。在這種情況下,你很可能
是應該重新下載這個補丁檔案,如果事情仍然還是保持原樣的話,那麼我建議你去嘗試從kernel.org上
下載一個完整的新的原始碼樹。
讓我們來看一下補丁可能產生的更多資訊。
如果patch命令停下來並且顯示一個“File to patch”的提示符,那麼這個時候patch命令找不到
要打補丁的檔案。很可能的情況是你忘記指定-p1引數或者你處於一個錯誤的目錄中了。更加不
常見的一種情況是,你會發現一些補丁需要使用-p0引數而不是-p1引數來打補丁(閱讀這個補丁檔案
應該能揭示出這些資訊--如果是這樣的話,這是一種建立補丁檔案的人所犯的錯誤,但是不致命)
如果你得到資訊“Hunk #2 succeeded at 1887 with fuzz 2 (offset 7 lines)”,或者是一個類似
的訊息,那就意味著patch命令必須調整改變的位置(在這個例子中,它需要在它想打補丁的地方移動7行來
適應這個補丁)。結果得到的檔案可能正確也可能不正確,這決定於這個檔案與所期望的檔案不相同的原因。
這常常發生於你所要打的patch產生於一個另外一個核心版本,這個核心版本和你要打的patch所基於的核心
版本不同。
如果你得到一個類似於“Hunk #3 FAILED at 2387”之類的訊息,那麼這就意味著不能正確地打上這個
補丁,並且patch程式也不能模糊地透過。這將產生一個導致patch失敗的.rej檔案並且產生一個.orig
檔案把一些不能改變的原始內容顯示給你。
如果你得到的資訊是:“Reversed (or previously applied) patch detected! Assume -R? [n]”,
那麼patch檢測到了這個補丁檔案中包含的改變已經應用在了目標檔案上。如果你確實已經在此之前打了
這個補丁並且重新打補丁遇到了錯誤,那麼你可以簡單地選擇[n]o並且終止這次補丁動作。如果你之前
打了補丁並且想得到打補丁以前的版本,但是忘記了指定-R引數,那麼你在這裡可以回答[y]es來使用patch
file:///D|/applying-patches.txt(第 3/9 頁)2006-8-15 18:22:12
file:///D|/applying-patches.txt
為你恢復它。這也可能發生在補丁檔案的建立者在建立補丁檔案的時候倒置了原始檔和目標目錄的位置,
在這種情況下從patch中revert實際上是打上了這個補丁。
一個類似於“patch: **** unexpected end of file in patch”或者“patch
unexpectedly ends in middle of line”的訊息意味著patch命令對你加入到它之中的
檔案覺得沒有意義。或者是你的下載被打斷了,你試圖打上一個沒有壓縮的patch檔案,而事前
並沒有解壓縮它,或者是你使用的補丁檔案在傳輸的某個地方被一個郵件客戶端或者一個郵件
傳輸代理給損壞了。例如,透過把一個長行分成兩行。通常情況下這些警告可以透過把這兩個
被分開的行合併起來來解決。
就像我上面提到的那樣,如果你打的是從kernel.org得來的補丁到一個正確的版本,
並且你沒有修改過原始碼樹,這些錯誤將從來不會發生。因此如果你從kernel.org來的
補丁上得來了這些錯誤,那麼你應該很可能認為或者是你的補丁檔案或者是原始碼樹
損壞掉了。我建議你重新開始下載一個完整的核心樹以及你想要打的補丁。
有patch的替代品麼?
-----------------
是的,有一些替代品。
你可以使用“interdiff”程式(來產生一個檔案來表示
兩個補丁檔案之間之間的不同,然後打上這個檔案。這可以使你從一個像2.6.12.2的版本一步
就可以到達版本2.6.12.3。-z標誌甚至可以使你送給interdiff一些使用gzip或者bzip2壓縮的
格式檔案而不用使用zcat或者bzcat或者手動解壓縮。
下面展示了你可以怎樣一步就可以從2.6.12.2到達2.6.12.3
interdiff -z ../patch-2.6.12.2.bz2 ../patch-2.6.12.3.gz | patch -p1
儘管interdiff可以節省一到兩步,但是我還是建議你通常情況下應該做這些附加的步驟,
這是由於在某些情況下interdiff會把事情弄糟。
另外的一個替代品是“ketchup”,是一個使用python寫的指令碼,這個指令碼可以自動下載和
打上一些補丁(
另外一些比較好的工具是diffstat,可以顯示patch所作的所有改變的總結;lsdiff,可以顯示
在一個patch檔案中受影響的檔案的簡短列表,以及(可選)每一個補丁的行號碼;grepdiff,可
以顯示在補丁包含給定的正規表示式的時候顯示一個被補丁檔案修改的檔案的列表。
我可以從哪兒下載這些補丁?
-----------------------
file:///D|/applying-patches.txt(第 4/9 頁)2006-8-15 18:22:12
file:///D|/applying-patches.txt
補丁檔案可以從來獲得
最近的補丁檔案可以從首頁的連結中得到,但是他們也有自己的特定的主頁。
2.6.x.y(-穩定)以及2.6.x補丁位於:

-rc補丁位於:

-git補丁位於:

-mm核心補丁位於:

在ftp.kernel.org中,你可以使用ftp.cc.kernel.org,這裡cc是一個國家的程式碼。這樣你就可以從一個
在地理上離你比較近的位置的映象站點下載,從而使你獲得較快的下載速度,全域性上更少的頻寬以及
對於kernel.org主伺服器的更小的壓力---這是比較好的事情,所以你還是在可能的時候使用這些映象
站點。
2.6.x核心
---------
這是Linus釋出的基礎穩定版本.釋出的最高版本是最新的。
如果發現了衝突或者嚴重的瑕疵,那麼在這個基礎上,一個-stable的修正補丁就會被髮布
出來(參見下面)。一旦一個新的2.6.x的基礎核心釋出出來,就可以得到一個測試版本的補丁
,這個補丁基於先前的2.6.x版本核心和這個新的核心。
為了應用一個從2.6.11到2.6.12的補丁,你最好按照下面來做(注意這些補丁不能應用於2.6.x.y的核心,
而是應用在2.6.x的基礎核心---如果你需要從2.6.x.y到2.6.x+1,那麼你首先需要解除安裝掉2.6.x.y的補丁)
下面是一些例子:
#從2.6.11到2.6.12
$ cd ~/linux-2.6.11 # 切換到核心原始碼目錄
$ patch -p1 < ../patch-2.6.12 # 應用2.6.12補丁
$ cd ..
$ mv linux-2.6.11 linux-2.6.12 # 重新命名原始碼目錄
# moving from 2.6.11.1 to 2.6.12
$ cd ~/linux-2.6.11.1 # 切換到核心原始碼目錄
$ patch -p1 -R < ../patch-2.6.11.1 # 恢復出來2.6.11.1
# 原始碼目錄現在是2.6.11
$ patch -p1 < ../patch-2.6.12 # 應用新的2.6.12補丁
file:///D|/applying-patches.txt(第 5/9 頁)2006-8-15 18:22:12
file:///D|/applying-patches.txt
$ cd ..
$ mv linux-2.6.11.1 linux-2.6.12 # 重新命名原始碼目錄
2.6.x.y核心
-----------
帶有四位數字版本號的核心是-stable的核心。他們包含了對一個給定的2.6.x核心的一些安全
問題以及發現的重要的退化的修復。
對於那些想要最近的穩定核心並且對於測試開發中的試驗性的版本沒有興趣的
使用者來說,我們推薦這個分支。
如果沒有可用的2.6.x.y核心,那麼最高數字的2.6.x核心是目前的穩定核心。
注意:維護穩定核心的團隊通常會做一些增量的補丁,就像是基於最近的主流版本釋出
的補丁一樣。但是在下面我僅僅說明了非增量的情況。那些增量式的版本可以在下面的ftp
處找到:
這些補丁不是增量式的,意味著例如對於2.6.12.3補丁不能應用於2.6.12.2的核心原始碼
上去,但是可以應用在2.6.12核心程式碼上。
因此,為了為了把2.6.12.3的補丁應用到你使用的2.6.12.2的核心原始碼上,你不得不解除安裝掉
2.5.12.2補丁(因此你可以得到一個基礎的2.6.12的核心原始碼),並且應用新的2.6.12.3補丁。
下面是一個小例子:
$ cd ~/linux-2.6.12.2 # 切換到核心原始碼目錄
$ patch -p1 -R < ../patch-2.6.12.2 # 迴歸2.6.12.2補丁
$ patch -p1 < ../patch-2.6.12.3 # 應用新的2.6.12.3補丁
$ cd ..
$ mv linux-2.6.12.2 linux-2.6.12.3 # 重新命名核心原始碼目錄
-rc核心
-------
這些是候選的釋出核心。當Linus認為目前的git(核心的原始碼管理工具)核心樹處於一個
健全的穩定狀態足以用來測試的時候,而釋出的開發核心。
這些核心是不穩定的,如果你試著執行他們應該會想到可能會不時地有問題出現。
但是這是主開發分支上的最穩定的核心,並且最終會變成下一個穩定的核心。因此
讓儘可能多的人來測試它就顯得格外重要。
file:///D|/applying-patches.txt(第 6/9 頁)2006-8-15 18:22:12
file:///D|/applying-patches.txt
對於那些想幫忙測試開發中的核心但是又不想跑那些試驗性的東西的人來說,這將是
一個非常好的分支。(這樣的人應該參照下面的關於-git和-mm核心的部分)
-rc補丁是非增量式的,他們應用於2.6.x核心上,就像上面描述的2.6.x.y核心一樣。在-rcN
字尾之前的核心版本號代表了這個-rc的核心最終會變成的核心版本。
因此,2.6.13-rc5意思是這是2.6.13核心的第五個候選的釋出版本,並且這個補丁應該打在
2.6.12的核心原始碼上。
下面是3個關於怎樣打這些補丁的例子:
# 首先是一個從2.6.12到2.6.13-rc3的例子
$ cd ~/linux-2.6.12 # 切換到2.6.12的原始碼目錄
$ patch -p1 < ../patch-2.6.13-rc3 # 打上2.6.13-rc3的補丁
$ cd ..
$ mv linux-2.6.12 linux-2.6.13-rc3 # 重新命名原始碼目錄
# 現在從2.6.13-rc3遷移到2.6.13-rc5
$ cd ~/linux-2.6.13-rc3 # 切換到2.6.12的原始碼目錄
$ patch -p1 -R < ../patch-2.6.13-rc3 # 解除安裝掉2.6.13-rc3補丁
$ patch -p1 < ../patch-2.6.13-rc5 # 應用新的2.6.13-rc5補丁
$ cd ..
$ mv linux-2.6.13-rc3 linux-2.6.13-rc5 # 重新命名原始碼目錄
# 最後讓我們試著從2.6.12.3到2.6.13-rc5
$ cd ~/linux-2.6.12.3 # 切換到核心原始碼目錄
$ patch -p1 -R < ../patch-2.6.12.3 # 回返2.6.12.3補丁
$ patch -p1 < ../patch-2.6.13-rc5 # 應用新的2.6.13-rc5補丁
$ cd ..
$ mv linux-2.6.12.3 linux-2.6.13-rc5 # 重新命名原始碼目錄
-git核心
--------
這些是每天Linus的核心樹的快照(在一個git倉庫中管理著,因此得名)。
這些補丁通常每天都發布而且代表了的Linus的核心樹的當前狀態,由於它們是自動產生的
甚至沒有任何一個游標的騷動來看它們是不是健全的,所以它們比-rc核心更具有試驗性。
-git補丁不是增量的,它們或者是應用在2.6.x核心上或者是應用在一個基礎的
2.6.x-rc核心上---這一點你可以從他們的名字上看出來。一個名字是2.6.12-git1的
補丁應用在2.6.12核心原始碼上,一個名字為2.6.13-rc3-git2的補丁應用在2.6.13-rc3
的核心原始碼上。
file:///D|/applying-patches.txt(第 7/9 頁)2006-8-15 18:22:12
file:///D|/applying-patches.txt
這裡是一些怎樣打這些補丁的例子:
# 從2.6.12遷移到2.6.12-git1
$ cd ~/linux-2.6.12 # 切換到核心原始碼目錄
$ patch -p1 < ../patch-2.6.12-git1 # 應用2.6.12-git1補丁
$ cd ..
$ mv linux-2.6.12 linux-2.6.12-git1 # 重新命名核心原始碼目錄
# 從2.6.12-git1遷移到2.6.13-rc2-git3
$ cd ~/linux-2.6.12-git1 # 切換到核心原始碼目錄
$ patch -p1 -R < ../patch-2.6.12-git1 # 回返2.6.12-git1補丁
# 我們現在有了一個2.6.12核心
$ patch -p1 < ../patch-2.6.13-rc2 # 打上2.6.13-rc2補丁
# 核心現在是2.6.13-rc2
$ patch -p1 < ../patch-2.6.13-rc2-git3 # 打上2.6.13-rc2-git3補丁
# 核心現在是2.6.13-rc2-git3
$ cd ..
$ mv linux-2.6.12-git1 linux-2.6.13-rc2-git3 # 重新命名核心原始碼目錄
-mm核心
-------
這是Andrew Morton釋出的實驗性的核心
-mm樹作為一個新特性和實驗性的補丁的實驗場。一旦一個補丁在-mm中經過一段時間被證明
有價值,為了使它能包含在主流核心中,Andrew就會把它推給Linus。
儘管鼓勵的方法是透過-mm樹把補丁推給Linus,這個步驟並不是總被實行。子系統的維護者
(或者個人)有些時候直接把補丁推給Linus,儘管(或者之後)它們已經被它併到了-mm中並得
到了測試(或者有些時候並沒有事前在-mm中得到測試)。
通常情況下你應該盡力使你的補丁透過-mm中最大程度測試後再到達主流核心中。
這個分支是一個持續的變化並且包含了一些實驗性的特徵,很多正在debug的補丁並不適合於
主流的核心等等。這個分支是這個文件中描述的最具有試驗性的分支。
這些核心核心不適合於應用在要求穩定的系統上面,並且在執行中比其他任何的分支都可能承擔
更大的風險(確信你有最新的備份---這對於任何實驗性的核心都適用,但是對於-mm更是這樣)。
file:///D|/applying-patches.txt(第 8/9 頁)2006-8-15 18:22:12
file:///D|/applying-patches.txt
這些核心除了包含所有的試驗性的補丁以外,它們還包含了在主流-git核心釋出的時候任何
可用的改變。
對-mm核心測試會得到極大的賞識,因為這個分支的總的目的就是為了在改變被加到更加穩定的
主流的Linus核心樹之前,消除退化、當機、資料失敗bug、build失敗(以及任何通常意義上的bug)。
但是-mm的測試者應該清醒地認識到這個原始碼樹中的失敗會比其他任何樹中的都要普遍。
-mm核心並不會以一個固定的時間釋出,但是通常一些-mm核心會在每一個-rc核心(通常1到3個)
釋出的中間。-mm核心或者是應用於一個基礎的2.6.x核心(當還沒有-rc核心釋出的時候)或者應用於
一個Linus -rc的核心。
這裡有一個打-mm補丁的例子
# 從2.6.12到2.6.12-mm1
$ cd ~/linux-2.6.12 # 切換到2.6.12的原始檔目錄
$ patch -p1 < ../2.6.12-mm1 # 打一個2.6.12-mm1的補丁
$ cd ..
$ mv linux-2.6.12 linux-2.6.12-mm1 # 重新正確命名這個原始檔
# 從2.6.12-mm1到2.6.13-rc3-mm3
$ cd ~/linux-2.6.12-mm1
$ patch -p1 -R < ../2.6.12-mm1 # 解除安裝掉2.6.12-mm1補丁
# 現在我們得到了一個2.6.12的原始檔
$ patch -p1 < ../patch-2.6.13-rc3 # 打一個2.6.13-rc3的補丁
# 我們現在得到一個2.6.13-rc3的原始檔
$ patch -p1 < ../2.6.13-rc3-mm3 # 打一個2.6.13-rc3-mm3的補丁
$ cd ..
$ mv linux-2.6.12-mm1 linux-2.6.13-rc3-mm3 # 重新命名原始檔目錄
上面總結了不同核心樹的一些解釋。我希望你已經明白了怎樣打不同的補丁並且對你測
試核心有所幫助。
致謝列表:
Randy Dunlap, Rolf Eike Beer, Linus Torvalds, Bodo Eggert,
Johannes Stezenbach, Grant Coady, Pavel Machek,還有一些人我可能忘記了他們的名字,
但是他們對這篇文件進行了評論或者貢獻。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617542/viewspace-959918/,如需轉載,請註明出處,否則將追究法律責任。

相關文章