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

Add gen_binaries annotation to control which bins to make target for #1718

Merged
merged 3 commits into from
Jan 3, 2023

Conversation

dtolnay
Copy link
Contributor

@dtolnay dtolnay commented Dec 21, 2022

In Cargo, when you depend on a library, it does not make Cargo build all the bin crates that might be included in that same package; your crate only depends on the other package's lib crate. This means packages in the Cargo ecosystem, even quite foundational ones like cc and clap, mindlessly include various small bins that are useful for their test suite or useful for local development.

Some examples:

Taking into account the state of the ecosystem, I don't think it makes sense for rules_rust's default behavior to expose all these, since they were never meant to be accessed downstream.

This PR changes generation of rust_binary targets in crates_vendor to opt-in by default. You can set gen_binaries = True for a specific package to generate Bazel targets for all of that package's bins, or gen_binaries = ["array", "of", "names"] to select specific bins you need a target for.

The naming of the new annotation mirrors the existing gen_build_script annotation.

Example

crates_vendor(
    name = "vendor",
    annotations = {
        "aaa": [crate.annotation(
            # Do not generate `rust_binary` for any of the package's
            # bins. This is the new default behavior.
            gen_binaries = False,
        )],
        "bbb": [crate.annotation(
            # Generate `rust_binary` for all bins. This is the previous
            # default behavior in rules_rust 0.15.0.
            gen_binaries = True,
        )],
        "ccc": [crate.annotation(
            # Generate `rust_binary` for a specific subset of the
            # bins by name.
            gen_binaries = ["gcc-shim"],
        )],
    },
    cargo_lockfile = ":Cargo.lock",
    manifests = [":Cargo.toml"],
    mode = "remote",
    tags = ["manual"],
    vendor_path = "bazel",
)

@dtolnay dtolnay force-pushed the genbinaries branch 2 times, most recently from 204057f to fd1b5d1 Compare December 21, 2022 08:25
Copy link
Collaborator

@illicitonion illicitonion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a very reasonable option to add, but I'm not sure about the default... Could you describe the particular problems these targets existing is causing you?

@dtolnay
Copy link
Contributor Author

dtolnay commented Dec 21, 2022

I'm not sure about the default... Could you describe the particular problems these targets existing is causing you?

I chose the default to be the setting that I would want to use.

We also don't generate targets for an imported library's examples, or tests. It didn't make sense to me that these predominantly test-only binaries would get a different treatment. Obviously I don't mind if rules_rust is able to generate targets for any of these when someone wants, but to me as someone importing libraries, those other targets are all noise, and opt-in solves that.

In regard to crates that are intended to be binaries (my faketty as an example), note that rules_rust's crates_vendor is already not suited to importing them. You can try adding faketty = "1" to a Cargo.toml and running bazel run //crate_universe/3rdparty:crates_vendor, and it will silently just not generate a rust_binary for faketty (independent of this PR). I'd guess that's because Cargo only supports depending on lib crates — "warning: repro v0.0.0: ignoring invalid dependency `faketty` which is missing a lib target". Given crates_vendor revolves around using a Cargo.toml and Cargo lockfile as the input, it would benefit from better conveying that it's not architected for importing bin-only crates, instead of sometimes generating bin targets depending on whether the package happens to contain a library next to the bin.

I think if crates_vendor at some point gets redone to do its own version resolution and stuff instead of leaning on Cargo, I think the ideal default would be to generate rust_binary for bin-only crates like faketty, and no rust_binary for library crates, but as I mentioned the bin-only dependencies don't work now.

@illicitonion
Copy link
Collaborator

In regard to crates that are intended to be binaries (my faketty as an example), note that rules_rust's crates_vendor is already not suited to importing them.

I think this is pretty compelling - the fact that it's hit-or-miss whether we generate bin targets based on arbitrary properties of the crate you're depending on means opting in to trying to make something work is probably reasonable (and hopefully means people can look at some documentation when they try to enable this, to see some caveats we may need to publish).

We also don't generate targets for an imported library's examples, or tests. It didn't make sense to me that these predominantly test-only binaries would get a different treatment.

I guess my intuition here leans towards "lots of crates expose a useful binary I may want to run, and there are some which are testonly which I can ignore", whereas yours leans towards "most binary targets are testonly, and create noise" - I don't think it super matters which way we lean, though, either default I think is reasonable. That said, /cc @UebelAndre in case they have a strong argument either way :) if not, I'll merge this as-is.

