Skip to main content

mcli - C/C++ 项目与包工作流工具

mcli 是面向多 target 的 C/C++ 项目、依赖、构建、测试和发布工作流工具。 它基于 Conan 管理包与构建环境,具体构建系统可以是 Meson、CMake 或其他 Conan recipe 支持的工具。MCLang 是可选的源码前端:需要时由 mcc 将 Python 方言生成 C++,再进入相同构建流程。

🚀 特性

  • 项目创建: 从内置或第三方模板创建项目
  • 依赖管理: 基于 Conan 的 C++ 依赖管理
  • 交叉编译: 以 target 为中心安装和使用交叉编译目标
  • 模板系统: 内置项目模板和 stub 文件生成

📦 安装

pip install mcli-build

安装后使用 mcli 命令:

mcli --version

或从源码安装:

git clone https://gitcode.com/zjp99/mcli.git
cd mcli
pip install -e . --force-reinstall --no-deps

# 安装到全局环境
pip install -e . --break-system-packages --force-reinstall --no-deps

可选依赖:mcli 是通用构建工具,不强制绑定 MCLang 编译器。仅当项目需要将 Python 编译为 C++ 时,才需要安装 mcc:

pip install "mcli-build[mcc]"

安装故障排除

若曾用开发模式安装过 mcc(例如在 mcc 源码目录执行过 pip install -e .),当前环境里可能残留无 RECORD 的 mclang-compiler 安装,导致后续无法正常卸载或升级,并出现 Cannot uninstall mclang-compiler None (no RECORD file)。

建议:

  1. 先不卸载,直接覆盖安装(推荐):
    pip3 install --ignore-installed --no-deps mclang-compiler --break-system-packages
    
  2. 若仍异常,可手动删除后再装:用 pip3 show mclang-compiler --break-system-packages 查看 Location,在该路径的 site-packages 下删除 mclang_compiler* 与 mcc* 相关目录,再执行 pip3 install "mcli-build[mcc]" --break-system-packages。

从 mclang-cli 0.1.x 迁移

mcli-build 使用 ~/.mcli 保存 target、compiler、sysroot、toolchain 和全局配置。 升级后执行一次:

mcli migrate home --dry-run
mcli migrate home
mcli target list

迁移采用同文件系统内的目录重命名,不会复制大型 target;过渡期会保留 ~/.mclang -> ~/.mcli 兼容链接。MCLANG_HOME 和 MCLANG_CONAN 等旧环境变量 仍可读取,新配置应使用 MCLI_HOME 和 MCLI_CONAN。

🔧 使用方法

mcli 项目管理

# 创建新项目
mcli create sample-core --template lib

# 构建项目
mcli build

# 构建并运行
mcli run

# 运行测试
mcli test

# 依赖管理(使用 Conan)
conan install . --user=dev

# 发布包
mcli publish --channel stable -bt release

# 安装交叉 target
# target 表示产物运行的平台;宿主机和交叉编译器由 mcli 自动处理
mcli target add linux-arm64

# 查看 target
mcli target list
mcli target info linux-arm64

# 按 target 构建/测试
mcli build --target linux-arm64
mcli test --target linux-arm64

# 迁移旧工具链
mcli migrate-toolchains --force

# 配置管理
mcli config
mcli config default_target
mcli config set default_target linux-arm64

mcli 在首次执行构建、测试或发布等 Conan 工作流时,会自动注册 mclang_public 公共只读仓库,并以匿名方式访问。如果相同 URL 已经以 mclang 等旧名称存在,mcli 会直接复用;用户如需认证访问,可按 Conan 标准命令自行登录,mcli 不会覆盖已有凭据。

项目配置

mcli.toml 是 mcli 的项目级配置文件,用于声明包信息、依赖、workspace、默认 target 和 target/profile 构建选项。完整字段见 mcli.toml 配置参考,多子项目仓库见 Workspace 与子项目。mds.* 显式引用和依赖 provider 已可用; mds/service.json 继续兼容旧项目:

