Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: CI

on:
push:
branches:
- main
pull_request:
workflow_dispatch:

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: bazel ${{ matrix.bazel }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
bazel:
- 9.0.1
- 9.0.2

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Bazelisk
uses: bazelbuild/setup-bazelisk@v3

- name: Select Bazel version
run: echo "USE_BAZEL_VERSION=${{ matrix.bazel }}" >> "$GITHUB_ENV"

- name: Show Bazel version
run: bazel version

- name: Run test suite
run: bazel test //...
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,30 @@ Bazel rules for building [Zig](https://ziglang.org/) projects.

- `zig_binary` — compile Zig source files into an executable
- `zig_library` — compile Zig source files into a static library (`.a`)
- `zig_test` — compile and run Zig tests with `bazel test`
- Bazel toolchain integration with platform-aware compiler resolution

## Requirements

- Zig: 0.13.0
- Bazel: 9.0+

## CI and support matrix

The repository currently runs CI on:

- Bazel 9.0.1 on Linux and macOS
- Bazel 9.0.2 on Linux and macOS

This gives us coverage for the minimum supported Bazel 9 line and a newer Bazel 9 patch release that is currently available on GitHub-hosted runners.

CI currently runs:

- `bazel build //...`
- `bazel test ...` when Bazel test targets are present

As the ruleset grows, this matrix can expand to include more Bazel versions, additional examples, and stricter validation.

## Setup

### Bzlmod (MODULE.bazel)
Expand Down Expand Up @@ -79,3 +96,24 @@ zig_library(
|-----------|-------------|----------|
| `srcs` | List of `.zig` source files | Yes |
| `main` | Root source file for the library. Defaults to the first file in `srcs`. | No |

### `zig_test` example

Compiles and runs Zig tests through `bazel test`.

```starlark
load("@rules_zig//zig:defs.bzl", "zig_test")

zig_test(
name = "math_test",
srcs = [
"math_test.zig",
"math.zig",
],
)
```

| Attribute | Description | Required |
|-----------|-------------|----------|
| `srcs` | List of `.zig` source files needed by the test, including imported sibling files | Yes |
| `main` | Root test source file. Defaults to the first file in `srcs`. | No |
10 changes: 9 additions & 1 deletion examples/math_lib/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
load("//zig:defs.bzl", "zig_library")
load("//zig:defs.bzl", "zig_library", "zig_test")

zig_library(
name = "math",
srcs = ["math.zig"],
)

zig_test(
name = "math_test",
srcs = [
"math_test.zig",
"math.zig",
],
)
8 changes: 8 additions & 0 deletions examples/math_lib/math_test.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const std = @import("std");
const math = @import("math.zig");

test "basic arithmetic helpers" {
try std.testing.expectEqual(@as(i32, 5), math.add(2, 3));
try std.testing.expectEqual(@as(i32, 6), math.multiply(2, 3));
try std.testing.expectEqual(@as(i32, -1), math.subtract(2, 3));
}
3 changes: 2 additions & 1 deletion zig/defs.bzl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Public API for rules_zig."""

load("//zig:rules.bzl", _zig_binary = "zig_binary", _zig_library = "zig_library")
load("//zig:rules.bzl", _zig_binary = "zig_binary", _zig_library = "zig_library", _zig_test = "zig_test")

zig_binary = _zig_binary
zig_library = _zig_library
zig_test = _zig_test
71 changes: 71 additions & 0 deletions zig/rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,74 @@ zig_library = rule(
},
toolchains = ["//zig:toolchain_type"],
)

def _zig_test_impl(ctx):
zig_toolchain = ctx.toolchains["//zig:toolchain_type"]
zig_info = zig_toolchain.zig_info
zig_exe = zig_info.zig_exe

srcs = ctx.files.srcs
if len(srcs) == 0:
fail("zig_test requires at least one source file in srcs.")

main_filename = ctx.attr.main if ctx.attr.main else srcs[0].basename
main_src = None
for src in srcs:
if src.basename == main_filename or src.short_path.endswith(main_filename):
main_src = src
break
if not main_src:
fail("main file '{}' not found in srcs.".format(main_filename))

out = ctx.actions.declare_file(ctx.label.name)
src_tree = ctx.actions.declare_directory(ctx.label.name + "_srcs")
zig_link = ctx.actions.declare_file(ctx.label.name + "_zig")

ctx.actions.symlink(
output = zig_link,
target_file = zig_exe,
is_executable = True,
)

copy_commands = []
for src in srcs:
copy_commands.append("cp '{}' '{}/{}'".format(src.path, src_tree.path, src.basename))

command = "set -euo pipefail\nROOT=\"$PWD\"\nmkdir -p '{src_tree}'\n{copies}\ncd '{src_tree}'\n\"$ROOT/{zig}\" test '{main}' -femit-bin=\"$ROOT/{out}\" --cache-dir /tmp/zig-cache --global-cache-dir /tmp/zig-global-cache".format(
src_tree = src_tree.path,
copies = "\n".join(copy_commands),
zig = zig_link.path,
main = main_src.basename,
out = out.path,
)

ctx.actions.run_shell(
outputs = [out, src_tree],
inputs = srcs + [zig_link],
command = command,
mnemonic = "ZigCompileTest",
progress_message = "Compiling Zig test %{label}",
)

return [
DefaultInfo(
files = depset([out]),
executable = out,
),
]

zig_test = rule(
implementation = _zig_test_impl,
attrs = {
"srcs": attr.label_list(
doc = "Zig test source files to compile.",
allow_files = [".zig"],
mandatory = True,
),
"main": attr.string(
doc = "The root source file for the test. Defaults to the first file in srcs.",
),
},
test = True,
toolchains = ["//zig:toolchain_type"],
)
Loading