Skip to content

Commit

Permalink
Update cargo_build_script to work without runfiles support.
Browse files Browse the repository at this point in the history
  • Loading branch information
UebelAndre committed Sep 19, 2024
1 parent 5a8b98d commit 31cdc0f
Show file tree
Hide file tree
Showing 8 changed files with 388 additions and 24 deletions.
37 changes: 37 additions & 0 deletions .bazelci/presubmit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,21 @@ default_windows_targets: &default_windows_targets
- "//..."
- "-//test/proto/..."
- "-//test/unit/pipelined_compilation/..."
default_windows_no_runfiles_targets: &default_windows_no_runfiles_targets
- "--" # Allows negative patterns; hack for https://github.com/bazelbuild/continuous-integration/pull/245
- "//..."
# TODO: https://github.com/bazelbuild/rules_rust/issues/1156
- "-//crate_universe/..."
- "-//test/chained_direct_deps:mod3_doc_test"
- "-//test/out_dir_in_tests:demo_lib_doc_test"
- "-//test/proto/..."
- "-//test/rustc_env_files:output_test"
- "-//test/test_env_launcher:test"
- "-//test/test_env:test_manifest_dir"
- "-//test/test_env:test_run"
- "-//test/unit/pipelined_compilation/..."
- "-//test/unit/rustdoc/..."
- "-//tools/runfiles/..."
crate_universe_vendor_example_targets: &crate_universe_vendor_example_targets
- "//vendor_external:crates_vendor"
- "//vendor_local_manifests:crates_vendor"
Expand Down Expand Up @@ -82,6 +97,15 @@ tasks:
platform: windows
build_targets: *default_windows_targets
test_targets: *default_windows_targets
windows_no_runfiles:
name: No Runfiles
platform: windows
build_flags:
- "--noenable_runfiles"
test_flags:
- "--noenable_runfiles"
build_targets: *default_windows_no_runfiles_targets
test_targets: *default_windows_no_runfiles_targets
ubuntu2004_split_coverage_postprocessing:
name: Split Coverage Postprocessing
platform: ubuntu2004
Expand Down Expand Up @@ -175,6 +199,19 @@ tasks:
- "--config=clippy"
build_targets: *default_windows_targets
test_targets: *default_windows_targets
windows_no_runfiles_with_aspects:
name: No Runfiles With Aspects
platform: windows
build_flags:
- "--noenable_runfiles"
- "--config=rustfmt"
- "--config=clippy"
test_flags:
- "--noenable_runfiles"
- "--config=rustfmt"
- "--config=clippy"
build_targets: *default_windows_no_runfiles_targets
test_targets: *default_windows_no_runfiles_targets
windows_rolling_with_aspects:
name: "Windows Rolling Bazel Version With Aspects"
platform: windows
Expand Down
6 changes: 6 additions & 0 deletions cargo/private/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load(":runfiles_enabled.bzl", "runfiles_enabled_build_setting")

bzl_library(
name = "bzl_lib",
srcs = glob(["**/*.bzl"]),
visibility = ["//:__subpackages__"],
)

runfiles_enabled_build_setting(
name = "runfiles_enabled",
visibility = ["//visibility:public"],
)
77 changes: 64 additions & 13 deletions cargo/private/cargo_build_script.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ load(
"find_toolchain",
_name_to_crate_name = "name_to_crate_name",
)
load(":runfiles_enabled.bzl", "is_runfiles_enabled", "runfiles_enabled_attr")

# Reexport for cargo_build_script_wrapper.bzl
name_to_crate_name = _name_to_crate_name
Expand Down Expand Up @@ -198,6 +199,38 @@ def _feature_enabled(ctx, feature_name, default = False):

return default

def _rlocationpath(file, workspace_name):
if file.short_path.startswith("../"):
return file.short_path[len("../"):]

return "{}/{}".format(workspace_name, file.short_path)

def _create_runfiles_dir(ctx, script):
runfiles_dir = ctx.actions.declare_directory("{}.cargo_runfiles".format(ctx.label.name))

# External repos always fall into the `../` branch of `_rlocationpath`.
workspace_name = ctx.workspace_name

def _runfiles_map(file):
return "{}={}".format(file.path, _rlocationpath(file, workspace_name))

runfiles = script[DefaultInfo].default_runfiles

args = ctx.actions.args()
args.use_param_file("@%s", use_always = True)
args.add(runfiles_dir.path)
args.add_all(runfiles.files, map_each = _runfiles_map, allow_closure = True)

ctx.actions.run(
mnemonic = "CargoBuildScriptRunfilesDir",
executable = ctx.executable._runfiles_maker,
arguments = [args],
inputs = runfiles.files,
outputs = [runfiles_dir],
)

