V 编译器 v3 ownership 模式:编译与使用指南

V 编译器 v3 ownership 模式:编译与使用指南

上一篇文章梳理了 v3 的内存管理(scoped bump arena)。这一篇接着写 v3 的另一条主线:ownership checker------它怎么打开,怎么编译出来,怎么用。

一、为什么需要单独编译

v3 的标准二进制把 $if ownership ? 块全部编译裁掉了:

The standard v3 executable is built without -d ownership, so the ownership checker and its analysis stages are compiled out. It rejects both -ownership and -d ownership; the main V driver builds a separate ownership-enabled v3 executable only for an explicit v -ownership invocation.

所以 ./v3 -ownership foo.v 会直接报错:

csharp 复制代码
ownership support is not compiled into this v3 executable

正确做法是:先用主 v 编译出一个独立的 v3_ownership 二进制,再用它去编用户程序。

二、编译 v3_ownership

在仓库根目录执行:

sh 复制代码
./v -gc none -d ownership -o v3_ownership vlib/v3/v3.v

参数含义:

参数 作用
-gc none v3 拒绝任何 GC,必须显式
-d ownership 编译期 $define ownership,让 v3 源码里的所有 $if ownership ? 块全部编入
-o v3_ownership 产物文件名(任意)
vlib/v3/v3.v v3 编译器入口

这条命令正是 cmd/v/v.vlaunch_v3_ownership_compiler() 调用的同一条:

v 复制代码
compilation_command := '${os.quoted_path(vexe)} -gc none -d ownership -o ${os.quoted_path(v3_exe)} ${os.quoted_path(v3_main_source)}'

如果走 v -ownership 驱动,它会自动把编译产物缓存到 $VTMP/v/delegated_v3/<vroot-hash>/v3_ownership,无需手动管理。

产物对比

二进制 大小 说明
v ~6.3 MB 主 v 驱动
v2 / v3 ~5.9 MB 标准 v3(不含 ownership)
v3_ownership ~9.1 MB 带 ownership checker 的 v3

因为 -d ownershiptypes/scope.v 的 scope 路径、types/checker_parallel.v 的 fork 处理、ownership drop 等大块代码都拉进来了,所以 v3_ownership 比标准 v3 大 50%+。

三、v3_ownership 怎么用

虽然叫 v3_ownership,但内部命令名仍是 v3,CLI 跟 v 几乎一样:

sh 复制代码
./v3_ownership [run|test] <file.v|directory> [options]

关键:必须加 -ownership 才会真正启用 ownership 检查。不加就和普通 v3 没区别(checker 已经在二进制里了,但运行时开关没打开)。

基本用法

sh 复制代码
# 编译一个程序(带 ownership 检查)
./v3_ownership -ownership -o my_prog my_prog.v

# 编译并直接跑
./v3_ownership -ownership run my_prog.v

# 跑测试
./v3_ownership -ownership test my_pkg/

# 只生成 C,不链接(看 codegen)
./v3_ownership -ownership -o my_prog.c my_prog.v

通用选项

| 选项 | 说明 |
|------------------------------|----------------|------|----------|----|
| -o <output> | 输出二进制或 .c 文件 |
| `-b <c | arm64 | wasm | eval>` | 后端 |
| -os <name> -arch <name> | 交叉编译目标 |
| -cc <compiler> | C 编译器 |
| -prod -c99 -shared -strict | C 构建模式 |
| -v | 详细阶段计时 |
| -no-memory-limit | 关闭 10 GiB 内存保护 |
| -d <name> | 编译期 define |

四、几个容易踩的坑

1. -ownership-d ownership

  • 编译期 -d ownership :让 v3 自己的 $if ownership ? 块参与编译。这是构建 v3_ownership 那一步要传的参数。
  • 运行时 -ownership :决定这一次编译 是否走 ownership checker,且只在 v3_ownership 这类二进制上才有意义。
  • v3.v 里的注释特意强调运行时 -ownership 不能把 ownership 暴露给目标程序的 $if_d_ownership.v 文件------它只加载 builtin overlays。

