moonkconfig

    Portable Kconfig core: typed dependency resolution, boolean choices and reproducible build configuration

    kconfig
    configuration
    tristate
    build
    Download zip
    Author
    Version
    0.3.0
    License
    Apache-2.0
    Last updated
    14 days ago
    Downloads
    44

    No dependencies

    #MoonKconfig

    MoonBit 编写的可嵌入构建配置引擎,版本 0.3.0,模块 CYang-dep/moonkconfig,Apache-2.0。

    语言实现终点固定为 Linux v6.12 Kconfig 完整语言符合性,参考提交 adc218676eef25575469234709c2d87185ca223a,包括预处理、跨文件同名声明合并及最终配置求值。0.3.0 提供独立的 parse_linux612 路径,保留原有可移植配置 API。符合性目标、证据映射和宿主职责见 符合性说明。有限测试是可复验的工程证据,不是对所有输入的形式证明或赛事审核结论。

    #使用场景

    • 固件工具将内存源树和板级配置交给统一求值器,输出 .config 和 C 头文件。见 固件示例。
    • 产品构建合并基础配置与型号覆盖,审计冲突、最终值变化,并生成可重放片段。见 变体示例。
    • 配置界面复用提示、帮助、来源、可见性、范围和请求探测。见 UI 示例。
    • Kconfig 集成使用固定版本语言路径处理重复声明、宏、依赖、choice 和兼容配置导入。见 Linux v6.12 示例。

    #安装与环境

    安装官方 MoonBit 工具链,在宿主模块执行:

    moon add CYang-dep/moonkconfig@0.3.0

    本地基线 moon 0.1.20261016 / moonc v0.10.16+b1a0e846e。四个目标为 wasm-gc、wasm、js、native;原生目标需要 C 编译器。CI 记录实际 stable 版本,并分别执行严格检查、测试、构建、六个示例及独立差分。运行库仅依赖官方 core;Python、Kconfiglib、Linux C 工具仅为外部开发验证依赖。

    #快速开始

    在宿主的 moon.pkg 导入:

    import {
    "CYang-dep/moonkconfig" @config,
    }

    pkgtype(kind: "executable")

    main.mbt:

    ///|
    fn main {
    try {
    let schema = @config.parse_kconfig("config ENABLE\n bool \"Enable\"\n default y\nconfig DEPTH\n int \"Depth\"\n range 1 32\n default 8")
    let requests = schema.parse_config("CONFIG_DEPTH=16")
    let result = schema.resolve(requests)
    assert_eq(result.value("ENABLE"), @config.Logic(@config.Y))
    assert_eq(result.value("DEPTH"), @config.Number(16L))
    println(schema.export_config(result))
    println(schema.export_header(result))
    } catch {
    _ => abort("configuration failed")
    }
    }

    moon run . --target js

    克隆源码后可直接运行三个完整工作流:

    moon run examples/firmware --target js moon run examples/variants --target js moon run examples/ui --target js

    #Linux v6.12 路径

    parse_linux612(entry, files, preprocessor~) 使用明确传入的源树;files 是路径到文本的 Map。环境快照、Shell 回调和消息回调经 Preprocessor 显式注入,库本身不读取环境、不运行进程。完整用例见 examples/linux612。

    let schema = @config.parse_linux612("Kconfig", files)
    let (requests, diagnostics) = schema.read_linux_config("CONFIG_RIGHT=y")
    ignore(diagnostics)
    let result = schema.resolve(requests)
    println(schema.export_linux_config(result))

    领域固定版本语义
    声明bool/tristate/string/int/hex,menu/menuconfig/if/comment/help,重复声明按遍历顺序合并并保留每个来源
    表达式与值三态逻辑、字符串词典序、带符号/无符号比较、保留数值原始文本与基数
    预处理=、:=、+=,参数函数、嵌套展开、标准内建函数、文件/行号和显式环境/Shell 适配
    源树固定版本的字面 source 路径、循环诊断、条件继承;完整输入由宿主提供
    求值首个有效 default、depends on、select、imply、modules、匿名 bool choice、首个活动 range
    配置宽松读取及诊断、重复有效赋值后写覆盖,最终配置的赋值省略与数值拼写

    v6.12 的 choice 为匿名 bool,不支持命名、tristate、optional choice;source 不展开 glob。旧可移植 API 的这些扩展不混入固定版本路径。Value::RawNumber(String, Kind) 保留 Linux 数值文本;使用枚举穷举匹配的下游需要适配新分支。

    跨文件 SHARED 在 LEFT 条件下默认 11,在 RIGHT 条件下默认 22:

    LEFTRIGHT显式 SHARED最终值最终导出
    nn无0省略 SHARED
    yn无11CONFIG_SHARED=11
    ny无22CONFIG_SHARED=22
    yy无11CONFIG_SHARED=11
    ny3737CONFIG_SHARED=37

    运行 moon run examples/linux612 --target js 可检查全部五组及两个源位置;同样输入经固定原生 conf 独立对照。

    #可移植 API

    parse_kconfig、parse_sources 及 Schema::new 保留原有构建配置行为;parse_config 严格拒绝未知、重复或非法赋值,export_config 输出完整快照。固定版本路径使用 read_linux_config 和 export_linux_config。二者的差异是公开 API 契约,不能混用完整快照与原生省略规则。

    merge_fragments 保留最后覆盖顺序,overlay_conflicts 报告覆盖,changes 比较最终值。minimal_fragment 实际重放求值,inspect 和 request_options 提供独立元数据副本。详情见 架构 和生成的 .mbti。

    #验证与复现

    moon info moon fmt --check moon check --deny-warn --target js moon test --deny-warn --target js moon build --deny-warn --target js python -m pip install kconfiglib==14.1.0 python tools/differential.py --target js python tools/check_declarations.py --target js python tools/audit.py

    常驻测试 59 个;原有 Kconfiglib 14.1.0 合成对照 113 场景、1361 断言。固定 Linux v6.12 原生 conf 对照 328 项,包括接受/拒绝输入、预处理消息、配置值和最终赋值集合、上游语言夹具,以及 7 个真实组件的 28 组配置。工具在测试前检查外部文件的 Git blob 摘要;不把自身输出当参考答案。

    原生工具复现(Linux,已安装 cc、bison、flex、Python):

    git clone --filter=blob:none --no-checkout https://github.com/torvalds/linux _oracle/linux git -C _oracle/linux checkout adc218676eef25575469234709c2d87185ca223a python tools/build_linux612.py --source _oracle/linux --output _oracle/build python tools/linux612.py --source _oracle/linux --conf _oracle/build/conf --target js --report _oracle/report-js.json

    四后端工作流 在每个提交重新构建外部 oracle 并保存逐项 JSON 证据;请核对对应提交的 CI,不能用旧发行的绿灯代替。tools/linux612-pins.json 固定来源及实际输入;tools/linux612.py 可在 Windows 通过 --wsl Ubuntu 调用外部 conf。

    #限制与宿主职责

    • 目标是固定版本的语言与最终配置语义;不交付 Linux 构建系统或终端菜单应用。.config 对照比较赋值内容和省略,不复制原生生成标题、菜单注释、排版与诊断的完整呈现格式。
    • 宿主需显式提供完整源树、环境、Shell 结果与资源策略。测试包含真实叶组件与合成宿主符号,没有宣称完成整个内核配置树或内核编译。
    • 资源有界:4096 符号、表达式 256 tokens / 128 层 / 4096 节点、source 深度 32、scope 深度 64、展开预算 16 Mi UTF-16 单元 / 65536 行、依赖边 65536;精简及交互探测限 256 符号。超限报错,这些预算不是安全认证。
    • 有限差分不能穷尽语言输入。发现目标版本的语义差异应作为实现缺陷修复,不能改成永久非目标;当前测试映射与实际证据见符合性说明。

    #许可、参考与 AI 使用

    原创实现采用 Apache-2.0。固定 Linux v6.12 的 GPL-2.0 源码与夹具由开发工具下载到外部目录,单独编译和运行,未随库发布、不参与运行时链接。Kconfiglib 14.1.0(ISC)仅为开发 oracle。来源、摘要和边界见 NOTICE。

    项目使用 AI 辅助进行实现、测试与文档编写,结论来自实际执行。有限生态检查见 公开查重记录。

    ConfigError

    pub suberror ConfigError {
    Invalid(String)
    } derive(
    Debug
    )

    ConfigError::to_repr

    #deprecated("`ConfigError::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn ConfigError::to_repr(ConfigError) ->
    Repr

    ConfigChange

    pub(all) struct ConfigChange {
    name : String
    before : Value
    after : Value
    } derive(Eq,
    Debug
    )

    ConfigChange::equal

    #deprecated("`ConfigChange::equal` is deprecated, use `Eq::equal` instead.")
    fn ConfigChange::equal(ConfigChange, ConfigChange) -> Bool

    ConfigChange::not_equal

    #deprecated("`ConfigChange::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn ConfigChange::not_equal(x : ConfigChange, y : ConfigChange) -> Bool

    ConfigChange::to_repr

    #deprecated("`ConfigChange::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn ConfigChange::to_repr(ConfigChange) ->
    Repr

    Expr

    pub(all) enum Expr {
    Constant(Value)
    NumericLiteral(String, Int64)
    SymbolRef(String)
    Negation(Expr)
    Conjunction(Expr, Expr)
    Disjunction(Expr, Expr)
    Comparison(String, Expr, Expr)
    } derive(Eq,
    Debug
    )

    Expr::equal

    #deprecated("`Expr::equal` is deprecated, use `Eq::equal` instead.")
    fn Expr::equal(Expr, Expr) -> Bool

    Expr::evaluate

    fn Expr::evaluate(self : Expr, values : Map[String, Value], linux612? : Bool) -> Value

    Expr::not_equal

    #deprecated("`Expr::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn Expr::not_equal(x : Expr, y : Expr) -> Bool

    Expr::references

    fn Expr::references(self : Expr) -> Array[String]

    Expr::to_repr

    #deprecated("`Expr::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn Expr::to_repr(Expr) ->
    Repr

    Fragment

    pub struct Fragment {
    // private fields
    }

    Validated user requests; the resolver may constrain them by visibility.

    Fragment::new

    fn Fragment::new() -> Fragment

    Fragment::values

    fn Fragment::values(self : Fragment) -> Map[String, Value]

    Kind

    pub(all) enum Kind {
    Boolean
    Tristate
    StringType
    Integer
    Hex
    } derive(Eq,
    Debug
    )

    Kind::accepts

    fn Kind::accepts(self : Kind, value : Value) -> Bool

    Kind::equal

    #deprecated("`Kind::equal` is deprecated, use `Eq::equal` instead.")
    fn Kind::equal(Kind, Kind) -> Bool

    Kind::initial

    fn Kind::initial(self : Kind) -> Value

    Kind::not_equal

    #deprecated("`Kind::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn Kind::not_equal(x : Kind, y : Kind) -> Bool

    Kind::to_repr

    #deprecated("`Kind::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn Kind::to_repr(Kind) ->
    Repr

    OverlayConflict

    pub(all) struct OverlayConflict {
    name : String
    previous : Value
    replacement : Value
    fragment_index : Int
    } derive(Eq,
    Debug
    )

    OverlayConflict::equal

    #deprecated("`OverlayConflict::equal` is deprecated, use `Eq::equal` instead.")
    fn OverlayConflict::equal(OverlayConflict, OverlayConflict) -> Bool

    OverlayConflict::not_equal

    #deprecated("`OverlayConflict::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn OverlayConflict::not_equal(x : OverlayConflict, y : OverlayConflict) -> Bool

    OverlayConflict::to_repr

    #deprecated("`OverlayConflict::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn OverlayConflict::to_repr(OverlayConflict) ->
    Repr

    Preprocessor

    pub struct Preprocessor {
    // private fields
    }

    A per-parse macro context. Host effects are explicit callbacks; environment is a snapshot, never the process-global environment. Return stdout from shell.

    Preprocessor::new

    fn Preprocessor::new(environment? : Map[String, String], shell? : (String) -> String raise ConfigError, message? : (String, String) -> Unit) -> Preprocessor

    Resolution

    pub struct Resolution {
    // private fields
    }

    Immutable-by-interface resolution snapshot detached from user input.

    Resolution::diagnostics

    fn Resolution::diagnostics(self : Resolution) -> Array[String]

    Resolution::reason

    fn Resolution::reason(self : Resolution, name : String) -> String raise ConfigError

    Resolution::value

    fn Resolution::value(self : Resolution, name : String) -> Value raise ConfigError

    Resolution::values

    fn Resolution::values(self : Resolution) -> Map[String, Value]

    Resolution::visibility

    fn Resolution::visibility(self : Resolution, name : String) -> Tri raise ConfigError

    Schema

    pub struct Schema {
    // private fields
    }

    Opaque schema; callers cannot mutate internal dependency structures.

    Schema::add

    fn Schema::add(self : Schema, name : String, kind : Kind, prompt? : String) -> Unit raise ConfigError

    Schema::changes

    fn Schema::changes(self : Schema, before : Resolution, after : Resolution) -> Array[ConfigChange] raise ConfigError

    Schema::choice_help

    fn Schema::choice_help(self : Schema, name : String) -> String raise ConfigError

    Help attached to a choice, addressed by its name or generated choice_N name.

    Schema::choice_members

    fn Schema::choice_members(self : Schema, name : String) -> Array[String] raise ConfigError

    Schema::choice_names

    fn Schema::choice_names(self : Schema) -> Array[String]

    Schema::default_value

    fn Schema::default_value(self : Schema, name : String, value : Expr, condition? : Expr) -> Unit raise ConfigError

    Schema::dependency

    fn Schema::dependency(self : Schema, name : String, expr : Expr) -> Unit raise ConfigError

    Schema::dependency_order

    fn Schema::dependency_order(self : Schema) -> Array[String] raise ConfigError

    Stable dependency-first ordering. Iterative DFS reports an actual cycle path.

    Schema::export_config

    fn Schema::export_config(self : Schema, result : Resolution) -> String raise ConfigError

    Deterministic complete value export in declaration order, with no host I/O.

    Schema::export_fragment

    fn Schema::export_fragment(self : Schema, fragment : Fragment) -> String raise ConfigError

    Schema::export_header

    fn Schema::export_header(self : Schema, result : Resolution) -> String raise ConfigError

    C preprocessor header; module values use CONFIG_NAME_MODULE, not CONFIG_NAME.

    Schema::export_linux_config

    fn Schema::export_linux_config(self : Schema, result : Resolution) -> String raise ConfigError

    Linux v6.12 .config assignments, with native omission rules. Menu captions and generated-file comments are intentionally presentation of the host UI.

    Schema::help

    fn Schema::help(self : Schema, name : String) -> String raise ConfigError

    Schema::inspect

    fn Schema::inspect(self : Schema, result : Resolution) -> Array[SymbolView] raise ConfigError

    UI-facing copies; changing returned arrays cannot mutate the schema.

    Schema::kind

    fn Schema::kind(self : Schema, name : String) -> Kind raise ConfigError

    Schema::minimal_fragment

    fn Schema::minimal_fragment(self : Schema, target : Resolution) -> Fragment raise ConfigError

    Greedy irredundant fragment, not a globally minimum cardinality solution. Limited to 256 symbols because each candidate requires a full resolution.

    Schema::names

    fn Schema::names(self : Schema) -> Array[String]

    Schema::new

    fn Schema::new(linux612? : Bool) -> Schema

    Schema::parse_config

    fn Schema::parse_config(self : Schema, text : String) -> Fragment raise ConfigError

    Strict .config reader: unknown symbols and duplicates are actionable errors.

    Schema::prompt

    fn Schema::prompt(self : Schema, name : String) -> (String?, Expr) raise ConfigError

    Schema::read_linux_config

    fn Schema::read_linux_config(self : Schema, text : String) -> (Fragment, Array[String]) raise ConfigError

    Linux olddefconfig import: unknown, malformed and invalid assignments are ignored; later valid assignments override earlier ones. Diagnostics are returned separately so applications can choose to treat them as errors.

    Schema::request

    fn Schema::request(self : Schema, requests : Fragment, name : String, value : Value) -> Unit raise ConfigError

    Schema::request_options

    fn Schema::request_options(self : Schema, fragment : Fragment, name : String) -> Array[Value] raise ConfigError

    Values achievable by making this the last explicit request. This is an executable transition query, not a claim to reproduce menuconfig widgets.

    Schema::resolve

    fn Schema::resolve(self : Schema, fragment : Fragment) -> Resolution raise ConfigError

    Resolve to a bounded fixed point; requests never override hidden prompts.

    Schema::reverse_dependency

    fn Schema::reverse_dependency(self : Schema, source : String, target : String, weak? : Bool, condition? : Expr) -> Unit raise ConfigError

    Schema::source_location

    fn Schema::source_location(self : Schema, name : String) -> String raise ConfigError

    Schema::source_locations

    fn Schema::source_locations(self : Schema, name : String) -> Array[String] raise ConfigError

    All declaration locations, in source traversal order. Builder symbols have the single location "builder"; callers receive a fresh array.

    Schema::validate

    fn Schema::validate(self : Schema) -> Unit raise ConfigError

    SymbolView

    pub(all) struct SymbolView {
    name : String
    kind : Kind
    value : Value
    prompt : String?
    help : String
    visibility : Tri
    reason : String
    location : String
    dependencies : Array[String]
    numeric_range : (Int64, Int64)?
    } derive(Eq,
    Debug
    )

    SymbolView::equal

    #deprecated("`SymbolView::equal` is deprecated, use `Eq::equal` instead.")
    fn SymbolView::equal(SymbolView, SymbolView) -> Bool

    SymbolView::not_equal

    #deprecated("`SymbolView::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn SymbolView::not_equal(x : SymbolView, y : SymbolView) -> Bool

    SymbolView::to_repr

    #deprecated("`SymbolView::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn SymbolView::to_repr(SymbolView) ->
    Repr

    Token

    pub(all) struct Token {
    text : String
    quoted : Bool
    offset : Int
    } derive(Eq,
    Debug
    )

    Tokens keep the original UTF-16 offset for diagnostics.

    Token::equal

    #deprecated("`Token::equal` is deprecated, use `Eq::equal` instead.")
    fn Token::equal(Token, Token) -> Bool

    Token::not_equal

    #deprecated("`Token::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn Token::not_equal(x : Token, y : Token) -> Bool

    Token::to_repr

    #deprecated("`Token::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn Token::to_repr(Token) ->
    Repr

    Tri

    pub(all) enum Tri {
    N
    M
    Y
    } derive(Eq,
    Debug
    )

    The ordered Kconfig lattice: n < m < y.

    Tri::equal

    #deprecated("`Tri::equal` is deprecated, use `Eq::equal` instead.")
    fn Tri::equal(Tri, Tri) -> Bool

    Tri::join

    fn Tri::join(self : Tri, other : Tri) -> Tri

    Tri::meet

    fn Tri::meet(self : Tri, other : Tri) -> Tri

    Tri::negate

    fn Tri::negate(self : Tri) -> Tri

    Tri::not_equal

    #deprecated("`Tri::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn Tri::not_equal(x : Tri, y : Tri) -> Bool

    Tri::rank

    fn Tri::rank(self : Tri) -> Int

    Tri::text

    fn Tri::text(self : Tri) -> String

    Tri::to_repr

    #deprecated("`Tri::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn Tri::to_repr(Tri) ->
    Repr

    Value

    pub(all) enum Value {
    Unset
    Logic(Tri)
    Text(String)
    Number(Int64)
    RawNumber(String, Kind)
    } derive(Eq,
    Debug
    )

    Value::equal

    #deprecated("`Value::equal` is deprecated, use `Eq::equal` instead.")
    fn Value::equal(Value, Value) -> Bool

    Value::logic

    fn Value::logic(self : Value) -> Tri

    Value::not_equal

    #deprecated("`Value::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn Value::not_equal(x : Value, y : Value) -> Bool

    Value::text

    fn Value::text(self : Value) -> String

    Value::to_repr

    #deprecated("`Value::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn Value::to_repr(Value) ->
    Repr

    identifier

    fn identifier(text : String) -> Bool

    merge_fragments

    fn merge_fragments(fragments : Array[Fragment]) -> Fragment

    Rightmost fragment wins. Returned fragments never alias input arrays.

    overlay_conflicts

    fn overlay_conflicts(fragments : Array[Fragment]) -> Array[OverlayConflict]

    Report only value-changing overrides, preserving input order.

    parse_conditional

    fn parse_conditional(text : String) -> (Expr, Expr) raise ConfigError

    Parse a value/condition pair as used by default and reverse dependencies.

    parse_expression

    fn parse_expression(text : String) -> Expr raise ConfigError

    parse_kconfig

    fn parse_kconfig(text : String, preprocessor? : Preprocessor) -> Schema raise ConfigError

    Parse the portable core; unsupported directives are errors, not ignored.

    parse_linux612

    fn parse_linux612(entry : String, sources : Map[String, String], preprocessor? : Preprocessor) -> Schema raise ConfigError

    Linux v6.12 language profile. Files and host preprocessor callbacks remain explicit; the library does not execute commands or read ambient files.

    parse_number

    fn parse_number(text : String) -> Int64 raise ConfigError

    Checked signed decimal/hex input without host-dependent conversions.

    parse_sources

    fn parse_sources(entry : String, sources : Map[String, String], preprocessor? : Preprocessor, linux612? : Bool) -> Schema raise ConfigError

    Resolve explicit in-memory source files; never reads disk, shell or environment.

    parse_tri

    fn parse_tri(text : String) -> Tri raise ConfigError

    quote_string

    fn quote_string(text : String) -> String raise ConfigError

    Escape strings in .config, prompts and generated C string constants.

    tokenize

    fn tokenize(text : String) -> Array[Token] raise ConfigError

    Lex one logical line. Limits prevent accidentally loading unbounded inputs.