Metadata-Version: 2.4
Name: mclang-cli
Version: 0.1.18
Summary: MCLang CLI - MCLang 项目管理工具
Home-page: https://gitcode.com/zjp99/mcli
Author: MCLang Development Team
Author-email: MCLang Development Team <mclang@openubmc.com>
Maintainer-email: MCLang Development Team <mclang@openubmc.com>
License: Mulan PSL v2
Project-URL: Homepage, https://gitcode.com/openubmc/mcli
Project-URL: Documentation, https://gitcode.com/openubmc/mcli
Project-URL: Repository, https://gitcode.com/openubmc/mcli
Project-URL: Issues, https://gitcode.com/openubmc/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: meson>=1.0
Requires-Dist: ninja>=1.10
Requires-Dist: conan>=2.0.0
Requires-Dist: mclang-compiler<0.4.0,>=0.3.7
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: psutil>=5.8.0; extra == "dev"
Dynamic: author
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-python

# MCLang CLI - MCLang 项目管理工具

MCLang CLI (mcli) 是 MCLang 工具链的命令行项目管理工具，提供项目创建、构建、依赖管理等功能。

## 🚀 特性

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

## 📦 安装

```bash
pip install mclang-cli
```

安装后使用 `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
```

**注意**: 安装 mclang-cli 会自动安装 mclang-compiler 作为依赖。

### 安装故障排除

若曾用**开发模式**安装过 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 mclang-cli --break-system-packages`。

全新环境仅执行 `pip install mclang-cli` 时，会自动从 PyPI 安装带完整元数据的 mclang-compiler，一般不会出现上述问题。

## 🔧 使用方法

### mcli 项目管理

```bash
# 创建新项目
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` 进行配置：

```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` 对齐：

```json
"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 解耦：

```json
{
    "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](https://docs.conan.io/2/knowledge/faq.html#defining-options-for-dependencies-in-conanfile-py-recipes-doesn-t-work)）。mcli 严格保持 `service.json` 里声明顺序生成 `CONAN_REQUIRES`，不做自动排序，这意味着你需要显式控制顺序：

- 被 `default_options` 偏好覆盖到的依赖（如 `liblogger`），若其他依赖（如 `libsomp`）会间接 require 它，必须把它写在"可能间接引入它的包"之前。这样 conan 先 require 它，偏好才能生效。
- 如果你的项目同时依赖了一个"中间层包"（如 `libmcpp`，它对 `liblogger` 有封装偏好）和一个"直接有 options 的同级包"（如 `libsoc_adapter`），把中间层包放在前面，让它先被 conan 展开，锁定它对传递依赖的偏好。

这些规则 mcli 无法自动推断（mcli 不知道各个依赖包内部会对哪些传递依赖施加偏好），所以由用户在 service.json 中显式保证。

## 📝 命令参考

### 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        target 标识 (如 aarch64-unknown-linux-gnu, 用于交叉编译)
  -j, --jobs NUM          并行构建任务数
  -v, --verbose           详细输出
```

### run - 构建并运行

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

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

### 依赖管理

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

```bash
mcli target add aarch64-unknown-linux-gnu --manifest ./targets/aarch64-unknown-linux-gnu.toml
```

示例 manifest：

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

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

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

### config - 配置管理

```bash
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 - 发布包

```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 '*/*: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` > 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/` 存放项目模板文件

## 📚 文档

- [MCLang CLI 使用指南](docs/mcli_guide.md) - 完整的命令参考和使用说明

## 🔌 依赖关系

mcli 依赖于以下组件：

- **mclang-compiler**: 编译器核心（自动安装）
- **conan**: C++ 包管理器（>= 2.0.0）

**构建系统**：mcli 使用 Conan 进行依赖管理和构建，用户可在项目的 `conanfile.py` 中选择具体的构建工具（CMake、Meson 等）。

## 🤝 贡献

欢迎提交 Issue 和 Pull Request！

## 📄 许可证

Mulan PSL v2 - 详见 [LICENSE](LICENSE) 文件
