diff --git a/docs/rules.md b/docs/rules.md index 0d50a20a..9718f51a 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -7,7 +7,7 @@ Public API re-exports ## zig_binary
-zig_binary(name, main, srcs) +zig_binary(name, deps, main, srcs)@@ -18,7 +18,28 @@ zig_binary(name, main< | Name | Description | Type | Mandatory | Default | | :------------- | :------------- | :------------- | :------------- | :------------- | | name | A unique name for this target. | Name | required | | +| deps | Packages or libraries required to build the target. | List of labels | optional |
[] |
| main | The main source file. | Label | required | |
| srcs | Other source files required to build the target. | List of labels | optional | [] |
+
+
+## zig_package
+
++zig_package(name, main, srcs) ++ + + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| main | The main source file. | Label | required | | +| srcs | Other source files required when building the package. | List of labels | optional |
[] |
+
+
diff --git a/e2e/workspace/zig-package-binary/BUILD.bazel b/e2e/workspace/zig-package-binary/BUILD.bazel
new file mode 100644
index 00000000..e7faf4aa
--- /dev/null
+++ b/e2e/workspace/zig-package-binary/BUILD.bazel
@@ -0,0 +1,24 @@
+load("@bazel_skylib//rules:diff_test.bzl", "diff_test")
+load("@rules_zig//zig:defs.bzl", "zig_binary")
+
+zig_binary(
+ name = "binary",
+ main = "main.zig",
+ deps = [
+ "//zig-package-binary/data",
+ "//zig-package-binary/io",
+ ],
+)
+
+genrule(
+ name = "output",
+ outs = ["output.actual"],
+ cmd = "$(execpath :binary) > $(OUTS)",
+ tools = [":binary"],
+)
+
+diff_test(
+ name = "output_test",
+ file1 = ":output.expected",
+ file2 = ":output.actual",
+)
diff --git a/e2e/workspace/zig-package-binary/data/BUILD.bazel b/e2e/workspace/zig-package-binary/data/BUILD.bazel
new file mode 100644
index 00000000..38c2418b
--- /dev/null
+++ b/e2e/workspace/zig-package-binary/data/BUILD.bazel
@@ -0,0 +1,11 @@
+load("@rules_zig//zig:defs.bzl", "zig_package")
+
+zig_package(
+ name = "data",
+ srcs = [
+ "data/hello.zig",
+ "data/world.zig",
+ ],
+ main = "data.zig",
+ visibility = ["//zig-package-binary:__pkg__"],
+)
diff --git a/e2e/workspace/zig-package-binary/data/data.zig b/e2e/workspace/zig-package-binary/data/data.zig
new file mode 100644
index 00000000..65d7612d
--- /dev/null
+++ b/e2e/workspace/zig-package-binary/data/data.zig
@@ -0,0 +1,4 @@
+const hello = @import("data/hello.zig");
+const world = @import("data/world.zig");
+
+pub const hello_world = hello.data ++ " " ++ world.data ++ "\n";
diff --git a/e2e/workspace/zig-package-binary/data/data/hello.zig b/e2e/workspace/zig-package-binary/data/data/hello.zig
new file mode 100644
index 00000000..dac2d625
--- /dev/null
+++ b/e2e/workspace/zig-package-binary/data/data/hello.zig
@@ -0,0 +1 @@
+pub const data = "Hello";
diff --git a/e2e/workspace/zig-package-binary/data/data/world.zig b/e2e/workspace/zig-package-binary/data/data/world.zig
new file mode 100644
index 00000000..7850d787
--- /dev/null
+++ b/e2e/workspace/zig-package-binary/data/data/world.zig
@@ -0,0 +1 @@
+pub const data = "World!";
diff --git a/e2e/workspace/zig-package-binary/io/BUILD.bazel b/e2e/workspace/zig-package-binary/io/BUILD.bazel
new file mode 100644
index 00000000..4461a240
--- /dev/null
+++ b/e2e/workspace/zig-package-binary/io/BUILD.bazel
@@ -0,0 +1,7 @@
+load("@rules_zig//zig:defs.bzl", "zig_package")
+
+zig_package(
+ name = "io",
+ main = "io.zig",
+ visibility = ["//zig-package-binary:__pkg__"],
+)
diff --git a/e2e/workspace/zig-package-binary/io/io.zig b/e2e/workspace/zig-package-binary/io/io.zig
new file mode 100644
index 00000000..83010cbc
--- /dev/null
+++ b/e2e/workspace/zig-package-binary/io/io.zig
@@ -0,0 +1,5 @@
+const std = @import("std");
+
+pub fn print(msg: []const u8) void {
+ std.io.getStdOut().writeAll(msg) catch unreachable;
+}
diff --git a/e2e/workspace/zig-package-binary/main.zig b/e2e/workspace/zig-package-binary/main.zig
new file mode 100644
index 00000000..8de05422
--- /dev/null
+++ b/e2e/workspace/zig-package-binary/main.zig
@@ -0,0 +1,7 @@
+const std = @import("std");
+const data = @import("data");
+const io = @import("io");
+
+pub fn main() void {
+ io.print(data.hello_world);
+}
diff --git a/e2e/workspace/zig-package-binary/output.expected b/e2e/workspace/zig-package-binary/output.expected
new file mode 100644
index 00000000..980a0d5f
--- /dev/null
+++ b/e2e/workspace/zig-package-binary/output.expected
@@ -0,0 +1 @@
+Hello World!
diff --git a/zig/BUILD.bazel b/zig/BUILD.bazel
index 7432787b..af6f2d61 100644
--- a/zig/BUILD.bazel
+++ b/zig/BUILD.bazel
@@ -27,7 +27,10 @@ bzl_library(
name = "defs",
srcs = ["defs.bzl"],
visibility = ["//visibility:public"],
- deps = ["//zig/private:zig_binary"],
+ deps = [
+ "//zig/private:zig_binary",
+ "//zig/private:zig_package",
+ ],
)
bzl_library(
diff --git a/zig/defs.bzl b/zig/defs.bzl
index 9a9a3fdb..a10850b7 100644
--- a/zig/defs.bzl
+++ b/zig/defs.bzl
@@ -1,5 +1,7 @@
"Public API re-exports"
load("//zig/private:zig_binary.bzl", _zig_binary = "zig_binary")
+load("//zig/private:zig_package.bzl", _zig_package = "zig_package")
zig_binary = _zig_binary
+zig_package = _zig_package
diff --git a/zig/private/BUILD.bazel b/zig/private/BUILD.bazel
index 3d0b18e5..17a658d0 100644
--- a/zig/private/BUILD.bazel
+++ b/zig/private/BUILD.bazel
@@ -16,5 +16,24 @@ bzl_library(
name = "zig_binary",
srcs = ["zig_binary.bzl"],
visibility = ["//zig:__subpackages__"],
- deps = ["@bazel_skylib//lib:paths"],
+ deps = [
+ ":filetypes",
+ "@bazel_skylib//lib:paths",
+ ],
+)
+
+bzl_library(
+ name = "zig_package",
+ srcs = ["zig_package.bzl"],
+ visibility = ["//zig:__subpackages__"],
+ deps = [
+ ":filetypes",
+ "//zig/private/providers:zig_package_info",
+ ],
+)
+
+bzl_library(
+ name = "filetypes",
+ srcs = ["filetypes.bzl"],
+ visibility = ["//zig:__subpackages__"],
)
diff --git a/zig/private/filetypes.bzl b/zig/private/filetypes.bzl
new file mode 100644
index 00000000..4f8b54ab
--- /dev/null
+++ b/zig/private/filetypes.bzl
@@ -0,0 +1,3 @@
+"""Define filetypes accepted by rules."""
+
+ZIG_SOURCE_EXTENSIONS = [".zig"]
diff --git a/zig/private/providers/BUILD.bazel b/zig/private/providers/BUILD.bazel
new file mode 100644
index 00000000..5d159ac3
--- /dev/null
+++ b/zig/private/providers/BUILD.bazel
@@ -0,0 +1,7 @@
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
+bzl_library(
+ name = "zig_package_info",
+ srcs = ["zig_package_info.bzl"],
+ visibility = ["//zig:__subpackages__"],
+)
diff --git a/zig/private/providers/zig_package_info.bzl b/zig/private/providers/zig_package_info.bzl
new file mode 100644
index 00000000..72cf0738
--- /dev/null
+++ b/zig/private/providers/zig_package_info.bzl
@@ -0,0 +1,31 @@
+"""Defines providers for the zig_package rule."""
+
+DOC = """\
+"""
+
+FIELDS = {
+ "name": "The import name of the package.",
+ "main": "The main source file of the package.",
+ "srcs": "Other source files required when building the package.",
+}
+
+ZigPackageInfo = provider(
+ fields = FIELDS,
+ doc = DOC,
+)
+
+def add_package_flags(args, package):
+ """Generate the Zig compiler flags to depend on the given package.
+
+ Generates `--pkg-begin` and `--pkg-end` flags required to build a target
+ that depends on this package.
+
+ Args:
+ args: The Args object to extend with the required flags.
+ package: The package to generate flags for.
+ """
+ args.add_all(["--pkg-begin", package.name, package.main, "--pkg-end"])
+
+def get_package_files(package):
+ """Generate a `depset` of the files required to depend on the package."""
+ return depset([package.main] + package.srcs)
diff --git a/zig/private/zig_binary.bzl b/zig/private/zig_binary.bzl
index 7b8901c9..d30abd89 100644
--- a/zig/private/zig_binary.bzl
+++ b/zig/private/zig_binary.bzl
@@ -1,8 +1,13 @@
"""Implementation of the zig_binary rule."""
load("@bazel_skylib//lib:paths.bzl", "paths")
-
-ZIG_SOURCE_EXTENSIONS = [".zig"]
+load("//zig/private:filetypes.bzl", "ZIG_SOURCE_EXTENSIONS")
+load(
+ "//zig/private/providers:zig_package_info.bzl",
+ "ZigPackageInfo",
+ "add_package_flags",
+ "get_package_files",
+)
DOC = """\
"""
@@ -18,6 +23,11 @@ ATTRS = {
doc = "Other source files required to build the target.",
mandatory = False,
),
+ "deps": attr.label_list(
+ doc = "Packages or libraries required to build the target.",
+ mandatory = False,
+ providers = [ZigPackageInfo],
+ ),
}
def _zig_binary_impl(ctx):
@@ -29,19 +39,28 @@ def _zig_binary_impl(ctx):
local_cache = ctx.actions.declare_directory(paths.join(".zig-cache", "local", ctx.label.name))
global_cache = ctx.actions.declare_directory(paths.join(".zig-cache", "global", ctx.label.name))
+ direct_inputs = [ctx.file.main] + ctx.files.srcs
+ transitive_inputs = []
+
args = ctx.actions.args()
args.use_param_file("@%s")
args.add(output, format = "-femit-bin=%s")
args.add(ctx.file.main)
+ for dep in ctx.attr.deps:
+ if ZigPackageInfo in dep:
+ package = dep[ZigPackageInfo]
+ transitive_inputs.append(get_package_files(package))
+ add_package_flags(args, package)
+
# TODO[AH] Persist or share at least the global cache somehow.
args.add_all(["--cache-dir", local_cache.path])
args.add_all(["--global-cache-dir", global_cache.path])
ctx.actions.run(
outputs = [output, local_cache, global_cache],
- inputs = [ctx.file.main] + ctx.files.srcs,
+ inputs = depset(direct = direct_inputs, transitive = transitive_inputs),
executable = ziginfo.target_tool_path,
tools = ziginfo.tool_files,
arguments = ["build-exe", args],
diff --git a/zig/private/zig_package.bzl b/zig/private/zig_package.bzl
new file mode 100644
index 00000000..be17bd05
--- /dev/null
+++ b/zig/private/zig_package.bzl
@@ -0,0 +1,37 @@
+"""Implementation of the zig_package rule."""
+
+load("//zig/private/providers:zig_package_info.bzl", "ZigPackageInfo")
+load("//zig/private:filetypes.bzl", "ZIG_SOURCE_EXTENSIONS")
+
+DOC = """\
+"""
+
+ATTRS = {
+ "main": attr.label(
+ allow_single_file = ZIG_SOURCE_EXTENSIONS,
+ doc = "The main source file.",
+ mandatory = True,
+ ),
+ "srcs": attr.label_list(
+ allow_files = ZIG_SOURCE_EXTENSIONS,
+ doc = "Other source files required when building the package.",
+ mandatory = False,
+ ),
+}
+
+def _zig_package_impl(ctx):
+ default = DefaultInfo(
+ )
+ package = ZigPackageInfo(
+ name = ctx.label.name,
+ main = ctx.file.main,
+ srcs = ctx.files.srcs,
+ )
+ return [default, package]
+
+zig_package = rule(
+ _zig_package_impl,
+ attrs = ATTRS,
+ doc = DOC,
+ toolchains = ["//zig:toolchain_type"],
+)
diff --git a/zig/tests/BUILD.bazel b/zig/tests/BUILD.bazel
index 40b2b2a3..a6204fff 100644
--- a/zig/tests/BUILD.bazel
+++ b/zig/tests/BUILD.bazel
@@ -1,6 +1,9 @@
load(":rules_test.bzl", "rules_test_suite")
+load(":package_info_test.bzl", "package_info_test_suite")
load(":versions_test.bzl", "versions_test_suite")
rules_test_suite(name = "rules_test")
+package_info_test_suite(name = "package_info_test")
+
versions_test_suite(name = "versions_test")
diff --git a/zig/tests/multiple-sources-package/BUILD.bazel b/zig/tests/multiple-sources-package/BUILD.bazel
new file mode 100644
index 00000000..73b70b42
--- /dev/null
+++ b/zig/tests/multiple-sources-package/BUILD.bazel
@@ -0,0 +1,11 @@
+load("@rules_zig//zig:defs.bzl", "zig_package")
+
+zig_package(
+ name = "data",
+ srcs = [
+ "data/hello.zig",
+ "data/world.zig",
+ ],
+ main = "data.zig",
+ visibility = ["//zig/tests:__pkg__"],
+)
diff --git a/zig/tests/multiple-sources-package/data.zig b/zig/tests/multiple-sources-package/data.zig
new file mode 100644
index 00000000..65d7612d
--- /dev/null
+++ b/zig/tests/multiple-sources-package/data.zig
@@ -0,0 +1,4 @@
+const hello = @import("data/hello.zig");
+const world = @import("data/world.zig");
+
+pub const hello_world = hello.data ++ " " ++ world.data ++ "\n";
diff --git a/zig/tests/multiple-sources-package/data/hello.zig b/zig/tests/multiple-sources-package/data/hello.zig
new file mode 100644
index 00000000..dac2d625
--- /dev/null
+++ b/zig/tests/multiple-sources-package/data/hello.zig
@@ -0,0 +1 @@
+pub const data = "Hello";
diff --git a/zig/tests/multiple-sources-package/data/world.zig b/zig/tests/multiple-sources-package/data/world.zig
new file mode 100644
index 00000000..7850d787
--- /dev/null
+++ b/zig/tests/multiple-sources-package/data/world.zig
@@ -0,0 +1 @@
+pub const data = "World!";
diff --git a/zig/tests/package_info_test.bzl b/zig/tests/package_info_test.bzl
new file mode 100644
index 00000000..51e9702c
--- /dev/null
+++ b/zig/tests/package_info_test.bzl
@@ -0,0 +1,69 @@
+"""Unit tests for ZigPackageInfo functions.
+"""
+
+load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest")
+load("@bazel_skylib//lib:sets.bzl", "sets")
+load(
+ "//zig/private/providers:zig_package_info.bzl",
+ "ZigPackageInfo",
+ "add_package_flags",
+ "get_package_files",
+)
+
+def _mock_args():
+ self_args = []
+
+ def add_all(args):
+ for arg in args:
+ if type(arg) == "File":
+ self_args.append(arg.path)
+ else:
+ self_args.append(arg)
+
+ def get_args():
+ return self_args
+
+ return struct(
+ add_all = add_all,
+ get_args = get_args,
+ )
+
+def _single_package_test_impl(ctx):
+ env = unittest.begin(ctx)
+
+ package = ctx.attr.pkg[ZigPackageInfo]
+
+ args = _mock_args()
+ add_package_flags(args, package)
+ asserts.equals(
+ env,
+ ["--pkg-begin", package.name, package.main.path, "--pkg-end"],
+ args.get_args(),
+ "add_package_flags should generate the expected arguments.",
+ )
+
+ files = get_package_files(package)
+ asserts.set_equals(
+ env,
+ sets.make([package.main] + package.srcs),
+ sets.make(files.to_list()),
+ "get_package_files should capture all package files.",
+ )
+
+ return unittest.end(env)
+
+_single_package_test = unittest.make(
+ _single_package_test_impl,
+ attrs = {
+ "pkg": attr.label(providers = [ZigPackageInfo]),
+ },
+)
+
+def package_info_test_suite(name):
+ unittest.suite(
+ name,
+ lambda name: _single_package_test(
+ name = name,
+ pkg = "//zig/tests/multiple-sources-package:data",
+ ),
+ )