return runfiles_dir

def _cargo_build_script_impl(ctx):
"""The implementation for the `cargo_build_script` rule.
Expand All @@ -208,16 +241,37 @@ def _cargo_build_script_impl(ctx):
list: A list containing a BuildInfo provider
"""
script = ctx.executable.script
script_info = ctx.attr.script[CargoBuildScriptRunfilesInfo]
toolchain = find_toolchain(ctx)
out_dir = ctx.actions.declare_directory(ctx.label.name + ".out_dir")
env_out = ctx.actions.declare_file(ctx.label.name + ".env")
dep_env_out = ctx.actions.declare_file(ctx.label.name + ".depenv")
flags_out = ctx.actions.declare_file(ctx.label.name + ".flags")
link_flags = ctx.actions.declare_file(ctx.label.name + ".linkflags")
link_search_paths = ctx.actions.declare_file(ctx.label.name + ".linksearchpaths") # rustc-link-search, propagated from transitive dependencies
manifest_dir = "%s.runfiles/%s/%s" % (script.path, ctx.label.workspace_name or ctx.workspace_name, ctx.label.package)
compilation_mode_opt_level = get_compilation_mode_opts(ctx, toolchain).opt_level

script_tools = []
script_data = []
for target in script_info.data:
script_data.append(target[DefaultInfo].files)
script_data.append(target[DefaultInfo].default_runfiles.files)
for target in script_info.tools:
script_tools.append(target[DefaultInfo].files)
script_tools.append(target[DefaultInfo].default_runfiles.files)

workspace_name = ctx.label.workspace_name
if not workspace_name:
workspace_name = ctx.workspace_name

if not is_runfiles_enabled(ctx.attr):
runfiles_dir = _create_runfiles_dir(ctx, ctx.attr.script)
script_data.append(depset([runfiles_dir]))
manifest_dir = "{}/{}/{}".format(runfiles_dir.path, workspace_name, ctx.label.package)
else:
script_data.append(ctx.attr.script[DefaultInfo].default_runfiles.files)
manifest_dir = "{}.runfiles/{}/{}".format(script.path, workspace_name, ctx.label.package)

