diff --git a/.bazelrc b/.bazelrc index 7500e6d5..89dc2064 100644 --- a/.bazelrc +++ b/.bazelrc @@ -7,8 +7,8 @@ import %workspace%/.bazelrc.flags # Deleted packages for integration tests. # To update these lines, execute # `bazel run @contrib_rules_bazel_integration_test//tools:update_deleted_packages` -build --deleted_packages=e2e/workspace,e2e/workspace/multiple-sources-and-packages-test,e2e/workspace/multiple-sources-binary,e2e/workspace/simple-binary,e2e/workspace/simple-library,e2e/workspace/simple-test,e2e/workspace/transitive-zig-packages-binary,e2e/workspace/transitive-zig-packages-binary/hello-world,e2e/workspace/transitive-zig-packages-binary/hello-world/data,e2e/workspace/transitive-zig-packages-binary/hello-world/data/hello,e2e/workspace/transitive-zig-packages-binary/hello-world/data/world,e2e/workspace/transitive-zig-packages-binary/hello-world/io,e2e/workspace/zig-package-binary,e2e/workspace/zig-package-binary/data,e2e/workspace/zig-package-binary/io,zig/tests/integration_tests/workspace -query --deleted_packages=e2e/workspace,e2e/workspace/multiple-sources-and-packages-test,e2e/workspace/multiple-sources-binary,e2e/workspace/simple-binary,e2e/workspace/simple-library,e2e/workspace/simple-test,e2e/workspace/transitive-zig-packages-binary,e2e/workspace/transitive-zig-packages-binary/hello-world,e2e/workspace/transitive-zig-packages-binary/hello-world/data,e2e/workspace/transitive-zig-packages-binary/hello-world/data/hello,e2e/workspace/transitive-zig-packages-binary/hello-world/data/world,e2e/workspace/transitive-zig-packages-binary/hello-world/io,e2e/workspace/zig-package-binary,e2e/workspace/zig-package-binary/data,e2e/workspace/zig-package-binary/io,zig/tests/integration_tests/workspace +build --deleted_packages=e2e/workspace,e2e/workspace/configure-mode,e2e/workspace/multiple-sources-and-packages-test,e2e/workspace/multiple-sources-binary,e2e/workspace/simple-binary,e2e/workspace/simple-library,e2e/workspace/simple-test,e2e/workspace/transitive-zig-packages-binary,e2e/workspace/transitive-zig-packages-binary/hello-world,e2e/workspace/transitive-zig-packages-binary/hello-world/data,e2e/workspace/transitive-zig-packages-binary/hello-world/data/hello,e2e/workspace/transitive-zig-packages-binary/hello-world/data/world,e2e/workspace/transitive-zig-packages-binary/hello-world/io,e2e/workspace/zig-package-binary,e2e/workspace/zig-package-binary/data,e2e/workspace/zig-package-binary/io,zig/tests/integration_tests/workspace +query --deleted_packages=e2e/workspace,e2e/workspace/configure-mode,e2e/workspace/multiple-sources-and-packages-test,e2e/workspace/multiple-sources-binary,e2e/workspace/simple-binary,e2e/workspace/simple-library,e2e/workspace/simple-test,e2e/workspace/transitive-zig-packages-binary,e2e/workspace/transitive-zig-packages-binary/hello-world,e2e/workspace/transitive-zig-packages-binary/hello-world/data,e2e/workspace/transitive-zig-packages-binary/hello-world/data/hello,e2e/workspace/transitive-zig-packages-binary/hello-world/data/world,e2e/workspace/transitive-zig-packages-binary/hello-world/io,e2e/workspace/zig-package-binary,e2e/workspace/zig-package-binary/data,e2e/workspace/zig-package-binary/io,zig/tests/integration_tests/workspace # Load any settings specific to the current user. # .bazelrc.user should appear in .gitignore so that settings are not shared with team members diff --git a/docs/rules.md b/docs/rules.md index 57beb4ff..d763052c 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -23,6 +23,66 @@ zig_binary(name, deps< | srcs | Other source files required to build the target. | List of labels | optional | [] | + + +## zig_configure + +
+zig_configure(name, actual, mode)
+
+ + + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| actual | The target to transition. | Label | required | | +| mode | The build mode setting | String | optional | "" | + + + + +## zig_configure_binary + +
+zig_configure_binary(name, actual, mode)
+
+ + + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| actual | The target to transition. | Label | required | | +| mode | The build mode setting | String | optional | "" | + + + + +## zig_configure_test + +
+zig_configure_test(name, actual, mode)
+
+ + + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| actual | The target to transition. | Label | required | | +| mode | The build mode setting | String | optional | "" | + + ## zig_library diff --git a/e2e/workspace/configure-mode/BUILD.bazel b/e2e/workspace/configure-mode/BUILD.bazel new file mode 100644 index 00000000..52933f78 --- /dev/null +++ b/e2e/workspace/configure-mode/BUILD.bazel @@ -0,0 +1,124 @@ +load("@bazel_skylib//rules:build_test.bzl", "build_test") +load("@bazel_skylib//rules:diff_test.bzl", "diff_test") +load( + "@rules_zig//zig:defs.bzl", + "zig_binary", + "zig_configure", + "zig_configure_binary", + "zig_configure_test", + "zig_library", + "zig_test", +) +load(":defs.bzl", "run") + +zig_library( + name = "library", + main = "library.zig", + tags = ["manual"], +) + +zig_configure( + name = "library_debug", + actual = ":library", + mode = "debug", +) + +zig_configure( + name = "library_release_safe", + actual = ":library", + mode = "release_safe", +) + +genrule( + name = "library_debug_symbol", + srcs = [":library_debug"], + outs = ["library_debug_symbol.txt"], + cmd = "$(NM) -j --defined-only $(SRCS) | grep Debug > $(OUTS)", + toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"], +) + +genrule( + name = "library_release_safe_symbol", + srcs = [":library_release_safe"], + outs = ["library_release_safe_symbol.txt"], + cmd = "$(NM) -j --defined-only $(SRCS) | grep ReleaseSafe > $(OUTS)", + toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"], +) + +build_test( + name = "library_test", + targets = [ + ":library_debug_symbol", + ":library_release_safe_symbol", + ], +) + +zig_binary( + name = "binary", + main = "binary.zig", + tags = ["manual"], +) + +zig_configure_binary( + name = "binary_debug", + actual = ":binary", + mode = "debug", +) + +zig_configure_binary( + name = "binary_release_safe", + actual = ":binary", + mode = "release_safe", +) + +# NOTE using genrule instead of run fails with Bazel version 5.3.2. +# It seems that the configuration transition is not handled correctly by +# genrule in Bazel version 5.3.2. + +run( + name = "binary_debug_output", + out = "binary_debug_output.actual", + tool = ":binary_debug", +) + +run( + name = "binary_release_safe_output", + out = "binary_release_safe_output.actual", + tool = ":binary_release_safe", +) + +diff_test( + name = "binary_debug_output_test", + file1 = ":binary_debug_output.expected", + file2 = ":binary_debug_output.actual", +) + +diff_test( + name = "binary_release_safe_output_test", + file1 = ":binary_release_safe_output.expected", + file2 = ":binary_release_safe_output.actual", +) + +zig_test( + name = "_test_debug", + main = "test_debug.zig", + tags = ["manual"], +) + +zig_configure_test( + name = "test_debug", + actual = "_test_debug", + mode = "debug", +) + +zig_test( + name = "_test_release_safe", + main = "test_release_safe.zig", + tags = ["manual"], +) + +zig_configure_test( + name = "test_release_safe", + actual = "_test_release_safe", + mode = "release_safe", +) diff --git a/e2e/workspace/configure-mode/binary.zig b/e2e/workspace/configure-mode/binary.zig new file mode 100644 index 00000000..11309dd5 --- /dev/null +++ b/e2e/workspace/configure-mode/binary.zig @@ -0,0 +1,9 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +pub fn main() void { + std.io.getStdOut().writer().print( + "{s}\n", + .{std.meta.tagName(builtin.mode)}, + ) catch unreachable; +} diff --git a/e2e/workspace/configure-mode/binary_debug_output.expected b/e2e/workspace/configure-mode/binary_debug_output.expected new file mode 100644 index 00000000..329d484d --- /dev/null +++ b/e2e/workspace/configure-mode/binary_debug_output.expected @@ -0,0 +1 @@ +Debug diff --git a/e2e/workspace/configure-mode/binary_release_safe_output.expected b/e2e/workspace/configure-mode/binary_release_safe_output.expected new file mode 100644 index 00000000..9dc92ff9 --- /dev/null +++ b/e2e/workspace/configure-mode/binary_release_safe_output.expected @@ -0,0 +1 @@ +ReleaseSafe diff --git a/e2e/workspace/configure-mode/defs.bzl b/e2e/workspace/configure-mode/defs.bzl new file mode 100644 index 00000000..e6a153d7 --- /dev/null +++ b/e2e/workspace/configure-mode/defs.bzl @@ -0,0 +1,19 @@ +"""Implements a rule to run a binary and write its output to a file.""" + +def _run_impl(ctx): + ctx.actions.run_shell( + outputs = [ctx.outputs.out], + tools = [ctx.executable.tool], + mnemonic = "RunBinary", + command = "{} > {}".format(ctx.executable.tool.path, ctx.outputs.out.path), + progress_message = "Running binary to create %{output}", + ) + return [DefaultInfo(files = depset([ctx.outputs.out]))] + +run = rule( + _run_impl, + attrs = { + "out": attr.output(), + "tool": attr.label(executable = True, cfg = "exec"), + }, +) diff --git a/e2e/workspace/configure-mode/library.zig b/e2e/workspace/configure-mode/library.zig new file mode 100644 index 00000000..60f31612 --- /dev/null +++ b/e2e/workspace/configure-mode/library.zig @@ -0,0 +1,8 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +comptime { + @export(internalName, .{ .name = @tagName(builtin.mode), .linkage = .Strong }); +} + +fn internalName() callconv(.C) void {} diff --git a/e2e/workspace/configure-mode/test_debug.zig b/e2e/workspace/configure-mode/test_debug.zig new file mode 100644 index 00000000..ffaec1b8 --- /dev/null +++ b/e2e/workspace/configure-mode/test_debug.zig @@ -0,0 +1,6 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +test "mode is Debug" { + try std.testing.expectEqual(std.builtin.Mode.Debug, builtin.mode); +} diff --git a/e2e/workspace/configure-mode/test_release_safe.zig b/e2e/workspace/configure-mode/test_release_safe.zig new file mode 100644 index 00000000..7b30b593 --- /dev/null +++ b/e2e/workspace/configure-mode/test_release_safe.zig @@ -0,0 +1,6 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +test "mode is ReleaseSafe" { + try std.testing.expectEqual(std.builtin.Mode.ReleaseSafe, builtin.mode); +} diff --git a/zig/BUILD.bazel b/zig/BUILD.bazel index d31b2b02..d07e4f89 100644 --- a/zig/BUILD.bazel +++ b/zig/BUILD.bazel @@ -38,6 +38,7 @@ bzl_library( visibility = ["//visibility:public"], deps = [ "//zig/private:zig_binary", + "//zig/private:zig_configure", "//zig/private:zig_library", "//zig/private:zig_package", "//zig/private:zig_test", diff --git a/zig/defs.bzl b/zig/defs.bzl index e7c82ada..0be601ec 100644 --- a/zig/defs.bzl +++ b/zig/defs.bzl @@ -4,8 +4,17 @@ load("//zig/private:zig_binary.bzl", _zig_binary = "zig_binary") load("//zig/private:zig_library.bzl", _zig_library = "zig_library") load("//zig/private:zig_package.bzl", _zig_package = "zig_package") load("//zig/private:zig_test.bzl", _zig_test = "zig_test") +load( + "//zig/private:zig_configure.bzl", + _zig_configure = "zig_configure", + _zig_configure_binary = "zig_configure_binary", + _zig_configure_test = "zig_configure_test", +) zig_binary = _zig_binary zig_library = _zig_library zig_package = _zig_package zig_test = _zig_test +zig_configure = _zig_configure +zig_configure_binary = _zig_configure_binary +zig_configure_test = _zig_configure_test diff --git a/zig/private/BUILD.bazel b/zig/private/BUILD.bazel index 78b29974..82010cea 100644 --- a/zig/private/BUILD.bazel +++ b/zig/private/BUILD.bazel @@ -48,6 +48,16 @@ bzl_library( ], ) +bzl_library( + name = "zig_configure", + srcs = ["zig_configure.bzl"], + visibility = ["//zig:__subpackages__"], + deps = [ + ":settings", + "@bazel_skylib//lib:paths", + ], +) + bzl_library( name = "resolved_toolchain", srcs = ["resolved_toolchain.bzl"], @@ -76,6 +86,7 @@ filegroup( ":toolchains_repo.bzl", ":versions.bzl", ":zig_binary.bzl", + ":zig_configure.bzl", ":zig_library.bzl", ":zig_package.bzl", ":zig_test.bzl", diff --git a/zig/private/settings.bzl b/zig/private/settings.bzl index 5b63fc67..4ddef3c1 100644 --- a/zig/private/settings.bzl +++ b/zig/private/settings.bzl @@ -20,6 +20,8 @@ MODE_ARGS = { "release_fast": ["-O", "ReleaseFast"], } +MODE_VALUES = ["debug", "release_safe", "release_small", "release_fast"] + def _settings_impl(ctx): args = [] diff --git a/zig/private/zig_configure.bzl b/zig/private/zig_configure.bzl new file mode 100644 index 00000000..5debd504 --- /dev/null +++ b/zig/private/zig_configure.bzl @@ -0,0 +1,105 @@ +"""Implementation of the zig_configure rule.""" + +load("@bazel_skylib//lib:paths.bzl", "paths") +load("//zig/private:settings.bzl", "MODE_VALUES") + +DOC = """\ +""" + +def _zig_transition_impl(settings, attr): + result = {} + if attr.mode: + result["//zig/settings:mode"] = attr.mode + return result + +_zig_transition = transition( + implementation = _zig_transition_impl, + inputs = [], + outputs = ["//zig/settings:mode"], +) + +def _make_attrs(*, executable, test): + return { + "actual": attr.label( + doc = "The target to transition.", + cfg = _zig_transition, + executable = executable, + mandatory = True, + ), + "mode": attr.string( + doc = "The build mode setting", + mandatory = False, + values = MODE_VALUES, + ), + "_whitelist_function_transition": attr.label( + default = "@bazel_tools//tools/whitelists/function_transition_whitelist", + ), + } + +_FORWARD_PROVIDERS = [ +] + +def _make_zig_configure_rule(*, executable, test): + _executable = executable + _test = test + + def _zig_configure_impl(ctx): + executable = _executable + test = _test + + if type(ctx.attr.actual) == "list": + if len(ctx.attr.actual) == 1: + actual = ctx.attr.actual[0] + else: + fail("INTERNAL ERROR: Unexpected 1:n transition encountered.") + else: + actual = ctx.attr.actual + + providers = [] + for provider in _FORWARD_PROVIDERS: + if provider in actual: + providers.append(actual[provider]) + + if executable: + # Executable rules must create the returned executable artifact + # themselves. This is required so that Bazel can create the + # corresponding runfiles tree or manifest next to the produced + # executable artifact. + # See https://github.com/bazelbuild/bazel/issues/4170 + + actual_executable = actual[DefaultInfo].files_to_run.executable + (_, extension) = paths.split_extension(actual_executable.path) + executable = ctx.actions.declare_file( + ctx.label.name + extension, + ) + ctx.actions.symlink( + output = executable, + target_file = actual_executable, + is_executable = True, + ) + + # TODO[AH] Add a data attribute for executable rules. + runfiles = ctx.runfiles(files = [executable, actual_executable]) + runfiles = runfiles.merge(actual[DefaultInfo].default_runfiles) + + providers.append(DefaultInfo( + executable = executable, + files = depset(direct = [executable]), + runfiles = runfiles, + )) + else: + providers.append(actual[DefaultInfo]) + + return providers + + return rule( + _zig_configure_impl, + attrs = _make_attrs(executable = executable, test = test), + doc = DOC, + executable = executable, + test = test, + ) + +zig_configure = _make_zig_configure_rule(executable = False, test = False) +zig_configure_binary = _make_zig_configure_rule(executable = True, test = False) +zig_configure_test = _make_zig_configure_rule(executable = True, test = True)