Skip to content

Commit 8d69865

Browse files
fmeumavdv
authored andcommitted
Use runfiles wrapper
1 parent 9d16f12 commit 8d69865

File tree

4 files changed

+59
-83
lines changed

4 files changed

+59
-83
lines changed

sh/posix.bzl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,10 @@ def _sh_posix_make_variables_impl(ctx):
7777
toolchain.sh_binaries_info,
7878
)
7979

80+
executable = ctx.actions.declare_file(ctx.label.name)
8081
default_info = mk_default_info_with_files_to_run(
8182
ctx,
82-
ctx.label.name,
83+
executable,
8384
toolchain.tool[DefaultInfo].files,
8485
toolchain.tool[DefaultInfo].default_runfiles,
8586
)

sh/private/defs.bzl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,11 @@ def mk_template_variable_info(name, sh_binaries_info):
3131
},
3232
))
3333

34-
def mk_default_info_with_files_to_run(ctx, name, files, runfiles):
34+
def mk_default_info_with_files_to_run(ctx, executable, files, runfiles):
3535
# Create a dummy executable to trigger the generation of a FilesToRun
3636
# provider which can be used in custom rules depending on this bundle to
3737
# input the needed runfiles into build actions.
3838
# This is a workaround for https://github.com/bazelbuild/bazel/issues/15486
39-
executable = ctx.actions.declare_file(name)
4039
ctx.actions.write(executable, "", is_executable = True)
4140
return DefaultInfo(
4241
executable = executable,

sh/sh.bzl

Lines changed: 54 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,37 @@ ShBinariesInfo = provider(
1717

1818
_WINDOWS_EXE_EXTENSIONS = [".exe", ".cmd", ".bat", ".ps1"]
1919

20-
def _sh_binaries_from_srcs(ctx, srcs, is_windows):
20+
_POSIX_WRAPPER_TEMPLATE = """\
21+
#!/bin/sh
22+
if [[ -z ${{RUNFILES_MANIFEST_FILE+x}} && -z ${{RUNFILES_DIR+x}} ]]; then
23+
if [[ -f "{main_executable}.runfiles_manifest" ]]; then
24+
export RUNFILES_MANIFEST_FILE="{main_executable}.runfiles_manifest"
25+
elif [[ -d "{main_executable}.runfiles" ]]; then
26+
export RUNFILES_DIR="{main_executable}.runfiles"
27+
else
28+
echo "ERROR: Runfiles not found for bundle {main_executable}" >&2
29+
exit 1
30+
fi
31+
fi
32+
exec "{original_executable}" "$@"
33+
"""
34+
35+
_WINDOWS_WRAPPER_TEMPLATE = """\
36+
@echo off
37+
if not defined RUNFILES_MANIFEST_FILE if not defined RUNFILES_DIR (
38+
if exist "{main_executable}.runfiles_manifest" (
39+
set RUNFILES_MANIFEST_FILE="{main_executable}.runfiles_manifest"
40+
) else if exist "{main_executable}.runfiles" (
41+
set RUNFILES_DIR="{main_executable}.runfiles"
42+
) else (
43+
echo ERROR: Runfiles not found for bundle {main_executable} >&2
44+
exit /b 1
45+
)
46+
)
47+
"{original_executable}" %*
48+
"""
49+
50+
def _sh_binaries_from_srcs(ctx, srcs, is_windows, main_executable):
2151
executable_files = []
2252
runfiles = ctx.runfiles()
2353
executables_dict = dict()
@@ -27,10 +57,10 @@ def _sh_binaries_from_srcs(ctx, srcs, is_windows):
2757
if src[DefaultInfo].files_to_run == None or src[DefaultInfo].files_to_run.executable == None:
2858
fail("srcs must be executable, but '{}' is not.".format(src.label))
2959

30-
executable = src[DefaultInfo].files_to_run.executable
31-
name = executable.basename
60+
original_executable = src[DefaultInfo].files_to_run.executable
61+
name = original_executable.basename
3262
if is_windows:
33-
(noext, ext) = paths.split_extension(executable.basename)
63+
(noext, ext) = paths.split_extension(original_executable.basename)
3464
if ext in _WINDOWS_EXE_EXTENSIONS:
3565
name = noext
3666

@@ -41,8 +71,21 @@ def _sh_binaries_from_srcs(ctx, srcs, is_windows):
4171
src.label,
4272
))
4373

74+
if src[DefaultInfo].default_runfiles:
75+
executable = ctx.actions.declare_file(ctx.label.name + ".path/" + (name + ".bat" if is_windows else name))
76+
ctx.actions.write(
77+
executable,
78+
(_WINDOWS_WRAPPER_TEMPLATE if is_windows else _POSIX_WRAPPER_TEMPLATE).format(
79+
main_executable = main_executable.path,
80+
original_executable = original_executable.path,
81+
),
82+
is_executable = True,
83+
)
84+
executable_files.append(original_executable)
85+
runfiles = runfiles.merge(src[DefaultInfo].default_runfiles)
86+
else:
87+
executable = original_executable
4488
executable_files.append(executable)
45-
runfiles = runfiles.merge(src[DefaultInfo].default_runfiles)
4689
executables_dict[name] = executable
4790
executable_paths.append(executable.dirname)
4891

@@ -64,6 +107,9 @@ def _sh_binaries_from_deps(ctx, deps):
64107
fail("deps must be sh_binaries targets, but '{}' is not.".format(dep.label))
65108

