Norn

大型 C 專案的程式碼瀏覽,
不用先編譯

在 VS Code 裡,用 Source Insight 的方式瀏覽程式碼。不用 compile_commands.json。追得到透過巨集和函式指標的呼叫,只看 build 實際會編譯的程式碼。

或 code --install-extension humphrey0925.norn-c · Windows、Linux、macOS · x64 與 Arm64

VS Code 裡的 Norn:編輯器周圍的 Project Symbols、File Symbols、Relation 和 Context

為什麼用 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 實際編譯的結果比對。

只在本機執行

不連網,不收集任何資料。

Nornclangdctags / cscope / GNU Global
沒有 compilation database 也能用✅⚠️ 準確度較低✅
知道 build 會編譯哪些 #if 分支✅✅ 需要 database❌
呼叫圖(呼叫者與被呼叫者)✅✅⚠️ cscope,只比對名稱
透過函式指標的呼叫✅❌❌
由巨集產生的呼叫✅✅ 需要 database❌
存檔即更新索引✅✅❌ 要重跑
Source Insight 式的檢視(Relation、Context)✅❌❌

基準測試

在公開專案上量測,標準答案是 clang 對該專案實際 build 的結果。每個工具回報的每個呼叫都和 clang 實際編譯的呼叫對照。clangd 量了兩次:一次給它真實 build 的 compilation database,一次什麼都不給。Norn 什麼都不給。

各專案、各工具找到的呼叫比例
各專案、各工具建立索引的時間
專案檔案數Nornclangd + build databaseclangdcscope
Redis801100.0%0.32 s100.0%1.67 s95.8%11 s96.9%0.26 s
git91999.9%0.25 s99.9%2.40 s64.2%32 s87.9%0.27 s
binutils1,62299.6%2.72 s92.7%9.72 s32.2%16 s70.6%1.34 s
STM32F4 HAL25396.5%0.64 s95.0%3.14 s0.0%1.14 s75.7%0.44 s
nrfx53598.0%0.84 s100.0%1.15 s14.1%1.22 s12.0%0.28 s

每格:找到的呼叫比例(和 clang 對照),下方為建立索引的時間。量測方法、所有數字與工具版本見 docs/benchmarks。所有數字都由 bench/compare.py 產生,沒有手打的。

功能

Norn 是完整的語言伺服器:移至定義、尋找參考、呼叫階層、參數提示、重新命名、摺疊、格式化、快速修正都有。和微軟的 C/C++ 擴充套件一起使用時,Norn 會成為 IntelliSense 的 configuration provider,而不是和它重複。

Project Symbols

模糊搜尋所有符號:片段順序不拘、縮寫、依序出現的字母都可以。

Project Symbols

Relation

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

以關係圖顯示的 Relation

附文件的懸停

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

懸停

Context

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

Relation 與 Context

自動完成

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

成員補全

上色與提示

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

語意上色與參數名稱提示

File Symbols 與區域變數

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

File Symbols 與區域變數

編譯條件

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

切換設定組

開始使用

  1. 安裝 Norn — Code Navigation & Symbol Index:從 Visual Studio Marketplace,或給 VSCodium、Cursor、Windsurf 用的 Open VSX,或從 releases 下載 .vsix。
  2. 開啟一個有 C 原始碼的資料夾。這樣就好了。

每個檢視和設定的說明見使用指南。不用 VS Code 時,同一個索引程式也是獨立的指令 norn,可在終端機、腳本、CI 和其他編輯器使用:見命令列手冊。

運作原理

原始碼 ─► tree-sitter 解析 ─► 每個檔案的事實 ─► 連結 ─► 呼叫圖(CSR)─► 語言伺服器
             ▲                                  ▲
   依 build 自己的設定和原始碼               解析透過巨集與
   判斷 #if                                 函式指標的呼叫

Norn 用 Rust 寫成。每個檔案先判斷前置處理器條件,再解析一次。每個檔案的結果依內容雜湊快取;連結成呼叫圖只要幾毫秒,查一個函式的呼叫者遠不到一微秒。