vlib/v3/tests/drop_codegen_test.v 里的写法(编目标程序时)就是 -d ownership 裸 define 形式:

v 复制代码
compile := os.execute('${v3_bin} ${src} -d ownership -b c -o ${out}')

-ownership 一样能激活 checker,只是作用层次不同。

2. -ownership 只支持直接编译

cmd/v/v.v 里的 is_ownership_relevant_command() 会拒绝 run / crun

go 复制代码
v: `-ownership` currently supports direct compilation only. Use `v -ownership module_dir`.

如果你想编译完直接跑,得用 ./v3_ownership -ownership run ...(绕过 v 驱动),或者拆成两步。

3. 复杂模块可能触发 codegen bug

我拿 net.http 那个 ip_check.v 试了一下,v3_ownership 编它的时候会在两处 drop 点崩:

rust 复制代码
src.c:31616:21: error: member reference base type 'int' is not a structure or union
                t->cur_size -= (0).size;

这是 ownership pass 在「作用域退出时释放数组」的路径上,把 struct 当成 literal 0 在引用。标准 v3 不会触发,v3_ownership 会------看起来是当前 ownership checker 的一个边界 bug(与 VMemoryBlock / scope drop 相关),不是二进制本身的问题。最小复现一般能稳定出现,建议提 issue。

五、一个跑通的最小例子

/tmp/v3own_demo/main.v

v 复制代码
module main

struct Box {
mut:
	value int
}

fn make_box(v int) &Box {
	return &Box{value: v}
}

fn main() {
	b := make_box(42)
	println('box: ${b.value}')
}
sh 复制代码
$ ./v3_ownership -ownership -o /tmp/v3own_demo/box /tmp/v3own_demo/main.v
$ /tmp/v3own_demo/box
box: 42

ownership pass 跑完生成的 C 代码,在 &Box{...} 离开 make_box 时按 checker 规则正确释放,没有 leak。

六、总结

步骤 命令
1. 编译 v3_ownership(一次性) ./v -gc none -d ownership -o v3_ownership vlib/v3/v3.v
2. 用它编你的模块 ./v3_ownership -ownership -o my_prog my_prog.v
3. (或)走 v 驱动自动维护 v -ownership my_prog_dir/

核心点就两个:

  1. 标准 v3 不带 ownership checker ------必须先用 ./v -gc none -d ownership -o v3_ownership vlib/v3/v3.v 编出专用二进制。
  2. 运行时开关 -ownership 必须显式传------否则二进制就当普通 v3 用。

至于 ownership checker 自己的规则、move semantics、borrow check 的细节,下一篇再展开。

相关推荐
swipe1 小时前
05|(前端转后全栈)不手写一堆 SQL,后端怎么操作数据库?MyBatis-Plus 入门
前端·后端·全栈
霸道流氓气质1 小时前
SpringBoot中使用JasperReports 报表引擎 — 介绍、原理与使用实践
java·spring boot·后端
swipe1 小时前
04|(前端转后全栈)前端状态为什么不够用?从页面数据到 MySQL 持久化
前端·后端·全栈
苏三说技术1 小时前
为什么越来越多人使用WebFlux?
后端
武子康2 小时前
Ask/Allow 不是安全边界:企业 Coding Agent 必须建立四层治理(Policy / Scoped Credential / Sandbox / Provenance)
人工智能·后端·agent
Wang's Blog2 小时前
Go-Zero项目开发17: IM私聊功能实现与消息存储设计
开发语言·后端·golang
她的男孩2 小时前
一行配置,把 Spring Boot 后台变成 AI Agent 的工具箱:Forge MCP Server 插件源码拆解
人工智能·后端
user_lwl2 小时前
Oracle 数据库备份还原工具
后端