diff --git a/cargo/private/cargo_build_script.bzl b/cargo/private/cargo_build_script.bzl index 3572675a0c..c7fb8a7aed 100644 --- a/cargo/private/cargo_build_script.bzl +++ b/cargo/private/cargo_build_script.bzl @@ -610,6 +610,7 @@ def _cargo_build_script_impl(ctx): DefaultInfo(files = depset([out_dir])), BuildInfo( out_dir = out_dir, + build_script_crate_root = ctx.attr.generated_crate_root, rustc_env = env_out, dep_env = dep_env_out, flags = flags_out, @@ -659,6 +660,9 @@ cargo_build_script = rule( providers = [[DepInfo], [CrateGroupInfo]], cfg = "exec", ), + "generated_crate_root": attr.string( + doc = "The location of the crate root when it is generated by the build script", + ), "link_deps": attr.label_list( doc = dedent("""\ The subset of the Rust (normal) dependencies of the crate that diff --git a/extensions/bindgen/private/bindgen.bzl b/extensions/bindgen/private/bindgen.bzl index deaa7e4e7a..42b6d9b214 100644 --- a/extensions/bindgen/private/bindgen.bzl +++ b/extensions/bindgen/private/bindgen.bzl @@ -185,6 +185,7 @@ def _generate_cc_link_build_info(ctx, cc_lib): linker_flags = None, link_search_paths = link_search_paths, out_dir = None, + build_script_crate_root = None, rustc_env = None, ) diff --git a/rust/private/providers.bzl b/rust/private/providers.bzl index f92a5fc8e7..0aee736d68 100644 --- a/rust/private/providers.bzl +++ b/rust/private/providers.bzl @@ -85,6 +85,7 @@ BuildInfo = provider( "link_search_paths": "Optional[File]: file containing search paths to pass to rustc and linker", "linker_flags": "Optional[File]: file containing flags to pass to the linker invoked by rustc or cc_common.link", "out_dir": "Optional[File]: directory containing the result of a build script", + "build_script_crate_root": "Optional[String]: the crate root that was generated by a build script", "rustc_env": "Optional[File]: file containing additional environment variables to set for rustc.", }, ) diff --git a/rust/private/rust.bzl b/rust/private/rust.bzl index 4b457ccf79..d8ddc7b4e8 100644 --- a/rust/private/rust.bzl +++ b/rust/private/rust.bzl @@ -33,6 +33,7 @@ load( "can_build_metadata", "can_use_metadata_for_pipelining", "compute_crate_name", + "crate_root_from_build_scripts", "crate_root_src", "dedent", "deduplicate", @@ -169,7 +170,7 @@ def _rust_library_common(ctx, crate_type): crate_root = getattr(ctx.file, "crate_root", None) if not crate_root: - crate_root = crate_root_src(ctx.attr.name, ctx.attr.crate_name, ctx.files.srcs, crate_type) + crate_root = crate_root_from_build_scripts(ctx) or crate_root_src(ctx.attr.name, ctx.attr.crate_name, ctx.files.srcs, crate_type) srcs, compile_data, crate_root = transform_sources(ctx, ctx.files.srcs, ctx.files.compile_data, crate_root) # Determine unique hash for this rlib. @@ -265,7 +266,7 @@ def _rust_binary_impl(ctx): crate_root = getattr(ctx.file, "crate_root", None) if not crate_root: - crate_root = crate_root_src(ctx.attr.name, ctx.attr.crate_name, ctx.files.srcs, ctx.attr.crate_type) + crate_root = crate_root_from_build_scripts(ctx) or crate_root_src(ctx.attr.name, ctx.attr.crate_name, ctx.files.srcs, ctx.attr.crate_type) srcs, compile_data, crate_root = transform_sources(ctx, ctx.files.srcs, ctx.files.compile_data, crate_root) rust_metadata = None diff --git a/rust/private/utils.bzl b/rust/private/utils.bzl index a759119e7c..220586dec7 100644 --- a/rust/private/utils.bzl +++ b/rust/private/utils.bzl @@ -756,6 +756,28 @@ def can_use_metadata_for_pipelining(toolchain, crate_type): return toolchain._pipelined_compilation and \ crate_type in ("rlib", "lib") +def crate_root_from_build_scripts(ctx): + """ + Identify the generated crate root that comes from a build script (if any) + and return a symlink to it (File). + + Args: + ctx: (ctx): The current rule's context object + """ + candidate_filename = None + candidate_path = None + for dep in ctx.attr.deps: + if BuildInfo in dep: + if dep[BuildInfo].build_script_crate_root: + candidate_filename = dep[BuildInfo].build_script_crate_root + candidate_path = dep[BuildInfo].out_dir.path + "/" + candidate_filename + break + if candidate_path: + crate_root = ctx.actions.declare_symlink(candidate_filename) + symlink_target = relativize(candidate_path, crate_root.dirname) + ctx.actions.symlink(output = crate_root, target_path = symlink_target) + return crate_root + def crate_root_src(name, crate_name, srcs, crate_type): """Determines the source file for the crate root, should it not be specified in `attr.crate_root`.