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 14, 2024
1 parent 30df2ef commit 144d696
Show file tree
Hide file tree
Showing 14 changed files with 192 additions and 146 deletions.
7 changes: 0 additions & 7 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@
## https://bazel.build/docs/best-practices#bazelrc-file
###############################################################################

# https://bazel.build/reference/command-line-reference#flag--enable_platform_specific_config
common --enable_platform_specific_config

# https://bazel.build/docs/windows#symlink
startup --windows_enable_symlinks
build:windows --enable_runfiles

# Enable the only currently supported report type
# https://bazel.build/reference/command-line-reference#flag--combined_report
coverage --combined_report=lcov
Expand Down
4 changes: 0 additions & 4 deletions .github/github.bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
# Always display the flags being used
common --announce_rc

# These settings make the windows workers behave similarly to unix workers
startup --windows_enable_symlinks
build --enable_runfiles

# Show errors in CI
test --test_output=errors

Expand Down
4 changes: 3 additions & 1 deletion cargo/cargo_build_script_runner/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ impl BuildScriptOutput {
pub fn outputs_from_command(
cmd: &mut Command,
) -> Result<(Vec<BuildScriptOutput>, Output), Output> {
let child_output = cmd.output().expect("Unable to start binary");
let child_output = cmd
.output()
.unwrap_or_else(|_| panic!("Unable to start command:\n{:#?}", cmd));
if child_output.status.success() {
let reader = BufReader::new(child_output.stdout.as_slice());
let output = Self::outputs_from_reader(reader);
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"],
)
54 changes: 51 additions & 3 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))

workspace_name = ctx.label.workspace_name
if not workspace_name:
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.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 @@ -215,9 +248,20 @@ def _cargo_build_script_impl(ctx):
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

build_script_inputs = []

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

manifest_dir = "{}.runfiles/{}/{}".format(script.path, workspace_name, ctx.label.package)
if not is_runfiles_enabled(ctx.attr):
runfiles_dir = _create_runfiles_dir(ctx, ctx.attr.script)
build_script_inputs.append(runfiles_dir)
manifest_dir = "{}/{}/{}".format(runfiles_dir.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 @@ -378,7 +422,6 @@ def _cargo_build_script_impl(ctx):
args.add(streams.stderr)
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 +563,12 @@ 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(),
fragments = ["cpp"],
toolchains = [
str(Label("//rust:toolchain_type")),
Expand Down
74 changes: 74 additions & 0 deletions cargo/private/runfiles_enabled.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""A small utility module dedicated to detecting whether or not the `--enable_runfiles` and `--windows_enable_symlinks` flag are enabled
"""

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 = Label("//cargo/private:runfiles_enabled")):
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):
native.config_setting(
name = "{}_enable_runfiles".format(name),
values = {"enable_runfiles": "true"},
)

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

runfiles_enabled_setting(
name = name,
value = select({
# If either of the runfiles are set, use the flag
":{}_enable_runfiles".format(name): True,
":{}_disable_runfiles".format(name): False,
# Otherwise fall back to the system default.
"@platforms//os:windows": False,
"//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"],
)
50 changes: 50 additions & 0 deletions cargo/private/runfiles_maker/runfiles_maker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//! A tool for building runfiles directories for Bazel environments that don't
//! support runfiles or have runfiles enabled.
use std::collections::BTreeMap;
use std::path::PathBuf;

struct Args {
pub output_dir: PathBuf,
pub runfiles: BTreeMap<PathBuf, PathBuf>,
}

impl Args {
fn parse() -> Self {
let mut args = std::env::args().skip(1);
let output_dir = PathBuf::from(
args.next()
.unwrap_or_else(|| panic!("Not enough arguments provided.")),
);
let runfiles = args
.map(|s| {
let (src, dest) = s
.split_once('=')
.unwrap_or_else(|| panic!("Unexpected runfiles argument: {}", s));
(PathBuf::from(src), PathBuf::from(dest))
})
.collect::<BTreeMap<_, _>>();

assert!(!runfiles.is_empty(), "No runfiles found");

Args {
output_dir,
runfiles,
}
}
}

fn main() {
let args = Args::parse();

for (src, dest) in args.runfiles.iter() {
let out_dest = args.output_dir.join(dest);
std::fs::create_dir_all(
out_dest
.parent()
.expect("The output location should have a valid parent."),
)
.expect("Failed to create output directory");
std::fs::copy(src, out_dest).expect("Failed to copy file");
}
}
6 changes: 0 additions & 6 deletions examples/crate_universe/.bazelrc
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
# `.bazelrc` is a Bazel configuration file.
# https://bazel.build/docs/best-practices#bazelrc-file

# Required on windows
common --enable_platform_specific_config
startup --windows_enable_symlinks
build:windows --enable_runfiles

# Enable rustfmt for all targets in the workspace
build:rustfmt --aspects=@rules_rust//rust:defs.bzl%rustfmt_aspect
build:rustfmt --output_groups=+rustfmt_checks
Expand All @@ -31,4 +26,3 @@ build --incompatible_merge_fixed_and_default_shell_env
# This import should always be last to allow users to override
# settings for local development.
try-import %workspace%/user.bazelrc

25 changes: 0 additions & 25 deletions examples/crate_universe/cargo_aliases/.bazelrc

This file was deleted.

25 changes: 0 additions & 25 deletions examples/crate_universe/cargo_remote/.bazelrc

This file was deleted.

25 changes: 0 additions & 25 deletions examples/crate_universe/cargo_workspace/.bazelrc

This file was deleted.

25 changes: 0 additions & 25 deletions examples/crate_universe/multi_package/.bazelrc

This file was deleted.

Loading

0 comments on commit 144d696

Please sign in to comment.