Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bazel build with prost-build build.rs fails with "No such file or directory" #454

Closed
ttiurani opened this issue Oct 19, 2020 · 6 comments · Fixed by #468
Closed

Bazel build with prost-build build.rs fails with "No such file or directory" #454

ttiurani opened this issue Oct 19, 2020 · 6 comments · Fixed by #468

Comments

@ttiurani
Copy link

ttiurani commented Oct 19, 2020

I created a demo repository:

https://github.com/ttiurani/bazel-prost-build-bug

to showcase an issue where the standard prost-build example works fine with a cargo build but running the same with cargo raze'd Bazel repository with bazel build demo fails with:

ERROR: /private/var/tmp/_bazel_ttiurani/0c87cdffcf4741baaa498655bde07714/external/raze__demo_prost_build__0_0_1/BUILD.bazel:36:19: CargoBuildScriptRun external/raze__demo_prost_build__0_0_1/demo_prost_build_build_script.out_dir failed (Exit 1) cargo_build_script_runner failed: error executing command bazel-out/darwin-opt-exec-2B5CBBC6/bin/external/io_bazel_rules_rust/cargo/cargo_build_script_runner/cargo_build_script_runner ... (remaining 8 argument(s) skipped)

Use --sandbox_debug to see verbose messages from the sandbox
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }', external/raze__demo_prost_build__0_0_1/cargo/build.rs:2:66
stack backtrace:
   0:        0x10cac9a6e - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h24bb64d98a7e25d6
   1:        0x10caeaf9c - core::fmt::write::h8fdc9cddb01cd8b2
   2:        0x10cac6bd9 - std::io::Write::write_fmt::hcc3030013983bab6
   3:        0x10cacbc35 - std::panicking::default_hook::{{closure}}::h95817712c5ff0736
   4:        0x10cacb972 - std::panicking::default_hook::h34e085f4e0b1062d
   5:        0x10cacc195 - std::panicking::rust_panic_with_hook::haf571858f996ac45
   6:        0x10cacbd62 - rust_begin_unwind
   7:        0x10caf37ef - core::panicking::panic_fmt::h11676ba6a846d9f4
   8:        0x10caf36f5 - core::option::expect_none_failed::h312e48bacb63d8ec
   9:        0x10ca81c1b - demo_prost_build_build_script_script_::main::h399dfdb84fd54273
  10:        0x10ca82986 - std::rt::lang_start::{{closure}}::h0a0a8f1aceef40a7
  11:        0x10cacc45f - std::rt::lang_start_internal::hcd84a36052901671
  12:        0x10ca81c69 - main
Error: "Build script process failed with exit code 101"

Where the build.rs is:

fn main() {
    prost_build::compile_protos(&["src/items.proto"], &["src/"]).unwrap();
}

The error message is quite non-descriptive so was unable to trace this further myself. Note that I'd very much like to use the bundled protoc binary and not an external one to make my build easily repeatable in CI environments.

Any ideas what might be wrong? I'm using the latest rules_rust from this morning.

@dae
Copy link
Contributor

dae commented Oct 19, 2020

protoc is likely not on your path. prost_build supports a PROTOC env var, but unless you're using the git version of prost_build, it checks it at build time instead of run time. I don't know if variable expansion is available in the Rust rules at the moment - adding it in the future would make things cleaner. I'm currently using a genrule with PROTOC=$(location @com_google_protobuf//:protoc) $(location :some_rust_binary_rule) in cmds to work around it.

@ttiurani
Copy link
Author

ttiurani commented Oct 19, 2020

