Skip to content

Latest commit

 

History

History
162 lines (124 loc) · 6.99 KB

File metadata and controls

162 lines (124 loc) · 6.99 KB

語言: English | 简体中文 | 繁體中文 | 日本語 | 한국어 | Français | Deutsch | Español | Italiano | Русский | العربية

← NeverC 外掛 ABI

Python 外掛

NeverC 可透過原生外掛所使用的同一個 -fplugin= 選項載入 Python 原始檔。一般原始碼建置現在預設啟用 Python 外掛,並在安裝時捆綁執行環境:

cmake -S llvm -B build -C neverc/cmake/caches/NeverC.cmake \
  -DCMAKE_INSTALL_PREFIX="$PWD/neverc-install"
cmake --build build --target install

全新建置預設採用 NEVERC_ENABLE_PYTHON_PLUGINS=ON 與 NEVERC_BUNDLE_PYTHON_RUNTIME=ON。CMake 可使用系統 Python 執行建置腳本, 但該解譯器不會決定外掛 ABI。NeverC 會另外下載經 SHA-256 驗證且版本固定為 CPython 3.12.10 的開發/執行環境,用它編譯並連結外掛橋接層,暫存於 build/python,安裝時再把同一套執行環境放進相鄰的 python/ 目錄。因此一般 原始碼建置與官方封存檔都固定以 CPython 3.12.10 執行外掛;建置樹及安裝後的 編譯器皆不需要外部 Python 執行環境、PYTHONHOME 或 PYTHONPATH。

離線建置時,可用 -DNEVERC_MANAGED_PYTHON_ROOT=/path/to/cpython-3.12.10 指向預先解壓、確切版本為 CPython 3.12.10 且含開發檔案的執行環境。NeverC 會先驗證再複製到建置目錄, 不會修改提供的來源目錄。

Linux 安裝階段要求 PATH 中有 patchelf。由於 CMake 會實際執行 ABI 探針, 目前啟用受管 Python 外掛的建置必須是原生建置;交叉編譯時應關閉 Python 功能, 或另設目標平台的原生封裝階段。若要刻意建置完全不含 Python 的編譯器,請同時傳入 -DNEVERC_ENABLE_PYTHON_PLUGINS=OFF 與 -DNEVERC_BUNDLE_PYTHON_RUNTIME=OFF。

可用 python3 -m pip install ./pluginsdk/python 安裝開發套件,也可將該目錄加入 PYTHONPATH,或建置/安裝 neverc-pluginsdk 元件。NeverC 也會自動尋找 <neverc 所在目錄>/../pluginsdk/python 中已暫存的 SDK。

最小外掛

from neverc_plugin import Plugin


@Plugin(id="com.example.minimal", name="Minimal Python Plugin", version="1.0.0")
class MinimalPlugin:
    def on_process_begin(self, ctx):
        ctx.state = {"sessions": 0}

以檔案系統路徑載入:

neverc -fplugin=/absolute/path/to/minimal.py -fsyntax-only input.c

decorator 接受一個規範外掛 ID、非空白顯示名稱與嚴格語意版本。一個 script 只宣告一個外掛 class。不同 script 是彼此獨立的 module,也可與原生外掛混用。

生命週期

所有 hook 都是選用的:

  • on_process_begin(ctx) 與 on_destroy(ctx) 包住編譯器 process。
  • register(ctx) 在 phase graph 凍結前註冊選項與 observer。
  • on_session_begin(ctx) 與 on_session_end(ctx) 包住一次 invocation。
  • on_task_begin(ctx) 與 on_task_end(ctx) 包住一個編譯工作單元。

begin hook 可回傳 Python 值或指派 ctx.state;配對的 end hook 可讀取該值。 其他 hook 與 observer callback 必須回傳 None。預設採 session-serial 且 不可重入;@Plugin 可選擇與原生外掛相同的模型。

選項與 observer

from neverc_plugin import Plugin
from neverc_plugin.domains import driver


@Plugin(id="com.example.trace", name="Trace", version="1.0.0")
class TracePlugin:
    def register(self, ctx):
        ctx.option(
            "--trace-python",
            kind="flag",
            value_type="bool",
            help="Trace raw driver arguments",
        )
        ctx.observer(
            driver.RAW_ARGUMENTS,
            when=("before", "after"),
            fn=self.observe,
        )

    def observe(self, frame):
        if frame.option_values("--trace-python"):
            frame.check_cancelled()
            frame.emit_remark(f"arguments: {frame.arguments}", code=1001)

neverc_plugin.phases 包含由規範 phase schema 產生的全部 130 個內建 phase 常數。Observer frame 提供 phase 與 route 資料、不透明的輸入/輸出 handle、 已解析的外掛選項值、diagnostic、取消檢查,以及 driver.RAW_ARGUMENTS 的原始 參數。原生 context 與 frame handle 會檢查生命週期:callback 結束後使用保留 物件會引發 RuntimeError。

選項 kind 為 flag、joined、separate、multi_arg;value type 為 bool、int、uint、string、enum、path;multiplicity 為 single、last_wins、append。enum 選項傳入 enum_values={名稱: 整數} mapping。argument_count 僅適用於 multi_arg。

完整 C ABI 存取

高階生命週期、選項與 observer 輔助功能建立在完整的公開 C 外掛 ABI 之上。neverc_plugin.abi 提供產生的 ctypes 定義, neverc_plugin.domains 下的模組會檢查版本與大小後查詢全部官方介面表。 bind_callbacks 透過簽章完全相符的原生 trampoline 連接 Python callback。

from neverc_plugin import abi
from neverc_plugin.domains import ir
from neverc_plugin.ffi import bind_callbacks, require_ok


def register(self, context):
    scope = context.ffi
    core = ir.CORE.query(scope)
    builder = ir.BUILDER.query(scope)
    passes = ir.PASS.query(scope)

Python OLLVM 範例

SDK 在 pluginsdk/python/examples/ollvm 提供一個只使用此公開 binding 撰寫的範例,確定性實作指令替換(SUB)、 偽控制流程(BCF)與控制流程平坦化(FLA):

neverc -fplugin=/path/to/ollvm_plugin.py \
  --ollvm-sub --ollvm-bcf --ollvm-fla \
  --ollvm-seed 42 --ollvm-probability 80 \
  input.c -o output

錯誤、安全性與目前範圍

未捕捉的 Python exception 會轉換成 NEVERC_STATUS_PLUGIN_EXCEPTION。在活動 session/task callback 中,NeverC 會把格式化 traceback 輸出成結構化外掛 diagnostic;import 與 activation 失敗則會在 loader error 中包含 traceback。 嵌入式 interpreter 在 process 範圍共享,NeverC 刻意不 finalize;每個外掛的 物件仍會在 unload 時釋放。

Python 外掛是受信任的編譯器擴充。它們在 process 內執行,可 import 任意 module,並擁有與 NeverC 相同的檔案系統與 process 權限;沒有 sandbox。

Python binding 並不是縮減版 API:自動生成的 ctypes 定義與原生 trampoline 涵蓋全部 36 個官方 C ABI interface table、record、function 與 callback family, 包括 mutation、interceptor 和 provider。lifetime、transaction 與 continuation 都會接受檢查。實作 SUB、BCF 與 FLA 的完整 Python OLLVM 範例位於 pluginsdk/python/examples/ollvm/。 底層定義位於 neverc_plugin.abi,table descriptor 位於 neverc_plugin.domains。