Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
5e06f39
Add `env` and `env_inherit` to `native_binary` and `native_test`
redsun82 Dec 20, 2023
f59ff4a
Add test for `env` and `env_inherit`
redsun82 Dec 21, 2023
4dc1f9a
Make env and env_inherit parameters of native_binary depend on bazel …
redsun82 Dec 21, 2023
10ea0af
Update docs
redsun82 Dec 21, 2023
70e6b77
Update patch indexes
redsun82 Dec 21, 2023
6e83bfe
Fix windows compilation of `assertenv.cc`
redsun82 Dec 21, 2023
d53f286
Autoformat
redsun82 Dec 21, 2023
336176f
Autoformat correctly
redsun82 Dec 21, 2023
b2b6677
Tweak `env_test` for Windows
redsun82 Dec 21, 2023
df44fa9
Lint
redsun82 Dec 21, 2023
5a73fbe
Mention bazel version in native_binary docs
redsun82 Dec 21, 2023
2453f16
Fix formatting
redsun82 Dec 21, 2023
20acd19
Generalize again test to windows
redsun82 Dec 21, 2023
9ce0e55
Use `bazel_features`
redsun82 Jan 11, 2024
f1bd4e0
Add missing directory and fix docs
redsun82 Jan 11, 2024
165e7ef
Fix formatting
redsun82 Jan 11, 2024
c23d409
Merge branch 'main' into env-native-binary-using-features
redsun82 Jun 13, 2024
f05da82
Update `bazel_features`
redsun82 Jun 13, 2024
02c2708
Update `MODULE.bazle-remove-override.patch`
redsun82 Jun 13, 2024
f86cde0
Add location expansion to `env`
redsun82 Jun 13, 2024
798c1a7
Update docs
redsun82 Jun 13, 2024
a7c1415
Fix `--noenable_bzlmod` checks
redsun82 Jun 13, 2024
b9cc025
Remove unneeded backward compatibility code
redsun82 Jun 26, 2024
b8adf7f
Fix formatting
redsun82 Jun 26, 2024
1ca13a4
Remove unneeded code
redsun82 Jun 26, 2024
bcbc4fd
Merge branch 'main' into env-native-binary-using-features
Aug 26, 2024
8f76bb6
Clean up test code
Aug 26, 2024
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
6 changes: 6 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ register_toolchains(
)

bazel_dep(name = "platforms", version = "0.0.4")
bazel_dep(name = "bazel_features", version = "1.2.0")

### INTERNAL ONLY - lines after this are not included in the release packaging.

Expand All @@ -27,3 +28,8 @@ local_path_override(
module_name = "bazel_skylib_gazelle_plugin",
path = "gazelle",
)

