1. 程式人生 > 實用技巧 >【技巧】一種提高 [ 定位Linux核心編譯錯誤 ] 效率的方法

【技巧】一種提高 [ 定位Linux核心編譯錯誤 ] 效率的方法

前言:在編譯一些非標準linux核心時,常會出現一些錯誤導致編譯中止。這其中的大部分都能通過根據編譯器報出的錯誤定位來查閱原始碼、找到相關的依賴配置,然後修正配置狀態來解決。但也有時候從依賴邏輯中無法發現問題所在,這就不得不把整個核心配置都倒騰一遍,這將花費大量的時間精力。本文便是在倒騰過程中發現的一些能夠提高效率的小技巧的總結。

關鍵詞:linux,核心編譯,錯誤定位

適用場景:

  • 有一份能夠正常編譯不報錯的配置檔案;
  • 通過查閱原始碼實在找不到造成問題的核心配置項;
  • 能夠確定錯誤是由核心配置引起的,而不是其它諸如環境配置等問題導致的。

(以上條件滿足越多越合適)

1 簡單認識兩個核心原始碼裡的檔案

  1. include/generated/autoconf.h:
    該檔案由.confg檔案轉換而成。在使用make menuconfig修改配置後.config檔案會被修改,但僅僅這樣是無法影響到核心原始碼的。於是在核心編譯的時候會將.config檔案中的配置項轉換為autoconf.h檔案裡對應的巨集定義,如此便可供核心裡的C原始碼使用。

  2. scripts/Kbuild.include:
    該檔案被頂層的Makefile引用,在編譯時會被執行。其中有幾條命令控制著編譯的具體命令,但是命令前加了@符合,導致編譯命令本身被遮蔽,只顯示結果。將@符合去掉,就可以顯示命令本身的內容。
    頂層Makefile對Kbuild.include檔案的引用:

    Kbuild.include檔案:

2 基本思路

  1. 對比正常編譯的autoconf.h和編譯出錯的autoconf.h檔案,找出差異項,將搜尋範圍縮小至差異項;
  2. 參照差異項使用二分法批量修改autoconf.h檔案,可在較少次數內定位到目標配置項;
  3. 去掉Kbuild.include檔案中@set -e前的@,顯示編譯命令的具體內容,由此可獲得導致錯誤的命令;
  4. 直接使用導致錯誤的命令來編譯驗證修改後的配置,可縮短驗證過程的時間。

3 示例

  1. 下圖是一個is deprecated錯誤,在將該錯誤程式碼處相關的幾個檔案來來回回看了幾遍後,依然沒有找出能夠修正錯誤的配置項:

  2. 修改scripts/Kbuild.include檔案,釋放出命令的具體內容:

  3. 再次編譯,可以看到編譯的具體命令了:

  4. 試一下,確實是這條命令報的錯:

  5. 將autoconf.h檔案備份一份,以防後續修改出錯;然後就可以比較編譯正常的autocof.h檔案與當前導致錯誤的autoconf.h檔案:

  6. 總共約2000條配置,左邊是可以正常編譯的,右邊是有問題的:(實際上如果用beyond compare來比較可以只顯示差異行,只需要從1000多條差異項中篩選即可,奈何這裡用的diffuse工具無法只顯示差異項)

  7. 使用二分法篩選,2000條理論上篩選11遍即可找出導致錯誤的配置;實際為了保險起見可能需要把二分法篩選淘汰的那一半也驗證一下,因為要防止導致錯誤的配置項不止一條的情況:
    先使用可正常編譯的配置檔案的前1000項替換有問題的配置檔案的對應配置:

    雖然報了其它錯誤,但沒有報那個is deprecated的錯誤。

  8. 可以判斷錯誤配置項在前1000項裡,還是使用剩餘的後1000多項驗證一下:


    也報了一堆其它錯誤,但同時也出現了之前的錯誤,說明後面的1000多項並不影響這個錯誤,驗證了之前的判斷。

(後面是繁瑣的除錯過程)

  1. 這時範圍縮小到前1000項,再分:
    前512項:

    後半部分:


    前512項沒出現,後半部分出現了,可以再把範圍縮小到前512項。

  2. 前244項:

    後半部分:

    前244項依然出現,後半部分正常,可以判斷在後半部分。

  3. 245-384項:出現目標錯誤

    後半部分(385-512):沒出現

    可以判斷在後半部分。

  4. 385-455:

    456-512:

    兩個都出現錯誤?後來反覆驗證了幾遍確實是這樣。

  5. 在455項和456項之間,有一個配置項左邊能正常編譯的檔案裡沒有,但是右邊的檔案有,所以剛才兩次覆蓋恰好都沒有覆蓋到它,猜測這個可能就是要找的配置項了:

  6. 去掉該配置項:

    編譯正常,沒想到提前解決了。

  7. 直接在make menuconfig裡關閉CONFIG_ENABLE_WARN_DEPRECATED配置項,然後make編譯:


    又報了新的錯誤,但至少那個is deprecated的錯誤是解決了。

最後原因竟然是不能開啟deprecated警告,這就是非標準核心的魅力吧aaaa。
-END-