大型 C 專案的程式碼瀏覽,
不用先編譯
在 VS Code 裡,用 Source Insight 的方式瀏覽程式碼。不用 compile_commands.json。追得到透過巨集和函式指標的呼叫,只看 build 實際會編譯的程式碼。
或 code --install-extension humphrey0925.norn-c · Windows、Linux、macOS · x64 與 Arm64
為什麼用 Norn
以編譯器為基礎的語言伺服器(例如 clangd)需要精確知道每個檔案怎麼編譯。很多實際的 C 專案很難提供這些資訊:用專屬工具鏈建置的韌體、每顆晶片一份標頭檔的 SDK、只能在某台機器上建置的程式碼。ctags、cscope 這類文字索引工具到哪裡都能用,但它們找的是名稱而不是呼叫。Norn 像人一樣直接讀原始碼,有 build 描述檔時也一併讀取。
不用設定
開啟資料夾即可。Norn 會從 Arm DS-5、Keil、IAR、Visual Studio、CMake、Makefile、PlatformIO、Kconfig 或 compile_commands.json 找出 build 的設定,判斷哪些 #if 分支會被編譯。
找的是呼叫,不只是名稱
追得到透過巨集、以及透過存在結構裡的函式指標的呼叫,並標出每個呼叫是怎麼發生的。
快到不用在意
整個 Linux kernel 在一般桌機上大約一分鐘建好索引;存檔後幾毫秒內更新。
和編譯器對照過
在公開專案上,逐一呼叫和 clang 實際編譯的結果比對。
只在本機執行
不連網,不收集任何資料。
| Norn | clangd | ctags / cscope / GNU Global | |
|---|---|---|---|
| 沒有 compilation database 也能用 | ✅ | ⚠️ 準確度較低 | ✅ |
知道 build 會編譯哪些 #if 分支 | ✅ | ✅ 需要 database | ❌ |
| 呼叫圖(呼叫者與被呼叫者) | ✅ | ✅ | ⚠️ cscope,只比對名稱 |
| 透過函式指標的呼叫 | ✅ | ❌ | ❌ |
| 由巨集產生的呼叫 | ✅ | ✅ 需要 database | ❌ |
| 存檔即更新索引 | ✅ | ✅ | ❌ 要重跑 |
| Source Insight 式的檢視(Relation、Context) | ✅ | ❌ | ❌ |
基準測試
在公開專案上量測,標準答案是 clang 對該專案實際 build 的結果。每個工具回報的每個呼叫都和 clang 實際編譯的呼叫對照。clangd 量了兩次:一次給它真實 build 的 compilation database,一次什麼都不給。Norn 什麼都不給。
| 專案 | 檔案數 | Norn | clangd + build database | clangd | cscope |
|---|---|---|---|---|---|
| Redis | 801 | 100.0%0.32 s | 100.0%1.67 s | 95.8%11 s | 96.9%0.26 s |
| git | 919 | 99.9%0.25 s | 99.9%2.40 s | 64.2%32 s | 87.9%0.27 s |
| binutils | 1,622 | 99.6%2.72 s | 92.7%9.72 s | 32.2%16 s | 70.6%1.34 s |
| STM32F4 HAL | 253 | 96.5%0.64 s | 95.0%3.14 s | 0.0%1.14 s | 75.7%0.44 s |
| nrfx | 535 | 98.0%0.84 s | 100.0%1.15 s | 14.1%1.22 s | 12.0%0.28 s |
每格:找到的呼叫比例(和 clang 對照),下方為建立索引的時間。量測方法、所有數字與工具版本見 docs/benchmarks。所有數字都由 bench/compare.py 產生,沒有手打的。
功能
Norn 是完整的語言伺服器:移至定義、尋找參考、呼叫階層、參數提示、重新命名、摺疊、格式化、快速修正都有。和微軟的 C/C++ 擴充套件一起使用時,Norn 會成為 IntelliSense 的 configuration provider,而不是和它重複。
Project Symbols
模糊搜尋所有符號:片段順序不拘、縮寫、依序出現的字母都可以。

Relation
呼叫者、被呼叫者、參考位置、函式指標的指派位置,可用樹狀或關係圖檢視。

附文件的懸停
顯示宣告和文件註解;巨集會一路展開算出值。

Context
在程式碼旁邊顯示游標所在名稱的定義,不用離開目前位置。

自動完成
.、-> 後的成員、區域變數、關鍵字、#include 路徑、所有索引到的名稱。

上色與提示
依名稱種類上色;呼叫處顯示參數名稱。

File Symbols 與區域變數
函式的參數和區域變數,以及每個用到它的行。

編譯條件
從 build 讀取設定組,在 Debug、Release 或各板子的設定之間切換。

開始使用
- 安裝 Norn — Code Navigation & Symbol Index:從 Visual Studio Marketplace,或給 VSCodium、Cursor、Windsurf 用的 Open VSX,或從 releases 下載
.vsix。 - 開啟一個有 C 原始碼的資料夾。這樣就好了。
每個檢視和設定的說明見使用指南。不用 VS Code 時,同一個索引程式也是獨立的指令 norn,可在終端機、腳本、CI 和其他編輯器使用:見命令列手冊。
運作原理
原始碼 ─► tree-sitter 解析 ─► 每個檔案的事實 ─► 連結 ─► 呼叫圖(CSR)─► 語言伺服器
▲ ▲
依 build 自己的設定和原始碼 解析透過巨集與
判斷 #if 函式指標的呼叫
Norn 用 Rust 寫成。每個檔案先判斷前置處理器條件,再解析一次。每個檔案的結果依內容雜湊快取;連結成呼叫圖只要幾毫秒,查一個函式的呼叫者遠不到一微秒。