{
    "name": "sample-core",
    "version": "1.0.0",
    "type": "library",
    "author": "Your Name",
    "license": "Mulan PSL v2",
    "description": "Project description",
    "dependencies": {
        "build": [
            {"conan": "boost/[>=1.87.0]"}
        ]
    },
    "mclang": {
        "type": "native",
        "stubs": {
            "dir": "stubs",
            "packages": ["mc", "gtest"]
        }
    }
}

编译能力声明

原生依赖或项目可以在 mclang.compile_capabilities 中声明当前 target 的 布尔编译事实:

{
    "name": "renderer",
    "version": "1.2.0",
    "mclang": {
        "compile_capabilities": {
            "renderer.vulkan": {
                "value": true,
                "description": "Vulkan renderer is present"
            }
        }
    }
}

每项必须同时提供布尔 value 和非空 description;capability 名称、owner 和配置来源会进入 mcc 的 schema 与生成缓存身份。需要按 target 改变取值时,在 已有 targets 覆盖中提供完整的 mclang.compile_capabilities 映射。

发布包会在 res/mclang/compile-capabilities.json 保存构建该二进制时使用的 完整、带指纹配置。下游构建合并所有依赖清单;target 不一致、清单损坏、同名定义 不一致或同名值冲突都会在 mcc 建立模块依赖图之前失败,不按依赖加载顺序覆盖。

依赖 options 与偏好声明

跨 target/profile 的包选项推荐写在项目根目录的 mcli.toml,例如 [target.hi1711.options]。命令行 -o 可作最高优先级的临时覆盖;provider 声明的 兼容约束除外,命令行给出不同值时会直接报冲突。 完整格式与 hi1711 示例见 mcli.toml 配置参考。

普通依赖写在 mcli.toml 的 [dependencies],测试依赖写在 [test-dependencies]。只要 mcli.toml 存在,最终配置结构就完全由 TOML 描述, 不会回退或隐式合并 service.json。需要复用既有配置时,可以用 mds.version、 mds.dependencies.build.<package> 等只读引用逐项取值;只有没有 mcli.toml 的 旧项目才进入完整的 service 兼容模式。

Workspace 成员自动提供自己的包名、版本和本地路径;其他成员通过 { workspace = true } 声明对它的依赖,无需在根目录重复登记 ref + path。 需要版本约束时可在消费成员中直接写正式 Conan ref,mcli 会校验并优先使用 同名本地成员。[workspace.dependencies] 用于集中维护共享的外部依赖, 其中的定义也只有被成员显式选择时才进入依赖图。

[options] 及 profile/target 下的 options 表示 Conan 包 options; 依赖展开写法中的 traits 表示 self.requires() 的依赖特性, 例如 transitive_headers 和 visible。两者不是同一类配置:

[options]
"sample-core/*:shared" = true

[dependencies]
sample-core = { ref = "sample-core/[>=1.0.0]@example/stable", traits = { transitive_headers = true, visible = true } }

同一项逻辑依赖需要在不同 target 选择不同实现时,可以在 [providers] 中声明 多个实现,再通过 { provider = "..." } 显式选择。Provider 会解析成真实 Conan 运行时依赖、构建工具依赖和兼容 options,并参与导出 recipe、package ID、构建 指纹和 lockfile;它不是只在 mcli 本地生效的链接替换。完整规则见 mcli.toml 配置参考。

📝 命令参考

create - 创建项目

mcli create <project-name> [options]

选项:
  -t, --template TYPE  项目模板 (bin/lib, 默认: bin)
  --list              列出所有可用模板

build - 构建项目

mcli build [options]

选项:
  --bt, --build-type TYPE  构建类型 (debug/release, 默认: debug)
  --target TARGET        目标平台 (如 linux-arm64,用于交叉编译)
  -j, --jobs NUM          并行构建任务数
  -v, --verbose           详细输出

run - 构建并运行

mcli run [options] [-- <args>]

选项:
  --bt, --build-type TYPE  构建类型
  --target TARGET         构建 target (如 linux-arm64)
  --name TARGET_NAME      要运行的可执行产物名称
  --                      分隔符,后面传递给程序的参数

