rules_rust icon indicating copy to clipboard operation
rules_rust copied to clipboard

`rust_library` cannot find `compile_data` if `srcs` contains generated code

Open fardream opened this issue 2 years ago • 3 comments

include_str and include_bytes don't work if some of the codes are generated, even if the include macros are called from codes that are not generated.

I have a reproducible example github.com/fardream/rules-rust-bug

For example, if I have lib.rs as below, where test.txt is a file in the same folder as lib.rs,

pub const BYTES: &'static str = include_str!("test.txt");

The below will compile

rust_library(
    name = "include_str",
    srcs = ["lib.rs"],
    compile_data = ["test.txt"],
)

However, compile will not work if some of the srcs are generated.

If I use below rule to write lib2.rs

def _write_rs(ctx):
    output = ctx.actions.declare_file(ctx.label.name)
    ctx.actions.write(
        output = output,
        content = "pub const BYTES: &'static str = \"astring\";",
    )
    return [DefaultInfo(files = depset([output]))]

write_rs = rule(implementation = _write_rs)

Below will not work

rust_library(
    name = "include_str_with_gen_code",
    srcs = [
        "lib.rs",
        "lib2.rs",
    ],
    compile_data = ["test.txt"],
)

And the error is compiler cannot find text.txt, even though it is there.

error: couldn't read bazel-out/darwin_arm64-fastbuild/bin/test.txt: No such file or directory (os error 2)
 --> bazel-out/darwin_arm64-fastbuild/bin/lib.rs:1:33
  |
1 | pub const BYTES: &'static str = include_str!("test.txt");
  |                                 ^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

Target //:include_str_with_gen_code failed to build
Use --verbose_failures to see the command lines of failed build steps.

fardream avatar Nov 17 '23 02:11 fardream

After some debugging, I think the problem lies in that srcs are symlinked to bazel-out if any of the source file is generated. I think the same should be done for everything in compile_data too.

This is the code location that is symlinking the source files: https://github.com/bazelbuild/rules_rust/blob/f11c529e802ee1a4537634d4a175bd6658dd60be/rust/private/rust.bzl#L151

changing transform_sources may probably work:

def transform_sources(ctx, srcs, compile_data, crate_root):
    """Creates symlinks of the source files if needed.

    Rustc assumes that the source files are located next to the crate root.
    In case of a mix between generated and non-generated source files, this
    we violate this assumption, as part of the sources will be located under
    bazel-out/... . In order to allow for targets that contain both generated
    and non-generated source files, we generate symlinks for all non-generated
    files.

    Args:
        ctx (struct): The current rule's context.
        srcs (List[File]): The sources listed in the `srcs` attribute
        compile_data (List[File]): The sources listed in the `compile_data` attribute
        crate_root (File): The file specified in the `crate_root` attribute,
                           if it exists, otherwise None

    Returns:
        Tuple(List[File], File): The transformed srcs and crate_root
    """
    has_generated_sources = (len([src for src in srcs if not src.is_source]) + len([src for src in compile_data if not src.is_source])) > 0

    if not has_generated_sources:
        return srcs, compile_data, crate_root

    package_root = paths.dirname(paths.join(ctx.label.workspace_root, ctx.build_file_path))
    generated_sources = [_symlink_for_non_generated_source(ctx, src, package_root) for src in srcs if src != crate_root]
    generated_compiled_data = [_symlink_for_non_generated_source(ctx, src, package_root) for src in compile_data if src != crate_root]
    generated_root = crate_root
    if crate_root:
        generated_root = _symlink_for_non_generated_source(ctx, crate_root, package_root)
        generated_sources.append(generated_root)

    return generated_sources, generated_compiled_data, generated_root

fardream avatar Nov 17 '23 18:11 fardream

I’m not sure what the fix should be. @scentini do you think compile data should also be copied to generated outputs like sources?

UebelAndre avatar Nov 18 '23 11:11 UebelAndre

Yeah, I think creating symlinks to compile data will work.

scentini avatar Nov 20 '23 09:11 scentini