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 e2dce55
Show file tree
Hide file tree
Showing 13 changed files with 242 additions and 135 deletions.
26 changes: 24 additions & 2 deletions .bazelci/presubmit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ 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
- "//..."
- "-//crate_universe/..."
- "-//test/proto/..."
- "-//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 @@ -78,6 +86,11 @@ tasks:
windows:
build_targets: *default_windows_targets
test_targets: *default_windows_targets
windows_no_runfiles:
build_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 @@ -171,6 +184,15 @@ 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"
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 Expand Up @@ -610,7 +632,7 @@ tasks:
environment:
# This ndk version matches with rules_android_ndk repo's CI
# https://github.com/bazelbuild/rules_android_ndk/blob/877c68ef34c9f3353028bf490d269230c1990483/.bazelci/presubmit.yml#L37
# The ndk is installed by this script
# The ndk is installed by this script
# https://github.com/bazelbuild/continuous-integration/blob/ba56013373821feadd9f2eaa6b81eb19528795f0/macos/mac-android.sh
ANDROID_NDK_HOME: /opt/android-ndk-r25b
android_examples_macos:
Expand All @@ -625,7 +647,7 @@ tasks:
environment:
# This ndk version matches with rules_android_ndk repo's CI
# https://github.com/bazelbuild/rules_android_ndk/blob/877c68ef34c9f3353028bf490d269230c1990483/.bazelci/presubmit.yml#L42
# The ndk is installed by this script
# The ndk is installed by this script
# https://github.com/bazelbuild/continuous-integration/blob/ba56013373821feadd9f2eaa6b81eb19528795f0/macos/mac-android.sh
ANDROID_NDK_HOME: /Users/buildkite/android-ndk-r25b
ios_examples:
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"],
)
55 changes: 52 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,39 @@ 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.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 @@ -215,9 +249,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 +423,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 +564,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"],
)
71 changes: 71 additions & 0 deletions cargo/private/runfiles_maker/runfiles_maker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//! 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 args_file = std::env::args().nth(1).expect("No args file was passed.");

let content = std::fs::read_to_string(
args_file
.strip_prefix("@")
.expect("Param files should start with @"),
)
.unwrap();
let mut args = content.lines();

let output_dir = PathBuf::from(
args.next()
.unwrap_or_else(|| panic!("Not enough arguments provided.")),
);
let runfiles = args
.map(|s| {
let s = if s.starts_with("'") && s.ends_with("'") {
s.trim_matches('\'')
} else {
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).unwrap_or_else(|e| {
panic!(
"Failed to copy file {} -> {}\n{:?}",
src.display(),
out_dest.display(),
e
)
});
}
}
8 changes: 4 additions & 4 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Note that rules_rust bzlmod support is still a work in progress. Most features s
To use `rules_rust` in a project using bzlmod, add the following to your `MODULE.bazel` file:

```python
bazel_dep(name = "rules_rust", version = "0.48.0")
bazel_dep(name = "rules_rust", version = "0.50.1")
```

Don't forget to substitute in your desired release's version number.
Expand All @@ -36,8 +36,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# https://github.com/bazelbuild/rules_rust/releases
http_archive(
name = "rules_rust",
integrity = "sha256-Weev1uz2QztBlDA88JX6A1N72SucD1V8lBsaliM0TTg=",
urls = ["https://github.com/bazelbuild/rules_rust/releases/download/0.48.0/rules_rust-v0.48.0.tar.gz"],
integrity = "sha256-Log/YgrGjboS4tCqQPBA58VPyFcnCn/IZm+xxKTZrn0=",
urls = ["https://github.com/bazelbuild/rules_rust/releases/download/0.50.1/rules_rust-v0.50.1.tar.gz"],
)

load("@rules_rust//rust:repositories.bzl", "rules_rust_dependencies", "rust_register_toolchains")
Expand All @@ -57,7 +57,7 @@ To build with a particular version of the Rust compiler, pass that version to [`
rust_register_toolchains(
edition = "2021",
versions = [
"1.79.0"
"1.79.0",
],
)
```
Expand Down
25 changes: 0 additions & 25 deletions examples/crate_universe/cargo_aliases/.bazelrc

This file was deleted.

Loading

0 comments on commit e2dce55

Please sign in to comment.