I think if crates_vendor at some point gets redone to do its own version resolution and stuff instead of leaning on Cargo, I think the ideal default would be to generate rust_binary for bin-only crates like faketty, and no rust_binary for library crates, but as I mentioned the bin-only dependencies don't work now.

FWIW I think the way we'd end up supporting this is via Cargo's artifact dependencies rather than via a custom resolver, but who knows what the future will hold!

@dtolnay
Copy link
Contributor Author

dtolnay commented Dec 22, 2022

Neat, I hadn't seen that feature. You're right it seems very relevant. My expectations from skimming the following docs would be:

[dependencies]
# Export rust_binary for all bins, do not export the rust_library from BUILD.bazel.
# Presumably a rust_library still needs to be generated in BUILD.example-1.0.0.bazel
# because the binary depends on it.
example = { version = "1", artifact = "bin" }

# Export rust_binary for those specific bins, do not export rust_library.
example = { version = "1", artifact = ["bin:faketty", "bin:cmake"] }

# Export rust_library as well as rust_binary.
example = { version = "1", artifact = "bin", lib = true }

# Same as this PR: export rust_library, do not generate rust_binary.
example = { version = "1" }

Copy link
Collaborator

@UebelAndre UebelAndre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I think this seems fine. I had one request though 😄

@@ -114,6 +115,8 @@ def _annotation(
data (list, optional): A list of labels to add to a crate's `rust_library::data` attribute.
data_glob (list, optional): A list of glob patterns to add to a crate's `rust_library::data` attribute.
deps (list, optional): A list of labels to add to a crate's `rust_library::deps` attribute.
gen_binaries (list or bool, optional): As a list, the subset of the crate's bins that should get `rust_binary`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also make this configurable globally like gen_build_script is?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add a note about this not affecting binary only crates? Maybe a section could be added to the top level crate_universe docs in //crate_universe:docs.bzl? Not sure where the best place is for this info but I can see that being a point of confusion for folks (already was but I want to try and avoid a bug report being incorrectly filed for this new feature)

@dtolnay
Copy link
Contributor Author

dtolnay commented Jan 1, 2023

@@ -114,6 +115,8 @@ def _annotation(
data (list, optional): A list of labels to add to a crate's `rust_library::data` attribute.
data_glob (list, optional): A list of glob patterns to add to a crate's `rust_library::data` attribute.
deps (list, optional): A list of labels to add to a crate's `rust_library::deps` attribute.
gen_binaries (list or bool, optional): As a list, the subset of the crate's bins that should get `rust_binary`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add a note about this not affecting binary only crates? Maybe a section could be added to the top level crate_universe docs in //crate_universe:docs.bzl? Not sure where the best place is for this info but I can see that being a point of confusion for folks (already was but I want to try and avoid a bug report being incorrectly filed for this new feature)

@dtolnay
Copy link
Contributor Author

dtolnay commented Jan 1, 2023

Copy link
Collaborator

@UebelAndre UebelAndre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! Looks good to me 😄

I'll leave the rest up to @illicitonion

Copy link
Collaborator

@illicitonion illicitonion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Example:

    crates_vendor(
        name = "vendor",
        annotations = {
            "aaa": [crate.annotation(
                # Do not generate `rust_binary` for any of the package's bins.
                # This is the new default behavior.
                gen_binaries = False,
            )],
            "bbb": [crate.annotation(
                # Generate `rust_binary` for all bins. This is the previous
                # default behavior in rules_rust 0.15.0.
                gen_binaries = True,
            )],
            "ccc": [crate.annotation(
                # Generate `rust_binary` for a specific subset of the bins.
                gen_binaries = ["gcc-shim"],
            )],
        },
        cargo_lockfile = ":Cargo.lock",
        manifests = [":Cargo.toml"],
        mode = "remote",
        tags = ["manual"],
        vendor_path = "bazel",
    )
@dtolnay
Copy link
Contributor Author

dtolnay commented Jan 3, 2023

  • Rebased to resolve conflict with Re-pinned all dependencies managed by crate_universe #1735 in the following generated files.

    • crate_universe/3rdparty/crates/BUILD.bazel
    • crate_universe/3rdparty/crates/BUILD.cargo-lock-8.0.3.bazel
    • crate_universe/3rdparty/crates/BUILD.cc-1.0.78.bazel
    • crate_universe/3rdparty/crates/BUILD.clap-4.0.32.bazel

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

Successfully merging this pull request may close these issues.

None yet

3 participants