66109
executable_files.append(dep[DefaultInfo].files)
110+
# TODO: Handle tools with runfiles in deps correctly. They need to be wrapped in a new
111+
# wrapper script as in _sh_binaries_from_srcs since the dummy executable they reference
112+
# is no longer the sibling of the runfiles tree.
67113
runfiles = runfiles.merge(dep[DefaultInfo].default_runfiles)
68114
executables_dict.update(dep[ShBinariesInfo].executables)
69115
executable_paths.append(dep[ShBinariesInfo].paths)
@@ -101,15 +147,16 @@ def _mk_sh_binaries_info(direct, transitive):
101147

102148
def _sh_binaries_impl(ctx):
103149
is_windows = ctx.attr._is_windows[ConstantInfo].value
104-
direct = _sh_binaries_from_srcs(ctx, ctx.attr.srcs, is_windows)
150+
executable = ctx.actions.declare_file(ctx.label.name)
151+
direct = _sh_binaries_from_srcs(ctx, ctx.attr.srcs, is_windows, executable)
105152
transitive = _sh_binaries_from_deps(ctx, ctx.attr.deps)
106153
data_runfiles = _runfiles_from_data(ctx, ctx.attr.data)
107154

108155
sh_binaries_info = _mk_sh_binaries_info(direct, transitive)
109156
template_variable_info = mk_template_variable_info(ctx.label.name, sh_binaries_info)
110157
default_info = mk_default_info_with_files_to_run(
111158
ctx,
112-
ctx.label.name,
159+
executable,
113160
depset(direct = direct.executable_files, transitive = transitive.executable_files),
114161
direct.runfiles.merge(transitive.runfiles).merge(data_runfiles),
115162
)
@@ -283,58 +330,5 @@ def _custom_rule_impl(ctx):
283330
...
284331
)
285332
```
286-
287-
*Caveat: Using Binaries that require Runfiles*
288-
289-
Note, support for binaries that require runfiles is limited due to limitations
290-
imposed by Bazel's Starlark API, see [#15486][issue-15486]. In order for these
291-
to work you will need to define the `RUNFILES_DIR` or `RUNFILES_MANIFEST_FILE`
292-
environment variables for the action using tools from the bundle.
293-
294-
(Use `RUNFILES_MANIFEST_FILE` if your operating system and configuration does
295-
not support a runfiles tree and instead only provides a runfiles manifest file,
296-
as is commonly the case on Windows.)
297-
298-
You can achieve this in a `genrule` as follows:
299-
300-
```bzl
301-
genrule(
302-
name = "runfiles-genrule",
303-
toolchains = [":a-bundle"],
304-
cmd = "\\n".join([
305-
# The explicit RUNFILES_DIR/RUNFILES_MANIFEST_FILE is a workaround for
306-
# https://github.com/bazelbuild/bazel/issues/15486
307-
"RUNFILES_DIR=$(execpath :a-bundle).runfiles",
308-
"RUNFILES_MANIFEST_FILE=$(execpath :a-bundle).runfiles_manifest",
309-
"$(A_BUNDLE_BINARY_A)",
310-
"$(A_BUNDLE_BINARY_B)",
311-
]),
312-
outs = [...],
313-
)
314-
```
315-
316-
And in a custom rule as follows:
317-
318-
```bzl
319-
def _custom_rule_impl(ctx):
320-
tools = ctx.attr.tools[ShBinariesInfo]
321-
(tools_inputs, tools_manifest) = ctx.resolve_tools(tools = [ctx.attr.tools])
322-
# The explicit RUNFILES_DIR/RUNFILES_MANIFEST_FILE is a workaround for
323-
# https://github.com/bazelbuild/bazel/issues/15486
324-
tools_env = {
325-
"RUNFILES_DIR": ctx.attr.tools[DefaultInfo].files_to_run.runfiles_manifest.dirname,
326-
"RUNFILES_MANIFEST_FILE": ctx.attr.tools[DefaultInfo].files_to_run.runfiles_manifest.path,
327-
}
328-
329-
ctx.actions.run(
330-
executable = tools.executables["binary-a"],
331-
env = tools_env, # Pass the environment into the action.
332-
inputs = tools_inputs,
333-
input_manifests = tools_manifest,
334-
...
335-
)
336-
```
337-
338-
[issue-15486]: https://github.com/bazelbuild/bazel/issues/15486
339333
""",
340334
)

tests/sh_binaries/sh_binaries_test.bzl

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -571,29 +571,11 @@ def _test_genrule():
571571
],
572572
cmd = """\
573573
$(GENRULE_BUNDLE_HELLO_WORLD) >$(execpath genrule_output_world)
574-
575-
IS_WINDOWS=
576-
case "$$OSTYPE" in
577-
cygwin|msys|win32) IS_WINDOWS=1;;
578-
esac
579-
580-
with_runfiles() {
581-
# The explicit RUNFILES_DIR|RUNFILES_MANIFEST_FILE is a workaround for
582-
# https://github.com/bazelbuild/bazel/issues/15486
583-
if [[ -n $$IS_WINDOWS ]]; then
584-
RUNFILES_MANIFEST_FILE=$(execpath :genrule_bundle).runfiles_manifest \\
585-
eval "$$@"
586-
else
587-
RUNFILES_DIR=$(execpath :genrule_bundle).runfiles \\
588-
eval "$$@"
589-
fi
590-
}
591-
592-
with_runfiles $(GENRULE_BUNDLE_HELLO_DATA) >$(execpath genrule_output_data)
574+
$(GENRULE_BUNDLE_HELLO_DATA) >$(execpath genrule_output_data)
593575
594576
PATH="$(_GENRULE_BUNDLE_PATH):$$PATH"
595577
hello_world >$(execpath genrule_output_by_path)
596-
with_runfiles hello_data >>$(execpath genrule_output_by_path)
578+
hello_data >>$(execpath genrule_output_by_path)
597579
""",
598580
toolchains = [":genrule_bundle"],
599581
)

0 commit comments

Comments
 (0)