@dae thanks for the quick reply! I'm really new to Bazel so don't quite understand where in my demo repository would that kind of genrule then be? Because I believe this fails now before I get to almost any of my own Bazel labels, because the build.rs containing dependency is cargo-only project (the demo project replicates an actual problem, so touching anything under cargo/ won't work).

@dae
Copy link
Contributor

dae commented Oct 20, 2020

I'm quite new to Bazel too :-) As far as I'm aware, this currently requires either hard-coding a path to PROTOC in the rustc_env argument (which you can have cargo-raze add for you), or jumping through hoops with a separate binary to resolve the proper location - which likely means vendoring the crate if it's not your own.

To onlookers, if there's a simpler way that I've missed, please let me know!

dae added a commit to ankitects/rules_rust that referenced this issue Oct 22, 2020
This makes it possible to pass in the path to generated files and
external tools.

This potentially closes bazelbuild#459, closes bazelbuild#454, and closes bazelbuild#79.

The docs seem to indicate there's precedent for this in rules_cc:
https://docs.bazel.build/versions/master/be/make-variables.html#predefined_label_variables
@wchargin
Copy link
Contributor

wchargin commented Nov 2, 2020

@dae: Could you help me understand your solution? I’m perfectly happy to
use a genrule that wires up PROTOC to a $(location), but I’m not
sure how to get that to work. Here’s what I have…

In my Cargo.toml, needed for prost-build to build:

[dependencies]
prost-build = "0.6.1"

[raze.crates.prost-build.'0.6.1']
gen_buildrs = true

[raze.crates.indexmap.'1.6.0']
additional_flags = [
    "--cfg=has_std",
]

As my test script:

fn main() -> std::io::Result<()> {
    let out_dir = "/tmp/gen_protos_out";
    std::fs::DirBuilder::new()
        .recursive(true)
        .create(out_dir)
        .unwrap();
    prost_build::Config::new()
        .out_dir(out_dir)
        .compile_protos(&[""][0..0], &[])
        .expect("compile_protos");
    Ok(())
}

To build that:

rust_binary(
    name = "build_protos",
    srcs = ["build_protos.rs"],
    edition = "2018",
    deps = [
        "//third_party/rust:prost_build",
    ],
)

Now, when I build and run this with Bazel, I get the same NotFound
error as above, regardless of whether I set PROTOC=... or what I set
it to. And when I run under strace -f -e trace=execve, I see:

[pid 3817263] execve("/HOMEDIR/.cache/bazel/_bazel_wchargin/52a95bbdd50941251730eb33b7476a66/sandbox/linux-sandbox/1165/execroot/org_tensorflow_tensorboard/bazel-out/k8-opt-exec-50AE0418/bin/external/raze__prost_build__0_6_1/prost_build_build_script_script_.runfiles/raze__prost_build__0_6_1/third-party/protobuf/protoc-linux-x86_64", ["/HOMEDIR/"..., "--include_imports", "--include_source_info", "-o", "/tmp/prost-buildQPI9io/prost-des"..., "-I", "/HOMEDIR/"...], 0x7ffeb0b6bd08 /* 80 vars */) = -1 ENOENT (No such file or directory)

Note the path to execve: it’s in the execroot for the build script for
the prost_build crate. This can’t be right. Presumably the build
script for prost_build is grabbing the execroot while the crate
is being compiled and baking that path into the crate, where it’s used
after the sandbox is wiped. Borrowed value does not live long enough! ;-)

Unsurprisingly, same dice when I invoke this via a genrule.

So, I’m happy to jump through some BUILD hoops, especially since I have
@com_google_protobuf//:protoc in my workspace already. But I don’t
want to do anything non-hermetic. Am I understanding correctly from your
$(location) comment that you know a way to do this?

(Let me know if you need a more precise repro… minimizing a Bazel
workspace that has a @com_google_protobuf dep is always a pain.)

@dae
Copy link
Contributor

dae commented Nov 2, 2020

If you use the branch waiting to be merged in #468, the genrule hack is no longer needed, as you can pass a location directly to the build script:

https://github.com/ankitects/anki/blob/ef5cd9f551269986ca44688e9fc42efeb4fc5bf6/rslib/BUILD.bazel#L24
https://github.com/ankitects/anki/blob/ef5cd9f551269986ca44688e9fc42efeb4fc5bf6/rslib/build/protobuf.rs#L80

Note that you'll need the git version of prost so it resolves PROTOC at run time instead of compile time.

@wchargin
Copy link
Contributor

wchargin commented Nov 2, 2020

Oh!—

Note that you'll need the git version of prost so it resolves PROTOC
at run time instead of compile time.

—thanks; this was what I had missed. I had been looking at the latest
sources on GitHub
and didn’t realize that this commit hadn’t
actually been released. Looks like there is one release blocker.

I’ve resolved my issue by copying your Git dep on prost-build,
and am looking forward to your PR, which seems still nicer. :-) Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants