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

What's the best way to vary crate_features? #801

Closed
sayrer opened this issue Jun 25, 2021 · 8 comments · Fixed by #809
Closed

What's the best way to vary crate_features? #801

sayrer opened this issue Jun 25, 2021 · 8 comments · Fixed by #809
Labels

Comments

@sayrer
Copy link
Contributor

sayrer commented Jun 25, 2021

Suppose I want to change crate_features arguments on the bazel command line. What's the best way?

@sayrer
Copy link
Contributor Author

sayrer commented Jun 25, 2021

I got this to sort of work:

genrule(
    name = "create_cfg_file",
    outs = ["path/rust_cfgs.txt"],
    cmd = "echo '--cfg=foo' >> $@",
)

load("@rules_rust//rust:defs.bzl", "rust_binary")
rust_binary(
    name = "simple_rs",
    srcs = ["simple.rs"],
    rustc_flags = [
        # This name has to be correct
        "--verbose",
        # More options can come from here, but the file path needs
        # to be correct. Perhaps a rustc_flags_file with a label?
        "@bazel-out/darwin-fastbuild/bin/path/rust_cfgs.txt"
    ],
    compile_data = [
        ":create_cfg_file",
    ]
)

@UebelAndre
Copy link
Collaborator

Would #566 give you what you're looking for?

@sayrer
Copy link
Contributor Author

sayrer commented Jun 26, 2021

I don't think so, but would be happy to be corrected.

If I use the functions like string_flag in @bazelskylib/rules/common_settings.bzl to control crate options, I think I need to coalesce them into a file, and make that the output of an action.

Frustratingly, none of the examples that read these flags do anything other than print them, like this one.

@sayrer
Copy link
Contributor Author

sayrer commented Jun 26, 2021

I think the problem with #566 is that those arguments will get passed to every crate, but what I really want to do is enable features in specific crates, and string_flag allows that to be scoped to a BUILD file (the project is fairly large).

@sayrer
Copy link
Contributor Author

sayrer commented Jun 27, 2021

I think this would work if rustc_flags did some Make variable expansion, like cc_binary does:
https://docs.bazel.build/versions/main/be/c-cpp.html#cc_binary.copts

load("@rules_rust//rust:defs.bzl", "rust_binary")
rust_binary(
    name = "simple_rs",
    srcs = ["simple.rs"],
    rustc_env = {
      # Works
      "RUSTC_FLAGS_FILE": "$(location :flags_file)"
    },
    rustc_flags = [
        # This name has to be correct
        "--verbose",
        # Does not work
        "@$(location :flags_file)"
    ],
    compile_data = [
        ":flags_file",
    ]
)

@UebelAndre
Copy link
Collaborator

I think it'd be reasonable to call expand_locations on rustc_flags. Curious about what other maintainers think though.

@sayrer
Copy link
Contributor Author

sayrer commented Jun 27, 2021

With my patch, I'm able to do something like this:

rules.bzl:

def _rustc_flags_file_impl(ctx):
  out = ctx.actions.declare_file(ctx.label.name + ".txt")
  cfg_lines = ["--cfg\nfeature=\"%s\"" % flag.label.name 
               for flag in ctx.attr.flags if flag[BuildSettingInfo].value]
  ctx.actions.write(
    output = out,
    content = "\n".join(cfg_lines),
  )
  return [DefaultInfo(files = depset([out]))]

rustc_flags_file = rule(
  implementation = _rustc_flags_file_impl,
  attrs = {
    "flags": attr.label_list(),
  }
)

BUILD.bazel:

load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
bool_flag(
  name = "foo",
  build_setting_default = False
)

bool_flag(
  name = "bar",
  build_setting_default = True
)

load("//:rules.bzl", "rustc_flags_file")
rustc_flags_file(
  name = "flags_file",
  flags = [":foo", ":bar"],
)

load("@rules_rust//rust:defs.bzl", "rust_binary")
rust_binary(
  name = "simple_rs",
  srcs = ["simple.rs"],
  rustc_flags = [
    "--verbose",
    "@$(location :flags_file)",
  ],
  compile_data = [
    ":flags_file",
  ]
)

simple.rs:

pub fn main() {
  let foo_data = if cfg!(feature="foo") {
    "FOO"
  } else {
    "unknown"
  };
  println!("hello, world: foo is {}", foo_data);
  let bar_data = if cfg!(feature="bar") {
    "BAR"
  } else {
    "unknown"
  };
  println!("hello, world: bar  is {}", bar_data);
}

That way, I can set things on specific targets, not just globally. Note that "bar" is on by default. Here's the output:

% bazel run //:simple_rs
hello, world: foo is unknown
hello, world: bar is BAR
% bazel run //:simple_rs --//:foo=1
hello, world: foo is FOO
hello, world: bar is BAR
% bazel run //:simple_rs --//:foo=1 --//:bar=0
hello, world: foo is FOO
hello, world: bar is unknown
% bazel run //:simple_rs --//:foo=0 --//:bar=0
hello, world: foo is unknown
hello, world: bar is unknown
% bazel run //:simple_rs --//:foo=0 --//:bar=1
hello, world: foo is unknown
hello, world: bar is BAR

@sayrer sayrer closed this as completed Jul 1, 2021
@sayrer
Copy link
Contributor Author

sayrer commented Jul 1, 2021

Fixed by #809.

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

Successfully merging a pull request may close this issue.

2 participants