rack 是 RGC 的包管理器,用 RGC 自己编写。它管理 RGC 项目的完整生命周期:新建项目、安装依赖(含传递依赖解析与完整性校验)、锁文件、构建与运行、发布与搜索。

这篇教程从一个真实的示例包出发,带你走一遍完整流程:发布 → 新建项目 → 安装依赖 → 查看依赖树 → 构建运行 → 发布自己的包。所有命令都在仓库中验证过,可以直接复制运行。

1. 准备

rack 二进制在仓库 rack/target/bin/rack(已构建)。也可以自行构建:

cd rack && ./tests/bootstrap.sh
# -> target/bin/rack

rack 构建项目时需要调用 rgc 编译器,通过 RGC 环境变量指定:

export RGC=/path/to/RGLite/build/rgc

验证:

rack --version
# rack 0.3.0 (RGC)

2. 发布示例包到本地注册表

rack 使用本地注册表(默认 $HOME/.rack/registry)。先把仓库里两个示例包发布进去:

cd rack/examples/mathx
rack publish

cd ../calcx
rack publish

输出:

Published [email protected] -> $HOME/.rack/registry
Published [email protected] -> $HOME/.rack/registry
  • mathx 是一个数学工具模块,提供 add / mul / fib / square_sum;
  • calcx 依赖 [email protected],提供 double_add / fib_sq。

3. 新建项目

rack new demo && cd demo

生成:

demo/
├── .gitignore   # 忽略 target/ 与 a.out
├── main.rg      # 项目入口
└── rack.toml   # 清单

默认 main.rg:

# demo — rack 项目入口

def main() {
    print("hello from demo")
}

rack.toml 记录包元数据:

[package]
name = "demo"
version = "0.1.0"
entry = "main.rg"

4. 安装依赖

把 main.rg 改成使用 calcx:

import calcx

def main() -> int {
    print(double_add(2, 3))
    return 0
}

安装:

rack install calcx

输出:

  resolved calcx -> [email protected]
  + [email protected]
  + [email protected]
  Installed 2 package(s)

rack 自动完成传递依赖解析:calcx 依赖 mathx,所以 mathx 一起被安装。

5. 查看依赖树

rack tree
[email protected]
└── [email protected]
    └── [email protected]

6. 构建并运行

rack run
built: ./target/bin/demo
10

此时项目布局:

demo/
  rack.toml       # 清单(rack 维护,手改亦可)
  rack.lock       # 锁文件:依赖闭包
  main.rg         # 入口
  target/
    deps/         # 已安装依赖模块 .rg(缓存,可随时重建)
    build/        # 构建暂存区(入口 + 全部依赖,每次构建前清空)
    bin/demo      # 构建产物

7. 锁文件 rack.lock

install 会把解析后的完整依赖闭包写入 rack.lock(rack 维护、随项目入库,勿手改):

# rack.lock — 依赖闭包锁文件(rack 维护,勿手改;随项目入库)

[lock.calcx]
version = "0.1.0"
checksum = "130f4c9b…"
dependencies = ["mathx"]

[lock.mathx]
version = "0.2.0"
checksum = "b1dfcea6…"
dependencies = []
  • version:解析后的精确版本;
  • checksum:publish 时记录的模块文件 sha256,install 时先校验再拷贝,build 前也会校验 target/deps 缓存是否被篡改;
  • dependencies:该包的直接依赖(用于依赖剪枝与完整性校验)。

8. 常用命令

命令 作用
rack new 新建项目骨架(rack.toml + main.rg + .gitignore)
rack init [name] 在当前目录初始化 rack 项目
rack install [@] 安装依赖及其全部传递依赖,写入清单与锁文件
rack update 把全部直接依赖重解析到最新版,重写锁文件
rack remove 移除依赖,并按依赖边剪掉孤儿传递依赖
rack build 校验锁文件 → 暂存依赖到 target/build → 调用 rgc 编译
rack run [-- ...] 构建并运行,参数原样转发给程序
rack tree 打印依赖树
rack list 显示清单与依赖安装状态
rack clean 清除 target/build 与 target/bin(保留 target/deps 缓存)
rack publish 把 .rg 与 rack.toml 发布到本地注册表
rack search [关键字] 在注册表中按包名搜索,显示最新版与描述
rack registry 显示本地注册表路径

运行参数透传

rack run -- <参数> 会把参数原样交给程序,程序用内建 args() 读取(含程序名,行为同 Python 的 sys.argv):

rack run -- hello world
def main() -> int {
    argv = args()
    print("argc =", argv.len())
    for a in argv {
        print("arg:", a)
    }
    return 0
}

9. 依赖解析:版本冲突与环检测

rack 对依赖闭包做完整性保证:

  • 版本冲突:同一包被两个依赖 pin 到不同精确版本时,直接报错拒装:
error: version conflict on `common`: pinned 1.0.0, but `beta` requires 2.0.0
  • 依赖环:A -> B -> A 这样的循环依赖会被检测并拒绝:
error: dependency cycle: cycleA -> cycleB -> cycleA

这两种情况都发生在 install 的解析阶段,不会把半成品写进清单或锁文件。

10. 发布自己的包

发布一个包只需要两个文件:模块代码 .rg 和清单 rack.toml。

mypkg.rg:

public def add(a: int, b: int) -> int {
    return a + b
}

rack.toml:

[package]
name = "mypkg"
version = "0.1.0"
entry = "mypkg.rg"

发布并搜索验证:

cd mypkg
rack publish
rack search mypkg

在另一个项目里安装使用:

rack new usemypkg && cd usemypkg
# 修改 main.rg:import mypkg ...
rack install mypkg
rack run

11. 构建钩子与链接参数

有些项目需要在编译前做原生预处理,或链接额外的库。rack.toml 支持 [build] 段:

[build]
prebuild = "bash tools/llvm-shim.sh"        # 编译前执行(cwd = 项目根目录)
link-args-file = "target/build/link-args"    # 文件内容作为 rgc --link-args

RGC 编译器项目本身就是一个 rack 项目(src/rack.toml):prebuild 负责编译内嵌 LLVM 的后端 shim,link-args-file 把 shim 与 LLVM 静态库的链接参数传给 rgc。

12. 下一步

rack 以 Apache 2.0 协议开源。欢迎在 GitHub 提 Issue、贡献代码。