MCLang CLI - MCLang 项目管理工具
MCLang CLI (mcli) 是 MCLang 工具链的命令行项目管理工具,提供项目创建、构建、依赖管理等功能。
🚀 特性
- 项目创建: 快速创建 MCLang 项目
- 依赖管理: 基于 Conan 的 C++ 依赖管理
- 交叉编译: 以
target为中心安装和使用交叉编译目标 - 模板系统: 内置项目模板和 stub 文件生成
📦 安装
pip install mclang-cli
安装后使用 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 "mclang-cli[mcc]"
安装故障排除
若曾用开发模式安装过 mcc(例如在 mcc 源码目录执行过 pip install -e .),当前环境里可能残留无 RECORD 的 mclang-compiler 安装,导致后续无法正常卸载或升级,并出现 Cannot uninstall mclang-compiler None (no RECORD file)。
建议:
- 先不卸载,直接覆盖安装(推荐):
pip3 install --ignore-installed --no-deps mclang-compiler --break-system-packages
- 若仍异常,可手动删除后再装:用
pip3 show mclang-compiler --break-system-packages查看Location,在该路径的site-packages下删除mclang_compiler*与mcc*相关目录,再执行pip3 install "mclang-cli[mcc]" --break-system-packages。
🔧 使用方法
mcli 项目管理
# 创建新项目
mcli create my-project --template lib
# 构建项目
mcli build
# 构建并运行
mcli run
# 运行测试
mcli test
# 依赖管理(使用 Conan)
conan install . --user=dev
# 发布包
mcli publish --channel stable -bt release
# 安装交叉 target(若已配置 catalog,可省略 --manifest)
mcli target add aarch64-unknown-linux-gnu --manifest ./targets/aarch64-unknown-linux-gnu.toml
# 查看 target
mcli target list
mcli target info aarch64-unknown-linux-gnu
# 按 target 构建/测试
mcli build --target aarch64-unknown-linux-gnu
mcli test --target aarch64-unknown-linux-gnu
# 迁移旧工具链
mcli migrate-toolchains --force
# 配置管理
mcli config
mcli config default_target
mcli config set default_target aarch64-unknown-linux-gnu
项目配置
项目使用 mds/service.json 进行配置:
{
"name": "my-project",
"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"]
}
}
}
依赖 options 与偏好声明
两个字段,职责分明:
| 字段 | 语义 | 对应 conan API |
|---|---|---|
顶层 default_options |
给依赖的 conan options 偏好(影响 package_id 匹配) | self.requires(ref, options={...}) |
dependencies[*].options |
self.requires 的 requires traits |
self.requires(ref, **kwargs)(如 transitive_headers、visible) |
顶层 default_options(推荐的 options 偏好表达方式)
语法与 conan 命令行 -o liblogger/*:test=True 对齐:
"default_options": {
"liblogger/*:test": {"Debug": true, "Release": false},
"libsomp/*:test": {"Debug": true, "Release": false},
"mydep/*:shared": false
}
- key 格式:
<pkg_name>/*:<option_name>或<pkg_name>:<option_name>,与 conan pattern 一致。 - value 支持两种形式:
- 常量(字符串/布尔/数字):不论 build_type,始终生效
- 条件字典
{"Debug": ..., "Release": ...}:按当前build_type挑选值;未覆盖的 build_type 视为未声明,让 conan 用该 option 的默认值(适合"本地 Debug 用 test=True 版依赖、交叉 Release 用 test=False"场景)
mcli 解析后会把这些偏好注入到对应 dependency 的 requires options,最终走 self.requires(ref, options={...}) 路径——所以它们会固化进 recipe,对下游可传递(即中间层封装能力)。
dependencies[*].options(requires traits)
只放 self.requires 的 trait kwargs,跟 conan options 解耦:
{
"conan": "mclboost/[>=0.1.0]",
"options": {
"transitive_headers": true,
"visible": true
}
}
中间层封装(减少顶层维护成本)
若 libA 依赖 libB、libA 又对 libB 有 options 偏好,请把偏好声明在 libA/service.json 的顶层 default_options 里。libA 发布后这份偏好会随 recipe 固化,下游消费 libA 的项目不需要再为 libB 重复声明。mcli 不会因为你的项目间接依赖 libB 而强制你在 service.json 里列出 libB。
依赖顺序的硬约束 ⚠️
conan 深度优先展开依赖图,同一包的 options 只在"被首次 require"时锁定一次(见 conan FAQ)。mcli 严格保持 service.json 里声明顺序生成 CONAN_REQUIRES,不做自动排序,这意味着你需要显式控制顺序:
- 被
default_options偏好覆盖到的依赖(如liblogger),若其他依赖(如libsomp)会间接 require 它,必须把它写在"可能间接引入它的包"之前。这样 conan 先 require 它,偏好才能生效。 - 如果你的项目同时依赖了一个"中间层包"(如
libmcpp,它对liblogger有封装偏好)和一个"直接有 options 的同级包"(如libsoc_adapter),把中间层包放在前面,让它先被 conan 展开,锁定它对传递依赖的偏好。
这些规则 mcli 无法自动推断(mcli 不知道各个依赖包内部会对哪些传递依赖施加偏好),所以由用户在 service.json 中显式保证。
📝 命令参考
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 target 标识 (如 aarch64-unknown-linux-gnu, 用于交叉编译)
-j, --jobs NUM 并行构建任务数
-v, --verbose 详细输出
run - 构建并运行
mcli run [options] [-- <args>]
选项:
--bt, --build-type TYPE 构建类型
--target TARGET 构建 target (如 aarch64-unknown-linux-gnu)
--name TARGET_NAME 要运行的 mclang 可执行目标名称
-- 分隔符,后面传递给程序的参数
示例:
mcli run # 使用上次构建配置运行
mcli run -bt release # 指定构建参数运行
mcli run --target aarch64-unknown-linux-gnu # 先按交叉 target 构建,再运行产物
mcli run -- --arg1 --arg2 # 传递参数给程序
test - 运行测试
mcli test [test_names] [options] [-- <framework-args>]
选项:
--bt, --build-type TYPE 构建类型 (debug/release)
--target TARGET target 标识 (如 aarch64-unknown-linux-gnu)
-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> --manifest ./targets/<target>.toml
mcli target remove <target>
示例:
mcli target add aarch64-unknown-linux-gnu --manifest ./targets/aarch64-unknown-linux-gnu.toml
mcli build --target aarch64-unknown-linux-gnu
mcli test --target aarch64-unknown-linux-gnu
Target Manifest
target 是用户唯一需要理解的交叉编译安装单位。一个 target manifest 描述:
- 该平台使用哪个 compiler
- 该平台使用哪个 sysroot
- 对应的目标 triple / cflags / ldflags
mcli target add aarch64-unknown-linux-gnu --manifest ./targets/aarch64-unknown-linux-gnu.toml
示例 manifest:
[target]
name = "aarch64-unknown-linux-gnu"
platform = "linux-aarch64"
triple = "aarch64-unknown-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 = "aarch64-unknown-linux-gnu"
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。
兼容迁移
旧的 toolchain / compiler / sysroot 机制已经退出主使用路径;如果本机还有历史资产,请用迁移命令一次性转成 target。
mcli migrate-toolchains --force
config - 配置管理
mcli config # 查看所有配置
mcli config <key> # 查看特定配置项
mcli config set <key> <value> # 设置配置项
示例:
mcli config set default_target aarch64-unknown-linux-gnu # 设置默认 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 '*/*:enable_luajit=True')
Conan 包版本格式: {name}/{version}@{user}/{stage}(默认)
或 {name}/{version}(裸发模式)
示例:
mcli publish # 默认 stage=dev → @openubmc.dev/dev:libmcpp/1.2.73@openubmc.dev/dev
mcli publish --stage stable # 显式发到 stable → @openubmc/stable:libmcpp/1.2.73@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 "" # 裸发:libmcpp/1.2.73(不带 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> envMCLI_DEFAULT_STAGE> 内置dev - user:CLI
--user> envMCLI_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/存放项目模板文件
📚 文档
- MCLang CLI 使用指南 - 完整的命令参考和使用说明
🔌 依赖关系
mcli 依赖于以下组件:
- conan: C++ 包管理器(>= 2.0.0)
- meson / ninja: 构建系统支持
可选依赖:
- mclang-compiler (
mccextra): Python -> C++ 编译器,仅 MCLang 项目需要(pip install "mclang-cli[mcc]")
构建系统:mcli 使用 Conan 进行依赖管理和构建,用户可在项目的 conanfile.py 中选择具体的构建工具(CMake、Meson 等)。
🤝 贡献
欢迎提交 Issue 和 Pull Request!
📄 许可证
Mulan PSL v2 - 详见 LICENSE 文件
Metadata
Release files for mclang-cli 0.1.19
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mclang_cli-0.1.19.tar.gz | 189.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mclang_cli-0.1.19-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 422.6 kB
Release files / mclang_cli-0.1.19.tar.gz
| Download URL | mclang_cli-0.1.19.tar.gz |
|---|---|
| Size | 189.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a5b2c9caa99f59484495d3545bd2ebbb05bd60cbdfa127b3b379e8991b2f7b16
|
|
BLAKE2b-256 checksum How to use checksums |
731421826cee126883f9a6d5f344ef21aed07bfc1bdbc1ed45e077e57206da74
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.1
|
Release files / mclang_cli-0.1.19-py3-none-any.whl
| Download URL | mclang_cli-0.1.19-py3-none-any.whl |
|---|---|
| Size | 232.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0f675b63311258923cd2202f0307c8635f93b1751c73e6d824e4a4a110001355
|
|
BLAKE2b-256 checksum How to use checksums |
7a3f4f04cdb93e2f468b3f13853230a0875e78a9db0261317c322d94593648b5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.1
|