`rust_library` cannot find `compile_data` if `srcs` contains generated code
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.
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
I’m not sure what the fix should be. @scentini do you think compile data should also be copied to generated outputs like sources?
Yeah, I think creating symlinks to compile data will work.