Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions rust/private/common.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ def _create_crate_info(**kwargs):
kwargs.update({"rustc_env_files": []})
if not "data" in kwargs:
kwargs.update({"data": depset([])})
if not "root_path" in kwargs:
kwargs.update({"root_path": ""})
return CrateInfo(**kwargs)

rust_common = struct(
Expand Down
1 change: 1 addition & 0 deletions rust/private/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ CrateInfo = provider(
"owner": "Label: The label of the target that produced this CrateInfo",
"proc_macro_deps": "depset[DepVariantInfo]: This crate's rust proc_macro dependencies' providers.",
"root": "File: The source File entrypoint to this crate, eg. lib.rs",
"root_path": "str: If root is a directory, path to the source entrypoint under it.",
"rustc_env": "Dict[String, String]: Additional `\"key\": \"value\"` environment variables to set for rustc.",
"rustc_env_files": "[File]: Files containing additional environment variables to set for rustc.",
"rustc_output": "File: The output from rustc from producing the output file. It is optional.",
Expand Down
34 changes: 34 additions & 0 deletions rust/private/rust.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,27 @@ def _rust_proc_macro_impl(ctx):
"""
return _rust_library_common(ctx, "proc-macro")

def _validate_root_path(ctx):
"""Validates that root_path is used iff there is no explicit crate_root and srcs is a single-element directory artifact."""
if getattr(ctx.attr, "crate", None):
if getattr(ctx.attr, "root_path", ""):
fail("rust_test.crate and rust_test.root_path are mutually exclusive.")
return

explicit_crate_root = getattr(ctx.file, "crate_root", None) != None
if explicit_crate_root and ctx.file.crate_root.is_directory:
fail("`crate_root` must be a file, not a directory. If you want to use a directory artifact as source, use `srcs` and `root_path` instead.")

srcs = ctx.files.srcs
is_single_dir = len(srcs) == 1 and srcs[0].is_directory
should_use_root_path = (not explicit_crate_root) and is_single_dir
has_root_path = bool(getattr(ctx.attr, "root_path", ""))

if should_use_root_path and not has_root_path:
fail("`root_path` must be specified when `srcs` is a single directory artifact and `crate_root` is not set.")
elif not should_use_root_path and has_root_path:
fail("`root_path` can only be used when `crate_root` is not set and `srcs` is a single directory artifact.")

def _rust_library_common(ctx, crate_type):
"""The common implementation of the library-like rules.

Expand All @@ -198,6 +219,7 @@ def _rust_library_common(ctx, crate_type):
Returns:
list: A list of providers. See `rustc_compile_action`
"""
_validate_root_path(ctx)
_assert_no_deprecated_attributes(ctx)
_assert_correct_dep_mapping(ctx)

Expand Down Expand Up @@ -260,6 +282,7 @@ def _rust_library_common(ctx, crate_type):
name = crate_name,
type = crate_type,
root = crate_root,
root_path = getattr(ctx.attr, "root_path", ""),
srcs = srcs,
deps = deps,
proc_macro_deps = proc_macro_deps,
Expand Down Expand Up @@ -290,6 +313,7 @@ def _rust_binary_impl(ctx):
Returns:
list: A list of providers. See `rustc_compile_action`
"""
_validate_root_path(ctx)
toolchain = find_toolchain(ctx)
crate_name = compute_crate_name(ctx.workspace_name, ctx.label, toolchain, ctx.attr.crate_name)
_assert_correct_dep_mapping(ctx)
Expand Down Expand Up @@ -327,6 +351,7 @@ def _rust_binary_impl(ctx):
name = crate_name,
type = ctx.attr.crate_type,
root = crate_root,
root_path = getattr(ctx.attr, "root_path", ""),
srcs = srcs,
deps = deps,
proc_macro_deps = proc_macro_deps,
Expand Down Expand Up @@ -383,6 +408,7 @@ def _rust_test_impl(ctx):
Returns:
list: The list of providers. See `rustc_compile_action`
"""
_validate_root_path(ctx)
_assert_no_deprecated_attributes(ctx)
_assert_correct_dep_mapping(ctx)

Expand Down Expand Up @@ -451,6 +477,7 @@ def _rust_test_impl(ctx):
name = crate_name,
type = crate_type,
root = crate.root,
root_path = crate.root_path,
srcs = srcs,
deps = depset(deps, transitive = [crate.deps]).to_list(),
proc_macro_deps = depset(proc_macro_deps, transitive = [crate.proc_macro_deps]).to_list(),
Expand Down Expand Up @@ -508,6 +535,7 @@ def _rust_test_impl(ctx):
name = crate_name,
type = crate_type,
root = crate_root,
root_path = getattr(ctx.attr, "root_path", ""),
srcs = srcs,
deps = deps,
proc_macro_deps = proc_macro_deps,
Expand Down Expand Up @@ -728,6 +756,9 @@ _COMMON_ATTRS = {

If `crate_root` is not set, then this rule will look for a `lib.rs` file (or `main.rs` for rust_binary)
or the single file in `srcs` if `srcs` contains only one file.

If the `srcs` contains only one file and that file is a directory,
use `root_path` to specify the path to the crate root .rs file under that directory.
"""),
allow_single_file = [".rs"],
),
Expand Down Expand Up @@ -784,6 +815,9 @@ _COMMON_ATTRS = {
values = [-1, 0, 1],
default = -1,
),
"root_path": attr.string(
doc = """If the crate root (single member of the `srcs` list) is a directory, this is the path to the crate root `.rs` file under that directory.""",
),
"rustc_env": attr.string_dict(
doc = dedent("""\
Dictionary of additional `"key": "value"` environment variables to set for rustc.
Expand Down
10 changes: 9 additions & 1 deletion rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

"""Functionality for constructing actions that invoke the Rust compiler"""

load("@bazel_skylib//lib:paths.bzl", "paths")
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
load(
"@bazel_tools//tools/build_defs/cc:action_names.bzl",
Expand Down Expand Up @@ -1143,7 +1144,7 @@ def construct_arguments(
rustc_flags = ctx.actions.args()
rustc_flags.set_param_file_format("multiline")
rustc_flags.use_param_file("@%s", use_always = bool(ctx.executable._process_wrapper))
rustc_flags.add(crate_info.root)
rustc_flags.add_all([(crate_info.root, crate_info.root_path)], map_each = _get_crate_root_path)
rustc_flags.add(crate_info.name, format = "--crate-name=%s")
rustc_flags.add(crate_info.type, format = "--crate-type=%s")

Expand Down Expand Up @@ -2855,6 +2856,13 @@ def _add_native_link_flags(
format_each = "-lstatic=%s",
)

def _get_crate_root_path(args):
file, root_path = args
if file.is_directory:
return paths.join(file.path, root_path)
else:
return file.path

def _get_dirname(file):
"""A helper function for `_add_native_link_flags`.

Expand Down
1 change: 1 addition & 0 deletions rust/private/rustdoc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def _strip_crate_info_output(crate_info):
name = crate_info.name,
type = crate_info.type,
root = crate_info.root,
root_path = crate_info.root_path,
srcs = crate_info.srcs,
deps = crate_info.deps,
proc_macro_deps = crate_info.proc_macro_deps,
Expand Down
1 change: 1 addition & 0 deletions rust/private/rustdoc_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ def _create_crate_info(ctx):
name = crate.name,
type = crate.type,
root = crate.root,
root_path = crate.root_path,
srcs = crate.srcs,
deps = depset(deps, transitive = [crate.deps]),
proc_macro_deps = depset(proc_macro_deps, transitive = [crate.proc_macro_deps]),
Expand Down
31 changes: 31 additions & 0 deletions test/root_path/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("//rust:defs.bzl", "rust_library", "rust_test")
load(":defs.bzl", "package_dir_artifact")

package(default_visibility = ["//visibility:private"])

package_dir_artifact(
name = "dir_artifact",
srcs = [
"src/lib.rs",
"src/submodule.rs",
],
)

rust_library(
name = "my_lib",
srcs = [":dir_artifact"],
root_path = "src/lib.rs",
)

rust_test(
name = "my_lib_test",
crate = ":my_lib",
)

build_test(
name = "build_test",
targets = [
":my_lib",
],
)
31 changes: 31 additions & 0 deletions test/root_path/defs.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""Custom rule to package sources into a directory TreeArtifact for testing root_path."""

def _package_dir_artifact_impl(ctx):
outdir = ctx.actions.declare_directory(ctx.attr.name + ".dir")

args = ctx.actions.args()
args.add(outdir.path)
for src in ctx.files.srcs:
args.add(src.path)

ctx.actions.run_shell(
outputs = [outdir],
inputs = ctx.files.srcs,
command = 'out="$1"; shift; mkdir -p "$out/src"; cp "$@" "$out/src/"',
arguments = [args],
progress_message = "Packaging srcs into directory artifact %s" % outdir.short_path,
)

return [
DefaultInfo(files = depset([outdir])),
]

package_dir_artifact = rule(
implementation = _package_dir_artifact_impl,
attrs = {
"srcs": attr.label_list(
allow_files = True,
mandatory = True,
),
},
)
15 changes: 15 additions & 0 deletions test/root_path/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
pub mod submodule;

pub fn greeting() -> &'static str {
submodule::msg()
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_greeting() {
assert_eq!(greeting(), "Hello from directory artifact!");
}
}
3 changes: 3 additions & 0 deletions test/root_path/src/submodule.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub fn msg() -> &'static str {
"Hello from directory artifact!"
}
Loading