diff --git a/docs/rules.md b/docs/rules.md index 3a4dda36..1200840a 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -2,15 +2,22 @@ Public API re-exports - + -## example +## zig_binary
-example() +zig_binary(name, main)-This is an example +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| main | The main source file. | Label | required | | + diff --git a/e2e/workspace/simple-binary/BUILD.bazel b/e2e/workspace/simple-binary/BUILD.bazel new file mode 100644 index 00000000..82fd9c70 --- /dev/null +++ b/e2e/workspace/simple-binary/BUILD.bazel @@ -0,0 +1,20 @@ +load("@bazel_skylib//rules:diff_test.bzl", "diff_test") +load("@rules_zig//zig:defs.bzl", "zig_binary") + +zig_binary( + name = "binary", + main = "main.zig", +) + +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/simple-binary/main.zig b/e2e/workspace/simple-binary/main.zig new file mode 100644 index 00000000..a2ce4c02 --- /dev/null +++ b/e2e/workspace/simple-binary/main.zig @@ -0,0 +1,7 @@ +const std = @import("std"); + +pub fn main() void { + std.io.getStdOut().writeAll( + "Hello World!\n", + ) catch unreachable; +} diff --git a/e2e/workspace/simple-binary/output.expected b/e2e/workspace/simple-binary/output.expected new file mode 100644 index 00000000..980a0d5f --- /dev/null +++ b/e2e/workspace/simple-binary/output.expected @@ -0,0 +1 @@ +Hello World! diff --git a/zig/BUILD.bazel b/zig/BUILD.bazel index d441b635..7432787b 100644 --- a/zig/BUILD.bazel +++ b/zig/BUILD.bazel @@ -27,6 +27,7 @@ bzl_library( name = "defs", srcs = ["defs.bzl"], visibility = ["//visibility:public"], + deps = ["//zig/private:zig_binary"], ) bzl_library( diff --git a/zig/defs.bzl b/zig/defs.bzl index b48c6fcb..9a9a3fdb 100644 --- a/zig/defs.bzl +++ b/zig/defs.bzl @@ -1,5 +1,5 @@ "Public API re-exports" -def example(): - """This is an example""" - pass +load("//zig/private:zig_binary.bzl", _zig_binary = "zig_binary") + +zig_binary = _zig_binary diff --git a/zig/private/BUILD.bazel b/zig/private/BUILD.bazel index 2f07e8d1..3d0b18e5 100644 --- a/zig/private/BUILD.bazel +++ b/zig/private/BUILD.bazel @@ -11,3 +11,10 @@ bzl_library( srcs = ["versions.bzl"], visibility = ["//zig:__subpackages__"], ) + +bzl_library( + name = "zig_binary", + srcs = ["zig_binary.bzl"], + visibility = ["//zig:__subpackages__"], + deps = ["@bazel_skylib//lib:paths"], +) diff --git a/zig/private/zig_binary.bzl b/zig/private/zig_binary.bzl new file mode 100644 index 00000000..1190ddc0 --- /dev/null +++ b/zig/private/zig_binary.bzl @@ -0,0 +1,59 @@ +"""Implementation of the zig_binary rule.""" + +load("@bazel_skylib//lib:paths.bzl", "paths") + +DOC = """\ +""" + +ATTRS = { + "main": attr.label( + allow_single_file = [".zig"], + doc = "The main source file.", + mandatory = True, + ), +} + +def _zig_binary_impl(ctx): + ziginfo = ctx.toolchains["//zig:toolchain_type"].ziginfo + + # TODO[AH] Append `.exe` extension on Windows. + output = ctx.actions.declare_file(ctx.label.name) + + 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)) + + args = ctx.actions.args() + args.use_param_file("@%s") + + args.add(output, format = "-femit-bin=%s") + args.add(ctx.file.main) + + # 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], + executable = ziginfo.target_tool_path, + tools = ziginfo.tool_files, + arguments = ["build-exe", args], + mnemonic = "ZigBuildExe", + progress_message = "Building %{input} as Zig binary %{output}", + execution_requirements = {tag: "" for tag in ctx.attr.tags}, + ) + + default = DefaultInfo( + executable = output, + files = depset([output]), + runfiles = ctx.runfiles(files = [output]), + ) + + return [default] + +zig_binary = rule( + _zig_binary_impl, + attrs = ATTRS, + doc = DOC, + toolchains = ["//zig:toolchain_type"], +) diff --git a/zig/tests/BUILD.bazel b/zig/tests/BUILD.bazel index 93eae3c5..40b2b2a3 100644 --- a/zig/tests/BUILD.bazel +++ b/zig/tests/BUILD.bazel @@ -1,3 +1,6 @@ +load(":rules_test.bzl", "rules_test_suite") load(":versions_test.bzl", "versions_test_suite") +rules_test_suite(name = "rules_test") + versions_test_suite(name = "versions_test") diff --git a/zig/tests/rules_test.bzl b/zig/tests/rules_test.bzl new file mode 100644 index 00000000..d2ab9161 --- /dev/null +++ b/zig/tests/rules_test.bzl @@ -0,0 +1,44 @@ +"""Analysis tests for rules +See https://bazel.build/rules/testing#testing-rules +""" + +load("@bazel_skylib//lib:sets.bzl", "sets") +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") + +def _simple_binary_test_impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + default = target[DefaultInfo] + + executable = default.files_to_run.executable + asserts.true(executable != None, "zig_binary should produce an executable.") + asserts.true(sets.contains(sets.make(default.files.to_list()), executable), "zig_binary should return the executable as an output.") + asserts.true(sets.contains(sets.make(default.default_runfiles.files.to_list()), executable), "zig_binary should return the executable in the runfiles.") + + build = [ + action + for action in analysistest.target_actions(env) + if action.mnemonic == "ZigBuildExe" + ] + asserts.equals(env, 1, len(build), "zig_binary should generate one ZigBuildExe action.") + build = build[0] + asserts.true(sets.contains(sets.make(build.outputs.to_list()), executable), "zig_binary should generate a ZigBuildExe action that generates the binary.") + + return analysistest.end(env) + +_simple_binary_test = analysistest.make(_simple_binary_test_impl) + +def _test_simple_binary(name): + _simple_binary_test( + name = name, + target_under_test = "//zig/tests/simple-binary:binary", + ) + +def rules_test_suite(name): + _test_simple_binary(name = "simple_binary_test") + native.test_suite( + name = name, + tests = [ + ":simple_binary_test", + ], + ) diff --git a/zig/tests/simple-binary/BUILD.bazel b/zig/tests/simple-binary/BUILD.bazel new file mode 100644 index 00000000..7419cb57 --- /dev/null +++ b/zig/tests/simple-binary/BUILD.bazel @@ -0,0 +1,7 @@ +load("@rules_zig//zig:defs.bzl", "zig_binary") + +zig_binary( + name = "binary", + main = "main.zig", + visibility = ["//zig/tests:__pkg__"], +) diff --git a/zig/tests/simple-binary/main.zig b/zig/tests/simple-binary/main.zig new file mode 100644 index 00000000..a2ce4c02 --- /dev/null +++ b/zig/tests/simple-binary/main.zig @@ -0,0 +1,7 @@ +const std = @import("std"); + +pub fn main() void { + std.io.getStdOut().writeAll( + "Hello World!\n", + ) catch unreachable; +}