示例:
  mcli run                               # 使用上次构建配置运行
  mcli run -bt release                      # 指定构建参数运行
  mcli run --target linux-arm64    # 先按交叉 target 构建,再运行产物
  mcli run -- --arg1 --arg2              # 传递参数给程序

test - 运行测试

mcli test [test_names] [options] [-- <framework-args>]

选项:
  --bt, --build-type TYPE  构建类型 (debug/release)
  --target TARGET        目标平台 (如 linux-arm64)
  -j, --jobs NUM          并行构建任务数
  -v, --verbose           mcli 详细输出(CTest -V)
  --                      分隔符,后面传递给测试框架的参数

使用 -- 分隔符:
  -- 之前:mcli 参数(测试名称用于 CTest -R 筛选)
  -- 之后:直接转发给测试框架(绕过 argparse 识别)

示例:
  mcli test                                  # 运行所有测试
  mcli test mcc_gtests                      # 运行指定测试
  mcli test mcc_gtests mcc_pytests          # 运行多个测试
  mcli test mcc_pytests -- test_lambda.py   # 转发参数给测试框架
  mcli test mcc_pytests -- -v               # pytest 详细输出
  mcli test mcc_gtests -- --gtest_filter=*Arc*  # GoogleTest filter
  mcli test -v mcc_pytests -- -v            # mcli 和 pytest 都详细输出

依赖管理

# 刷新依赖(更新 stub 文件)
mcli reload

# 刷新稳定版本依赖
mcli reload --channel stable -bt release

# 使用 Conan 安装依赖
conan install . --user=dev

# 查看已安装的包
conan list

target - Target 管理

mcli target list
mcli target info <target>
mcli target add <target>
mcli target remove <target>

示例:
  mcli target add linux-arm64
  mcli build --target linux-arm64
  mcli test --target linux-arm64

Target Manifest

target 是用户唯一需要理解的交叉编译安装单位。一个 target manifest 描述:

  • 该平台使用哪个 compiler
  • 该平台使用哪个 sysroot
  • 对应的目标 triple / cflags / ldflags

官方 linux-arm64 预设生成的程序直接使用 hi1711 的系统运行库:解释器路径为 /lib64/ld-linux-aarch64.so.1,C++ 使用旧版 libstdc++ dual ABI。部署时无需复制 target 自带的 libstdc++.so.6 或 libgcc_s.so.1,也没有额外兼容层。

mcli target add linux-arm64

示例 manifest:

[target]
name = "linux-arm64/gcc9"
aliases = ["linux-arm64"]
platform = "linux-aarch64"
triple = "aarch64-linux-gnu"

[target.compiler]
name = "bmc-sdk-compiler"
source = "./artifacts/bmc-sdk-compiler.tar.gz"
type = "gcc"
tool_prefix = "aarch64-target-linux-gnu"

[target.sysroot]
name = "bmc-sdk-sysroot"
source = "./artifacts/bmc-sdk-sysroot.tar.gz"

只配不带(用户自行安装编译器)

当编译器已通过系统包管理器安装时,manifest 可以声明版本约束而不打包编译器:

[target]
name = "linux-arm64/local-hcc"
aliases = ["linux-arm64"]
cflags = ["-Os", "-ffunction-sections"]
ldflags = ["-Wl,--gc-sections"]

[target.compiler]
type = "gcc"
source = "system"
tool_prefix = "hcc-arm64le"
min_version = "7.0"
max_version = "8.0"

mcli 会从 PATH 中查找 hcc-arm64le-g++,校验版本是否满足约束(7.0 <= version < 8.0),版本不满足时输出警告。

若组织内已配置 catalog,mcli target add <target> 可直接省略 --manifest。mcli 也内置了 openUBMC hi1711 等常见 target 模板(位于 targets/),支持自动检测 SDK 布局(/opt/ 或 ~/)和变量替换,mcli target add hi1711 一键完成导入。

兼容迁移

旧的 toolchain / compiler / sysroot 机制已经退出主使用路径;如果本机还有历史资产,请用迁移命令一次性转成 target。