local_path_override(
module_name = "bazel_features",
path = "bazel_features_stub",
)
11 changes: 5 additions & 6 deletions MODULE.bazel-remove-override.patch
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
--- MODULE.bazel
+++ MODULE.bazel
@@ -22,8 +22,8 @@
@@ -23,12 +23,3 @@
# Needed for bazelci and for building distribution tarballs.
# If using an unreleased version of bazel_skylib via git_override, apply
# MODULE.bazel-remove-override.patch to remove the following lines:
Expand All @@ -9,8 +9,7 @@
- module_name = "bazel_skylib_gazelle_plugin",
- path = "gazelle",
-)
+# bazel_dep(name = "bazel_skylib_gazelle_plugin", dev_dependency = True)
+# local_path_override(
+# module_name = "bazel_skylib_gazelle_plugin",
+# path = "gazelle",
+# )
-local_path_override(
- module_name = "bazel_features",
- path = "bazel_features_stub",
-)
1 change: 1 addition & 0 deletions bazel_features_stub/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports_files(["features.bzl"])
5 changes: 5 additions & 0 deletions bazel_features_stub/MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module(
name = "bazel_features",
version = "0.0.0",
compatibility_level = 1,
)
Empty file added bazel_features_stub/WORKSPACE
Empty file.
10 changes: 10 additions & 0 deletions bazel_features_stub/features.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""
This is a stub for [bazel_features](https://github.com/bazel-contrib/bazel_features) used for
testing and updating docs.
"""

bazel_features = struct(
globals = struct(
RunEnvironmentInfo = RunEnvironmentInfo,
),
)
3 changes: 3 additions & 0 deletions docs/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ stardoc_with_diff_test(
name = "native_binary",
bzl_library_target = "//rules:native_binary",
out_label = "//docs:native_binary_doc.md",
deps = [
"@bazel_features//:features.bzl",
],
)

stardoc_with_diff_test(
Expand Down
7 changes: 7 additions & 0 deletions docs/maintainers_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@ load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
bazel_skylib_workspace()
```

***Additional WORKSPACE setup for `native_binary.bzl`***

```starlark
load("@bazel_features//:deps.bzl", "bazel_features_deps")
bazel_features_deps()
```

***Additional WORKSPACE setup for the Gazelle plugin***

```starlark
Expand Down
11 changes: 9 additions & 2 deletions docs/native_binary_doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ and test rule respectively. They fulfill the same goal as sh_binary and sh_test
do, but they run the wrapped binary directly, instead of through Bash, so they
don't depend on Bash and work with --shell_executable="".

If `bazel_skylib` is loaded from `WORKSPACE` rather than with bzlmod, using
this library requires additional `WORKSPACE` setup as explained in the
[release page](https://github.com/bazelbuild/bazel-skylib/releases).


<a id="native_binary"></a>

## native_binary

<pre>
native_binary(<a href="#native_binary-name">name</a>, <a href="#native_binary-data">data</a>, <a href="#native_binary-out">out</a>, <a href="#native_binary-src">src</a>)
native_binary(<a href="#native_binary-name">name</a>, <a href="#native_binary-data">data</a>, <a href="#native_binary-env">env</a>, <a href="#native_binary-out">out</a>, <a href="#native_binary-src">src</a>)
</pre>


Expand All @@ -30,6 +34,7 @@ in genrule.tools for example. You can also augment the binary with runfiles.
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="native_binary-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="native_binary-data"></a>data | data dependencies. See https://bazel.build/reference/be/common-definitions#typical.data | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | <code>[]</code> |
| <a id="native_binary-env"></a>env | additional environment variables to set when the target is executed by <code>bazel</code>. Setting this requires bazel version 5.3.0 or later. | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | <code>{}</code> |
| <a id="native_binary-out"></a>out | An output name for the copy of the binary | String | required | |
| <a id="native_binary-src"></a>src | path of the pre-built executable | <a href="https://bazel.build/concepts/labels">Label</a> | required | |

Expand All @@ -39,7 +44,7 @@ in genrule.tools for example. You can also augment the binary with runfiles.
## native_test

<pre>
native_test(<a href="#native_test-name">name</a>, <a href="#native_test-data">data</a>, <a href="#native_test-out">out</a>, <a href="#native_test-src">src</a>)
native_test(<a href="#native_test-name">name</a>, <a href="#native_test-data">data</a>, <a href="#native_test-env">env</a>, <a href="#native_test-env_inherit">env_inherit</a>, <a href="#native_test-out">out</a>, <a href="#native_test-src">src</a>)
</pre>


Expand All @@ -56,6 +61,8 @@ the binary with runfiles.
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="native_test-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="native_test-data"></a>data | data dependencies. See https://bazel.build/reference/be/common-definitions#typical.data | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | <code>[]</code> |
| <a id="native_test-env"></a>env | additional environment variables to set when the target is executed by <code>bazel</code>. Setting this requires bazel version 5.3.0 or later. | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | <code>{}</code> |
| <a id="native_test-env_inherit"></a>env_inherit | additional environment variables to inherit from the external environment when the test is executed by <code>bazel test</code>. Setting this requires bazel version 5.3.0 or later. | List of strings | optional | <code>[]</code> |
| <a id="native_test-out"></a>out | An output name for the copy of the binary | String | required | |
| <a id="native_test-src"></a>src | path of the pre-built executable | <a href="https://bazel.build/concepts/labels">Label</a> | required | |

Expand Down
6 changes: 4 additions & 2 deletions docs/private/stardoc_with_diff_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc")
def stardoc_with_diff_test(
name,
bzl_library_target,
out_label):
out_label,
deps = None):
"""Creates a stardoc target coupled with a `diff_test` for a given `bzl_library`.

This is helpful for minimizing boilerplate in repos with lots of stardoc targets.
Expand All @@ -39,6 +40,7 @@ def stardoc_with_diff_test(
name: the stardoc target name
bzl_library_target: the label of the `bzl_library` target to generate documentation for
out_label: the label of the output MD file
deps: additional files loaded by the bazel library, if any
"""
out_file = out_label.replace("//", "").replace(":", "/")

Expand All @@ -47,7 +49,7 @@ def stardoc_with_diff_test(
name = name,
out = out_file.replace(".md", "-docgen.md"),
input = bzl_library_target + ".bzl",
deps = [bzl_library_target],
deps = [bzl_library_target] + (deps or []),
)

# Ensure that the generated MD has been updated in the local source tree
Expand Down
48 changes: 42 additions & 6 deletions rules/native_binary.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,20 @@ These rules let you wrap a pre-built binary or script in a conventional binary
and test rule respectively. They fulfill the same goal as sh_binary and sh_test
do, but they run the wrapped binary directly, instead of through Bash, so they
don't depend on Bash and work with --shell_executable="".

If `bazel_skylib` is loaded from `WORKSPACE` rather than with bzlmod, using
this library requires additional `WORKSPACE` setup as explained in the
[release page](https://github.com/bazelbuild/bazel-skylib/releases).
"""

load("@bazel_features//:features.bzl", "bazel_features")

def _impl_rule(ctx):
if not bazel_features.globals.RunEnvironmentInfo:
for attr in ("env", "env_inherit"):
if getattr(ctx.attr, attr, None):
fail("Attribute %s specified for %s is only supported with bazel >= 5.3.0" %
(attr, ctx.label))
out = ctx.actions.declare_file(ctx.attr.out)
ctx.actions.symlink(
target_file = ctx.executable.src,
Expand All @@ -41,11 +52,21 @@ def _impl_rule(ctx):
runfiles = runfiles.merge(d[DefaultInfo].default_runfiles)
runfiles = runfiles.merge(ctx.attr.src[DefaultInfo].default_runfiles)

return DefaultInfo(
executable = out,
files = depset([out]),
runfiles = runfiles,
)
ret = [
DefaultInfo(
executable = out,
files = depset([out]),
runfiles = runfiles,
),
]
if bazel_features.globals.RunEnvironmentInfo:
ret.append(
bazel_features.globals.RunEnvironmentInfo(
environment = ctx.attr.env,
inherited_environment = getattr(ctx.attr, "env_inherit", []),
),
)
return ret

_ATTRS = {
"src": attr.label(
Expand All @@ -65,8 +86,23 @@ _ATTRS = {
),
# "out" is attr.string instead of attr.output, so that it is select()'able.
"out": attr.string(mandatory = True, doc = "An output name for the copy of the binary"),
"env": attr.string_dict(
doc = "additional environment variables to set when the target is executed by " +
"`bazel`. Setting this requires bazel version 5.3.0 or later.",
default = {},
),
}

_TEST_ATTRS = dict(
_ATTRS,
env_inherit = attr.string_list(
doc = "additional environment variables to inherit from the external " +
"environment when the test is executed by `bazel test`. " +
"Setting this requires bazel version 5.3.0 or later.",
default = [],
),
)

native_binary = rule(
implementation = _impl_rule,
attrs = _ATTRS,
Expand All @@ -81,7 +117,7 @@ in genrule.tools for example. You can also augment the binary with runfiles.

native_test = rule(
implementation = _impl_rule,
attrs = _ATTRS,
attrs = _TEST_ATTRS,
test = True,
doc = """
Wraps a pre-built binary or script with a test rule.
Expand Down
31 changes: 31 additions & 0 deletions tests/native_binary/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ cc_binary(
deps = ["@bazel_tools//tools/cpp/runfiles"],
)

cc_binary(
name = "assertenv",
srcs = ["assertenv.cc"],
)

# A rule that copies "assertarg"'s output as an opaque executable, simulating a
# binary that's not built from source and needs to be wrapped in native_binary.
copy_file(
Expand All @@ -54,6 +59,16 @@ copy_file(
is_executable = True,
)

copy_file(
name = "copy_assertenv_exe",
src = ":assertenv",
# On Windows we need the ".exe" extension.
# On other platforms the extension doesn't matter.
# Therefore we can use ".exe" on every platform.
out = "assertenv_copy.exe",
is_executable = True,
)

_ARGS = [
"'a b'",
"c\\ d",
Expand Down Expand Up @@ -115,3 +130,19 @@ native_test(
# Therefore we can use ".exe" on every platform.
out = "data_from_binary_test.exe",
)

native_test(
name = "env_test",
src = ":copy_assertenv_exe",
# On Windows we need the ".exe" extension.
# On other platforms the extension doesn't matter.
# Therefore we can use ".exe" on every platform.
out = "env_test.exe",
env = {
"TEST_ENV_VAR": "test_env_var_value",
},
env_inherit = [
"HOME", # for POSIX
"APPDATA", # for Windows
],
)
31 changes: 31 additions & 0 deletions tests/native_binary/assertenv.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <stdio.h>
#include <string.h>

#ifdef _WIN32
#define OS_VAR "APPDATA"
#define strncasecmp _strnicmp
#else
#define OS_VAR "HOME"
#endif

int main(int argc, char **argv, char **envp) {
bool test_env_found = false;
bool inherited_var_found = false;
for (char **env = envp; *env != NULL; ++env) {
printf("%s\n", *env);
if (strcmp(*env, "TEST_ENV_VAR=test_env_var_value") == 0) {
test_env_found = true;
}
if (strncasecmp(*env, OS_VAR "=", strlen(OS_VAR "=")) == 0) {
inherited_var_found = true;
}
}
if (!test_env_found) {
fprintf(stderr,
"expected TEST_ENV_VAR=test_env_var_value in environment\n");
}
if (!inherited_var_found) {
fprintf(stderr, "expected " OS_VAR " in environment\n");
}
return test_env_found && inherited_var_found ? 0 : 1;
}
9 changes: 9 additions & 0 deletions workspace.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,16 @@
"""Dependency registration helpers for repositories which need to load bazel-skylib."""

load("@bazel_skylib//lib:unittest.bzl", "register_unittest_toolchains")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")

def bazel_skylib_workspace():
"""Registers toolchains and declares repository dependencies of the bazel_skylib repository."""
register_unittest_toolchains()
maybe(
http_archive,
name = "bazel_features",
sha256 = "b8789c83c893d7ef3041d3f2795774936b27ff61701a705df52fd41d6ddbf692",
strip_prefix = "bazel_features-1.2.0",
url = "https://github.com/bazel-contrib/bazel_features/releases/download/v1.2.0/bazel_features-v1.2.0.tar.gz",
)