扣丁書屋

Android Kernel 源碼環境

前言

工欲善其事 必先利其器。

本篇將會搭建一個完美的Linux Kernel及其內核模塊的源碼閱讀開發環境。

當我們開始研究Android Kernel,想要優雅的閱讀源碼好像是一件費勁的事情。

因為Kernel源碼實在是太龐大了,打開一個c文件,想要詳細的研究研究,甚至上手寫兩句代碼,即沒有高亮提示,也沒有代碼跳轉。在這種情況下,想要理清楚內核源碼,相當不易。

用CLion?貌似不太行。

Kernel的構建體系是make而不是類似于LLVM的CMake。Clion直接打開Kernel源碼是無法被CLion解析的。

用Source Insight?貌似不是非常完美。對于Kernel源碼來說,很多函數symbols一樣,只是適用于不同架構罷了。Source Insight在跳轉的時候,全源引索,并不會幫我們加以區分。諸如此類的問題,Source Insight還有很多...強迫癥患者表示很難受~

用VsCode?貌似更不行?

VsCode對C/C++代碼的高亮提示,依托于C/C++ Extension Pack這個插件,我不清楚別人體驗如何,至少對我來說,這個插件有多爛,我都不想多做評價....

淺談代碼索引

1、為什么IDE集成開發環境可以完美的索引項目代碼?

