Metadata-Version: 2.1
Name: mcli-build
Version: 0.3.0
Summary: Target-aware C/C++ project and package workflow tool
Home-page: https://gitcode.com/zjp99/mcli
Author: mcli Development Team
Author-email: mcli Development Team <mclang@openubmc.com>
Maintainer-email: mcli Development Team <mclang@openubmc.com>
License: Mulan PSL v2
Project-URL: Homepage, https://gitcode.com/zjp99/mcli
Project-URL: Documentation, https://gitcode.com/zjp99/mcli
Project-URL: Repository, https://gitcode.com/zjp99/mcli
Project-URL: Issues, https://gitcode.com/zjp99/mcli/issues
Keywords: compiler,code-generator,python,cpp,transpiler,build-tools,project-management
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Code Generators
Classifier: Topic :: Software Development :: Compilers
Classifier: Topic :: Software Development :: Build Tools
Classifier: License :: OSI Approved
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: C++
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: conan >=2.0.0
Requires-Dist: meson >=1.0
Requires-Dist: ninja >=1.10
Requires-Dist: packaging >=23.0
Requires-Dist: pkgconf >=2.1
Provides-Extra: dev
Requires-Dist: psutil >=5.8.0 ; extra == 'dev'
Requires-Dist: pytest >=7.0.0 ; extra == 'dev'
Provides-Extra: mcc
Requires-Dist: mclang-compiler <0.4.0,>=0.3.7 ; extra == 'mcc'

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

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

## 🚀 特性

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

## 📦 安装

```bash
pip install mcli-build
```

安装后使用 `mcli` 命令：

```bash
mcli --version
```

或从源码安装：

```bash
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`：

```bash
pip install "mcli-build[mcc]"
```

### 安装故障排除

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

**建议**：

1. **先不卸载，直接覆盖安装**（推荐）：
   ```bash
   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 和全局配置。
升级后执行一次：

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

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

## 🔧 使用方法

### mcli 项目管理

```bash
# 创建新项目
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 配置参考](docs/build-configuration.md)，多子项目仓库见
[Workspace 与子项目](docs/workspaces.md)。`mds.*` 显式引用和依赖 provider 已可用；
`mds/service.json` 继续兼容旧项目：

```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 的
布尔编译事实：

```json
{
    "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 配置参考](docs/build-configuration.md)。

普通依赖写在 `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`。两者不是同一类配置：

```toml
[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 配置参考](docs/build-configuration.md)。

## 📝 命令参考

### create - 创建项目

```bash
mcli create <project-name> [options]

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

### build - 构建项目

```bash
mcli build [options]

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

### run - 构建并运行

```bash
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 - 运行测试

```bash
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 都详细输出
```

### 依赖管理

```bash
# 刷新依赖（更新 stub 文件）
mcli reload

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

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

# 查看已安装的包
conan list
```

### target - Target 管理

```bash
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`，也没有额外兼容层。

```bash
mcli target add linux-arm64
```

示例 manifest：

```toml
[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 可以声明版本约束而不打包编译器：

```toml
[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。

```bash
mcli migrate-toolchains --force
```

### config - 配置管理

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

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

### publish - 发布包

```bash
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 使用指南](docs/mcli_guide.md) - 完整的命令参考和使用说明
- [本地项目联调](docs/local-links.md) - 使用 `mcli link` 跨仓库增量开发

## 🔌 依赖关系

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](LICENSE) 文件