mcli migrate-toolchains --force

config - 配置管理

mcli config                        # 查看所有配置
mcli config <key>                  # 查看特定配置项
mcli config set <key> <value>      # 设置配置项

示例:
  mcli target default linux-arm64  # 设置默认 target
  mcli config default_target                    # 查看默认 target

publish - 发布包

mcli publish [options]

选项:
  --user USER              Conan 包所有者;不指定时按 stage 联动推导默认值
                           (stage=dev → openubmc.dev,其他 → openubmc),
                           可被环境变量 MCLI_DEFAULT_USER 整体覆盖;
                           传空串 (--user "") 表示「裸发,不带 user/channel」
  --stage STAGE            发布阶段 (dev/rc/stable);与 bingo 的 --stage 对齐;
                           不指定时取 mcli 默认(dev,可被环境变量
                           MCLI_DEFAULT_STAGE 覆盖)
  --channel CHANNEL        --stage 的别名;二者不可同时指定
  --bt, --build-type TYPE  构建类型 (debug/release)
  -r, --remote REMOTE      上传到指定远端仓库(不指定则只导出到本地缓存)
  --force                  强制覆盖远端已存在的包
  -o KEY=VALUE             透传 conan -o 选项,build/export-pkg 阶段都生效
                           (依赖项请用 pkg/*:opt 形式,例如 -o 'sample-runtime/*:enable_feature=True')

Conan 包版本格式: {name}/{version}@{user}/{stage}(默认)
                  或 {name}/{version}(裸发模式)

示例:
  mcli publish                                  # 默认 stage=dev → @openubmc.dev/dev:sample-core/1.0.0@openubmc.dev/dev
  mcli publish --stage stable                   # 显式发到 stable → @openubmc/stable:sample-core/1.0.0@openubmc/stable
  mcli publish --stage rc                       # 发到 rc → @openubmc/rc
  mcli publish -r openubmc_sdk                  # 默认 dev,并上传到指定远端
  mcli publish --user openubmc --stage dev      # 显式覆盖:发到 @openubmc/dev(绕过 stage 联动)
  mcli publish --user myorg --stage dev         # 命令行同时覆盖 user 和 stage
  mcli publish --user ""                        # 裸发:sample-core/1.0.0(不带 user/channel)

  # 通过环境变量定制团队默认(写到 ~/.zshrc 或 CI 脚本里):
  export MCLI_DEFAULT_USER=myteam               # 整体覆盖默认 user(绕过 stage 联动)
  export MCLI_DEFAULT_STAGE=rc                  # 默认 stage 改成 rc

设计原则:项目代码不绑死「会被发到哪里」 + 默认 user 跟 stage 联动

user/channel 都是发布行为的属性,不是项目代码的属性。所以 service.json 里不再支持 publish.user 这类配置 —— 否则一个项目的源码 仓库会硬编码 conan 仓库归属,团队 fork、镜像私服、个人实验都得改源码。

默认 user 与 stage 联动(CLI / env 都未指定时):

stage 默认 user 含义
dev openubmc.dev 本地/开发机构建,与 bingo conan create --user openubmc.dev 约定对齐,bingo 集成测试可直接 cache-hit mcli 发布的 binary
rc / stable / 其他 openubmc 远端 CI 出的正式产物归属

mcli 解析这两类元信息:

元信息 解析顺序
user CLI --user > env MCLI_DEFAULT_USER > 按 stage 推导
stage / channel CLI --stage/--channel > env MCLI_DEFAULT_STAGE > 内置 dev
  • 日常 mcli publish(不带任何参数)→ @openubmc.dev/dev,跟 bingo 本地构建包同 ref,集成测试直接命中
  • 想让远端 stable 仓库(依赖写的是 @openubmc/stable)拿到本机改动时, 显式 mcli publish --stage stable(自动用 @openubmc/stable,不带 .dev 后缀)
  • 别的团队默认 user 不是 openubmc:export MCLI_DEFAULT_USER=myteam 整体覆盖联动逻辑

解析优先级(统一两层 + stage 联动)

  • stage/channel:CLI --stage/--channel > env MCLI_DEFAULT_STAGE > 内置 dev
  • user:CLI --user > env MCLI_DEFAULT_USER > 按 stage 推导 (stage=dev → openubmc.dev,其他 → openubmc)
  • 命令行同时给出 --stage 和 --channel → 报错(避免歧义)
  • CLI --user "" → 裸发模式(不带 user/channel),仅本地纯实验用

🏗️ 架构

mcli/
├── mcli/                  # CLI 工具核心
│   ├── commands/          # 命令实现
│   │   ├── create.py      # 项目创建
│   │   ├── build.py       # 构建管理
│   │   ├── deps.py        # 依赖管理
│   │   └── publish.py     # 包发布
│   ├── toolchain/         # 工具链管理(内部模块)
│   │   ├── base.py        # 工具链基类
│   │   ├── zig.py         # Zig 工具链
│   │   ├── system.py      # 系统工具链 (GCC/Clang)
│   │   └── manager.py     # 工具链管理器
│   ├── package/           # 包管理(内部模块)
│   │   ├── manager.py     # 包管理器
│   │   ├── conan.py       # Conan 集成
│   │   └── abi.py         # ABI 管理
│   ├── target/            # target 模型(主入口)
│   ├── template.py        # 模板引擎(内置,支持 {{ }} 和 {% %} 语法)
│   ├── paths.py           # 路径工具
│   ├── logging.py         # 日志系统
│   └── config.py          # 配置管理
└── templates/             # 项目模板
    ├── conanbase.py.mct   # Conan 基类模板(自动生成到用户项目)
    ├── bin/               # 可执行程序模板
    ├── lib/               # 库项目模板
    └── toolchain/         # 工具链配置模板

设计说明:

  • mcli/ 包含 CLI 的所有核心代码
  • template.py 是内置的模板引擎,支持 {{ }} 和 {% %} 语法
  • target/ 是交叉编译主入口;toolchain/ 退回为内部兼容层
  • templates/conanbase.py.mct 是 Conan 基类模板,mcli build 时自动生成到用户项目目录
  • 用户项目的 conanfile.py 通过 from conanbase import ConanBase 导入生成的基类
  • templates/ 存放项目模板文件

📚 文档

🔌 依赖关系

mcli 依赖于以下组件:

  • conan: C++ 包管理器(>= 2.0.0)
  • meson / ninja: 构建系统支持

可选依赖:

  • mclang-compiler (mcc extra): Python -> C++ 编译器,仅 MCLang 项目需要(pip install "mcli-build[mcc]")

构建系统:mcli 使用 Conan 进行依赖管理和构建,用户可在项目的 conanfile.py 中选择具体的构建工具(CMake、Meson 等)。

🤝 贡献

欢迎提交 Issue 和 Pull Request!

📄 许可证

Mulan PSL v2 - 详见 LICENSE 文件

Metadata

Release files for mcli-build 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mcli-build 0.3.0
File Size Uploaded
mcli_build-0.3.0.tar.gz 292.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mcli-build 0.3.0
File Interpreter ABI Platform
mcli_build-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 564.9 kB

Release files / mcli_build-0.3.0.tar.gz

Download URL mcli_build-0.3.0.tar.gz
Size 292.0 kB
Tags Source
SHA-256 checksum
How to use checksums
b79f8f2f47126f72b5cf0b179c36663484e9053d880064a598a957c3830c289e
BLAKE2b-256 checksum
How to use checksums
6e65f2cfe8210e5dc98ab2c18df85a52b87988ad8792552b1eebd81a32dae353
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / mcli_build-0.3.0-py3-none-any.whl

Download URL mcli_build-0.3.0-py3-none-any.whl
Size 272.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2235d58f4fd72ad9c254d46eba21914ad9c684491dbe4cffe151a5779e9e4789
BLAKE2b-256 checksum
How to use checksums
45d8fc97c6893ff9fdc71183bd1551097d5a026c63ec28c6570021cbaaad094b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page