參考于微軟的一篇文檔(https://learn.microsoft.com/zh-cn/visualstudio/extensibility/language-server-protocol?view=vs-2022#what-is-the-language-server-protocol),我了解到了語言服務器這個東西。

2、什么是語言服務器,有什么作用?

簡單來說,VsCode,VIM等等,都是文本編輯器的性質,可以讓我們愉快的編輯代碼。而clang,gcc等等,都是代碼編譯套件,可以將我們的源碼文件編譯出來。最后clangd,rust-analyzer等等,就屬于語言服務器,就是他們的工作,才使我們的源碼具備了高亮提示和代碼跳轉方面的功能。

其實,各大IDE可以完美的對代碼做解析服務,多半也是內部集成了語言服務器。

CLion對代碼索引的功能 貌似就是通過clangd實現的。

1、如何讓語言服務器運作起來?

我們現在知道了,想要對c語言的代碼做解析,就需要clangd這個語言服務器。那么,如何讓clangd運作起來呢?clangd對代碼做解析,需要compile_commands.json文件。

2、該文件是什么作用?

這個文件記錄著我們對源碼編譯時候的每個命令,用的什么編譯器,提供的什么編譯參數,鏈接了哪些庫,設置了什么宏,編譯的什么源碼文件等等。

如此,clangd就可以通過編譯命令,詳細的了解到整個編譯流程。

3、如何生成該文件?

對于make項目來說,常規來講,可以使用Bear來對源碼生成compile_commands.json文件。

make ## 原編譯命令 --> 不生成compile_commands.json
bear make ## 使用bear --> 生成compile_commands.json

對于CMake項目來說,這個相當簡單。

參考于CMake官方文檔(https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html),只需要設置CMAKE_EXPORT_COMPILE_COMMANDS為True即可在編譯后生成compile_commands.json文件。

set(CMAKE_EXPORT_COMPILE_COMMANDS True)

這里特別提一嘴,對于mk體系編譯的的項目 mk腳本,其本質上是make,但是對于安卓的來說,生成編譯描述文件非常簡單。官方有文檔(https://developer.android.com/ndk/guides/ndk-build#json)提供命令。

ndk-build GEN_COMPILE_COMMANDS_DB=true ## 構建的時候順便生成compile_commands.json

所以,理論上來說,搭建的這套代碼解析方案,不僅僅適用于Kernel源碼閱讀。也適用于各種交叉編譯。

敲定方案

毫無疑問 Kernel的源碼大多是c文件,以及少部分的匯編文件,設備樹文件......

1、明確一點,我們需要clangd支持。

首先看看VsCode有沒有clangd插件,搜了一下,果然有clangd插件(https://github.com/clangd/vscode-clangd)。

2、我們需要對內核編譯的流程,生成描述文件。

這里我找到一個項目,可以把已經完整編譯好了的內核解析出編譯描述文件出來:vscode-linux-kernel(https://github.com/amezin/vscode-linux-kernel)。

如何使用將在下面細說。

Kernel正好是make體系,理論上是可以用Bear的。由于我做教程的時候,已經把內核編譯結束了,實在不想重新編譯內核,理論上選哪個都一樣,我們只是要個編譯描述文件罷。

使用套件最終定型:

VsCode + clangd + 編譯描述文件 + C/C++ Extension Pack

雖然C/C++ Extension Pack相當的爛,但是部分C/C++方面的東西,還需他提供支持。

所以這里依然需要安裝該插件,后續在設置中禁用掉他的代碼提示服務,轉交給clangd插件即可。

關于clangd插件

這個插件會網絡下載clangd的bin文件,很多人可能網絡不佳,會下載失敗。

這里不需要擔心這個,我們只管安裝插件即可,ndk里面自帶的clangd就可以提供語言解析服務了,VsCode設置里面指定clangd路徑即可。

而且,貌似高版本clangd有什么大???

開始動手

1、完整編譯內核

這里以ACK(Android Common Kernel)為例。因為ACK的編譯最簡單,不會出亂七八糟的錯誤,Google基本上完善好了一鍵編譯體系。

參考Google官方文檔(https://source.android.google.cn/docs/setup/build/building-kernels

這里默認讀者會換源或者其他手法保持網絡通暢。

步驟簡述:

① 初始化repo庫。


## 這里選擇common-android12-5.10分支
repo init -u https://android.googlesource.com/kernel/manifest -b common-android12-5.10

② 同步repo庫代碼。



repo sync

漫長的等待...

③ 選擇自己需要的config文件,開啟build.sh腳本。

這里以build.config.gki.aarch64為例。

BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh

④ 等待一段時間后,內核即可編譯完成。

2、生成編譯描述文件

仔細觀察我們編譯的out目錄,會發現有很多后綴為cmd的文件,這些其實就是編譯過程中的臨時文件,包含了編譯命令等。

vscode-linux-kernel其實就是利用編譯后的cmd等文件做解析,生成編譯描述文件compile_commands.json。

步驟簡述:

① 進入內核源碼的根目錄,將vscode-linux-kernel項目拉下來:


cd common # 進入內核源碼根目錄
# clone vscode-linux-kernel項目到.vscode文件夾
# 該文件夾為vscode配置文件夾 類似于.idea
git clone --depth=1 https://github.com/amezin/vscode-linux-kernel.git .vscode

② 運行python腳本,并指定-O參數到編譯產出目錄。

python .vscode/generate_compdb.py -O ../out/android12-5.10/common/
ls -al | grep compile_commands.json
# -rw-r--r--   1 kali kali 8888862 Nov 30 01:07 compile_commands.json

可以看到,源碼目錄下的compile_commands.json文件已經生成。

對于Out-of-tree編譯的內核模塊

詳細見原項目地址的Out-of-tree module development (https://github.com/amezin/vscode-linux-kernel#out-of-tree-module-development)

這一套代碼解析方案也完美的適用于Out-of-tree的內核模塊

3、配置VsCode

對于VsCode來說.vscode目錄下,是一些配置文件。

我們修改原項目的setting.json文件,內容修改成如下:

{
    "files.associations": {
        "iostream": "cpp",
        "intrinsics.h": "c",
        "ostream": "cpp",
        "vector": "cpp"
    },
    "editor.formatOnPaste": true,
    "editor.formatOnSave": true,
    "editor.formatOnType": true,
    // 關閉 C/C++ Extension Pack 插件的提示 防止其與clangd沖突
    "C_Cpp.errorSquiggles": "Disabled",
    "C_Cpp.intelliSenseEngineFallback": "Disabled",
    "C_Cpp.intelliSenseEngine": "Disabled",
    "C_Cpp.autocomplete": "Disabled", // So you don't get autocomplete from both extensions.
    // 指向clangd路徑
    "clangd.path": "/tmp/NDK/ndk-r25b/toolchains/llvm/prebuilt/linux-x86_64/bin/clangd",
    "clangd.arguments": [
        // compelie_commands.json 文件的目錄位置
        "--compile-commands-dir=${workspaceFolder}/",
        // 讓 Clangd 生成更詳細的日志
        "--log=verbose",
        // 輸出的 JSON 文件更美觀
        "--pretty",
        // 全局補全
        "--all-scopes-completion",
        // 建議風格:打包(重載函數只會給出一個建議)相反可以設置為detailed
        "--completion-style=bundled",
        // 跨文件重命名變量
        "--cross-file-rename",
        // 允許補充頭文件
        "--header-insertion=iwyu",
        // 輸入建議中,已包含頭文件的項與還未包含頭文件的項會以圓點加以區分
        "--header-insertion-decorators",
        // 在后臺自動分析文件 基于 complie_commands
        "--background-index",
        // 啟用 Clang-Tidy 以提供「靜態檢查」
        "--clang-tidy",
        // Clang-Tidy 靜態檢查的參數,指出按照哪些規則進行靜態檢查
        // 參數后部分的*表示通配符
        // 在參數前加入-,如-modernize-use-trailing-return-type,將會禁用某一規則
        "--clang-tidy-checks=cppcoreguidelines-*,performance-*,bugprone-*,portability-*,modernize-*,google-*",
        // 默認格式化風格: 谷歌開源項目代碼指南
        "--fallback-style=file",
        // 同時開啟的任務數量
        "-j=2",
        // pch優化的位置(memory 或 disk,選擇memory會增加內存開銷,但會提升性能)
        "--pch-storage=disk",
        // 啟用這項時,補全函數時,將會給參數提供占位符
        // 我選擇禁用
        "--function-arg-placeholders=false"
    ],
}

注釋已經寫到相當清楚,這里不再贅述。

4、打開Kernel根目錄,等待索引結束。

我這里是ssh遠程連接的Linux虛擬機。

打開源碼根目錄后,隨便打開一個c文件,觸發VsCode的插件后,他會提示你,你的默認配置會被.vscode目錄下的setting文件覆蓋,是否確認:

這里當然選擇YES,使用我們配置的setting。

停留在c文件上面,等待一段時間,則會出現如下畫面:

左邊會出現.cache緩存目錄,里面不斷緩存著整個內核源碼的index索引。

左下角有一個indexing,意味著clangd解析整個源碼的進度。

當indexing解析結束后,打開內核源碼的任意c文件,都可以自由的跳轉頭文件,跳轉到函數定義和實現,智能提示函數和結構體等等。就和用IDE寫代碼一樣,非常絲滑舒服。

所有的索引都在一秒不到內可以完成,而且也不會高額占用機器性能。

甚至他還會結合編譯的config,對未開啟的config代碼塊不高亮顯示:

做一些潤滑

你發現會報很多無關痛癢的警告:

1、內核源碼根目錄下,新建一個文件.clangd,內容如下:


CompileFlags:
    Add: [-Wno-declaration-after-, -Wno-int-conversion, -Wno-all]

Diagnostics:
    ClangTidy:
        Remove: bugprone-sizeof-expression

2、Reload Windows后,Warning消失不見。

小技巧:

1、cmd + T 全內核源碼搜索Symbols

2、cmd + Shift + o 當前文件搜索Symbols


https://mp.weixin.qq.com/s/pQO1b0D7mWNG0S5evt8k6Q

最多閱讀

簡化Android的UI開發 3年以前  |  515859次閱讀
Android 深色模式適配原理分析 2年以前  |  27474次閱讀
Android 樣式系統 | 主題背景覆蓋 2年以前  |  8727次閱讀
Android Studio 生成so文件 及調用 2年以前  |  6742次閱讀
30分鐘搭建一個android的私有Maven倉庫 4年以前  |  5508次閱讀
Android設計與開發工作流 3年以前  |  5225次閱讀
移動端常見崩潰指標 2年以前  |  5081次閱讀
Android陰影實現的幾種方案 5月以前  |  5058次閱讀
Google Enjarify:可代替dex2jar的dex反編譯 4年以前  |  5018次閱讀
Android內存異常機制(用戶空間)_NE 2年以前  |  4766次閱讀
Android-模塊化-面向接口編程 2年以前  |  4667次閱讀
Android多渠道打包工具:apptools 4年以前  |  4570次閱讀
Google Java編程風格規范(中文版) 4年以前  |  4423次閱讀
Android死鎖初探 2年以前  |  4391次閱讀

手機掃碼閱讀
18禁止午夜福利体验区,人与动人物xxxx毛片人与狍,色男人窝网站聚色窝
<蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>