streams = struct(
stdout = ctx.actions.declare_file(ctx.label.name + ".stdout.log"),
stderr = ctx.actions.declare_file(ctx.label.name + ".stderr.log"),
Expand Down Expand Up @@ -331,8 +385,6 @@ def _cargo_build_script_impl(ctx):
variables = getattr(target[platform_common.TemplateVariableInfo], "variables", depset([]))
env.update(variables)

script_info = ctx.attr.script[CargoBuildScriptRunfilesInfo]

_merge_env_dict(env, expand_dict_value_locations(
ctx,
ctx.attr.build_script_env,
Expand All @@ -343,15 +395,6 @@ def _cargo_build_script_impl(ctx):
script_info.tools,
))

script_tools = []
script_data = []
for target in script_info.data:
script_data.append(target[DefaultInfo].files)
script_data.append(target[DefaultInfo].default_runfiles.files)
for target in script_info.tools:
script_tools.append(target[DefaultInfo].files)
script_tools.append(target[DefaultInfo].default_runfiles.files)

tools = depset(
direct = [
script,
Expand Down Expand Up @@ -379,6 +422,7 @@ def _cargo_build_script_impl(ctx):
args.add(ctx.attr.rundir)

build_script_inputs = []

for dep in ctx.attr.link_deps:
if rust_common.dep_info in dep and dep[rust_common.dep_info].dep_env:
dep_env_file = dep[rust_common.dep_info].dep_env
Expand Down Expand Up @@ -520,7 +564,14 @@ cargo_build_script = rule(
"_experimental_symlink_execroot": attr.label(
default = Label("//cargo/settings:experimental_symlink_execroot"),
),
},
"_runfiles_maker": attr.label(
cfg = "exec",
executable = True,
default = Label("//cargo/private/runfiles_maker"),
),
} | runfiles_enabled_attr(
default = Label("//cargo/private:runfiles_enabled"),
),
fragments = ["cpp"],
toolchains = [
str(Label("//rust:toolchain_type")),
Expand Down
167 changes: 167 additions & 0 deletions cargo/private/runfiles_enabled.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
"""A small utility module dedicated to detecting whether or not the `--enable_runfiles` and `--windows_enable_symlinks` flag are enabled
"""

load("@bazel_skylib//lib:selects.bzl", "selects")
load("@bazel_skylib//rules:common_settings.bzl", "bool_setting")

RunfilesEnabledInfo = provider(
doc = "A singleton provider that contains the raw value of a build setting",
fields = {
"value": "The value of the build setting in the current configuration. " +
"This value may come from the command line or an upstream transition, " +
"or else it will be the build setting's default.",
},
)

def _runfiles_enabled_setting_impl(ctx):
return RunfilesEnabledInfo(value = ctx.attr.value)

runfiles_enabled_setting = rule(
implementation = _runfiles_enabled_setting_impl,
doc = "A bool-typed build setting that cannot be set on the command line",
attrs = {
"value": attr.bool(
doc = "A boolean value",
mandatory = True,
),
},
)

_RUNFILES_ENABLED_ATTR_NAME = "_runfiles_enabled"

def runfiles_enabled_attr(default):
return {
_RUNFILES_ENABLED_ATTR_NAME: attr.label(
doc = "A flag representing whether or not runfiles are enabled.",
providers = [RunfilesEnabledInfo],
default = default,
cfg = "exec",
),
}

def runfiles_enabled_build_setting(name, **kwargs):
"""Define a build setting identifying if runfiles are enabled.
Args:
name (str): The name of the build setting
**kwargs: Additional keyword arguments for the target.
"""
native.config_setting(
name = "{}__enable_runfiles".format(name),
values = {"enable_runfiles": "true"},
)

native.config_setting(
name = "{}__disable_runfiles".format(name),
values = {"enable_runfiles": "false"},
)

bool_setting(
name = "{}__always_true".format(name),
build_setting_default = True,
)

native.config_setting(
name = "{}__always_true_setting".format(name),
flag_values = {":{}__always_true".format(name): "True"},
)

native.config_setting(
name = "{}__always_false_setting".format(name),
flag_values = {":{}__always_true".format(name): "False"},
)

# There is no way to query a setting that is unset. By utilizing constant
# settings, we can filter to a fallback setting where no known value is
# defined.
native.alias(
name = "{}__unset_runfiles".format(name),
actual = select({
":{}__disable_runfiles".format(name): ":{}__always_false_setting".format(name),
":{}__enable_runfiles".format(name): ":{}__always_false_setting".format(name),
"//conditions:default": ":{}__always_true_setting".format(name),
}),
)

selects.config_setting_group(
name = "{}__windows_enable_runfiles".format(name),
match_all = [
":{}__enable_runfiles".format(name),
"@platforms//os:windows",
],
)

selects.config_setting_group(
name = "{}__windows_disable_runfiles".format(name),
match_all = [
":{}__disable_runfiles".format(name),
"@platforms//os:windows",
],
)

selects.config_setting_group(
name = "{}__windows_unset_runfiles".format(name),
match_all = [
":{}__unset_runfiles".format(name),
"@platforms//os:windows",
],
)

native.alias(
name = "{}__unix".format(name),
actual = select({
"@platforms//os:windows": ":{}__always_false_setting".format(name),
"//conditions:default": ":{}__always_true_setting".format(name),
}),
)

selects.config_setting_group(
name = "{}__unix_enable_runfiles".format(name),
match_all = [
":{}__enable_runfiles".format(name),
":{}__unix".format(name),
],
)

selects.config_setting_group(
name = "{}__unix_disable_runfiles".format(name),
match_all = [
":{}__disable_runfiles".format(name),
":{}__unix".format(name),
],
)

selects.config_setting_group(
name = "{}__unix_unset_runfiles".format(name),
match_all = [
":{}__unset_runfiles".format(name),
":{}__unix".format(name),
],
)

runfiles_enabled_setting(
name = name,
value = select({
":{}__windows_enable_runfiles".format(name): True,
":{}__windows_disable_runfiles".format(name): False,
":{}__windows_unset_runfiles".format(name): False,
":{}__unix_enable_runfiles".format(name): True,
":{}__unix_disable_runfiles".format(name): False,
":{}__unix_unset_runfiles".format(name): True,
"//conditions:default": True,
}),
**kwargs
)

def is_runfiles_enabled(attr):
"""Determine whether or not runfiles are enabled.
Args:
attr (struct): A rule's struct of attributes (`ctx.attr`)
Returns:
bool: The enable_runfiles value.
"""

runfiles_enabled = getattr(attr, _RUNFILES_ENABLED_ATTR_NAME, None)

return runfiles_enabled[RunfilesEnabledInfo].value if runfiles_enabled else True
8 changes: 8 additions & 0 deletions cargo/private/runfiles_maker/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
load("//rust:defs.bzl", "rust_binary")

rust_binary(
name = "runfiles_maker",
srcs = ["runfiles_maker.rs"],
edition = "2021",
visibility = ["//visibility:public"],
)
Loading

0 comments on commit 31cdc0f

Please sign in to comment.