订阅以接收新文章的通知:

在 Cloudflare Workers 上使用 WASI 运行 Zig

2022-08-01

2 分钟阅读时间
这篇博文也有 English繁體中文版本。

在阅读最近关于 Workers 中的 WASI 支持的公告之后,我决定探索一下,怎样才能让 Zig 中编写的代码作为 Worker 运行,结果发现毫不费力就能做到。本文记录了我作为 Zig 的新用户所采用的过程。我惊奇地发现,Cloudflare Workers 是一个多语言平台,可以采用自己喜欢的语言或者正在学习的语言来编写程序!

Running Zig with WASI on Cloudflare Workers

你好,世界!

我绝非 Zig 专家,实不相瞒,我刚刚开始学习这门语言,但我们总归要迈出第一步。所以,如果我的 Zig 代码有疏漏之处,请多包涵。我的目标是使用 Zig 构建一个真实的小程序,并将其部署到 Cloudflare Workers 上。然后看看我从一片空白开始,到写出富有成效的代码,需要多长时间。

我的目标谈不上宏伟,就只是从 stdin 读取一些文本,然后打印到 stdout 并加上行号,就像运行 cat -n 那样。但这确实表明 Workers 范式非常简单。这个 Zig 程序在笔记本电脑的命令行上以及作为部署到 Cloudflare Workers 上的 HTTP API 时采用完全相同的方式运行。

我编写的代码如下。它从 stdin 读取一行,将其原封不动地输出,只是加上了行号前缀。没有更多输入时,程序终止。

要构建 Zig 代码,就需要创建一个 build.zig 文件来定义如何构建项目。就这个小案例而言,我选择从源文件构建可执行文件

const std = @import("std");

pub fn main() anyerror!void {
	// setup allocator
	var gpa = std.heap.GeneralPurposeAllocator(.{}){};
	defer std.debug.assert(!gpa.deinit());
	const allocator = gpa.allocator();

	// setup streams
	const stdout = std.io.getStdOut().writer();
	const in = std.io.getStdIn();
	var reader = std.io.bufferedReader(in.reader()).reader();

	var counter: u32 = 1;

	// read input line by line
	while (try reader.readUntilDelimiterOrEofAlloc(allocator, '\n', std.math.maxInt(usize))) |line| {
    	    defer allocator.free(line);
    	    try stdout.print("{d}\t{s}\n", .{counter, line});
    	    counter = counter + 1;
	}
}

通过运行 zig build,编译器将运行并在 zig-out/bin 下输出二进制文件

const std = @import("std");

pub fn build(b: *std.build.Builder) void {
	const target = b.standardTargetOptions(.{});
	const mode = b.standardReleaseOptions();

	const exe = b.addExecutable("print-with-line-numbers", "src/main.zig");
	exe.setTarget(target);
	exe.setBuildMode(mode);
	exe.install();
}

WASI

$ zig build

$ ls zig-out/bin
print-with-line-numbers

$ echo "Hello\nWorld" | ./zig-out/bin/print-with-line-numbers
1    Hello
2    World

下一步就是在 Workers 上运行此程序,但首先我需要将其编译到具有 WASI 支持的 WASM 中。

幸好,在最新版本的 Zig 中,这个功能开箱即用,所以可以直接让编译器使用 wasm32-wasi 目标构建可执行文件,这样生成的文件可以在任何兼容 WASI 的 WebAssembly 运行时上运行,例如 wasmtime

这同一个 .wasm 文件可在 wasmtime 中运行并直接部署到 Cloudflare Workers。这样一来,就可以无缝地编译、测试和部署。

Workers 上的 Zig

$ zig build -Dtarget=wasm32-wasi

$ ls zig-out/bin
print-with-line-numbers.wasm

$ echo "Hello\nWorld" | wasmtime ./zig-out/bin/print-with-line-numbers.wasm
1    Hello
2    World

二进制文件准备好之后,最后需要使用 Wrangler2 在 Cloudflare Workers 上运行它。这很简单,只需在 workers.dev 上发布 .wasm 文件即可。如果没有 workers.dev 帐户,可以按照我们入门指南上的教程,几分钟就能完成从编写代码到部署的全过程!

事实上,我注册帐户之后,只需完成前两步,即安装 Wrangler 和登录。

然后,我运行了以下命令来发布我的 Worker:

$ npx wrangler@wasm login
Attempting to login via OAuth...
Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth
Successfully logged in.

完成这一步之后,Worker 即可开始运行,并可通过调用上面输出中打印的 URL 来调用 Worker。

$ npx wrangler@wasm publish --name print-with-line-numbers --compatibility-date=2022-07-07 zig-out/bin/print-with-line-numbers.wasm
Uploaded print-with-line-numbers (3.04 sec)
Published print-with-line-numbers (6.28 sec)
  print-with-line-numbers.workers.dev

调用成功!

echo "Hello\nWorld" | curl https://print-with-line-numbers.workers.dev -X POST --data-binary @-
1    Hello
2    World

总结

整个过程十分简单,这让我惊叹不已。

首先,我为笔记本电脑的架构编译了二进制文件,然后向编译器传递一个标志来将代码编译到 WebAssembly 中,最后,不用改动任何代码,就可以让程序在 Workers 上运行。

诚然,这个程序并不怎么复杂,能够做的事情无非是从 STDIN 读取内容并写入 STDOUT,但这让我对其潜力充满信心,尤其随着 WASI 这样的技术趋于成熟,相信它能打造无限可能。

我们保护整个企业网络,帮助客户高效构建互联网规模的应用程序,加速任何网站或互联网应用程序抵御 DDoS 攻击,防止黑客入侵,并能协助您实现 Zero Trust 的过程

从任何设备访问 1.1.1.1,以开始使用我们的免费应用程序,帮助您更快、更安全地访问互联网。要进一步了解我们帮助构建更美好互联网的使命,请从这里开始。如果您正在寻找新的职业方向,请查看我们的空缺职位
Cloudflare WorkersWebAssemblyWASM开发人员Developer Platform

在 X 上关注

Cloudflare|@cloudflare

相关帖子