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

Support constraint_value directly in select() #12071

Closed

Conversation

gregestren
Copy link
Contributor

@gregestren gregestren commented Sep 9, 2020

No more need for a redundant config_setting. See #8583 for an example.

This was a bit subtle. constraint_value can't directly export a ConfigMatchingProvider because it needs to know the
platform to determine if it's a match. But platforms are built out of constraint_values, so the platform isn't available
yet. So the parent target with the select() provides this detail.

Also beautifies "invalid select() key" errors in support of #11984.

Fixes #8583.

RELNOTES[NEW]: select() directly supports constraint_value (no need for an intermediate config_setting).

No more need for a redundant config_setting. See bazelbuild#8583
for an example.

This was a bit subtle. constraint_value can't directly
export a ConfigMatchingProvider because it needs to know the
platform to determine if it's a match. But platforms are
built out of constraint_values, so the platform isn't available
yet. So the parent target with the select() provides this detail.

Also beautifies "invalid select() key" errors in support of bazelbuild#11984.

Fixes bazelbuild#8583.

RELNOTES[NEW]: select() directly supports constraint_value (no need for an intermediate config_setting).

PiperOrigin-RevId: 327885099
Change-Id: Ifbdfa275ff83f0cb30207a5bd77aca317599fc21
@gregestren
Copy link
Contributor Author

@philsc @AustinSchuh FYI

Copy link
Member

@katre katre left a comment

Choose a reason for hiding this comment

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

This is really clever and I like it.

Most of my comments are not actionable, just ways I want to think about the API. I will probably come back tomorrow and turn some of them into standalone issues, sorry for adding my stream-of-consciousness to your PR review.

```

This saves the need for boilerplate `config_setting`s when you only need to
check against single values.
Copy link
Member

Choose a reason for hiding this comment

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

Should we give an example of using config_setting for multiple constraint values?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The example before here already does this, so I think we have good coverage overall: https://docs.bazel.build/versions/3.5.0/configurable-attributes.html#platforms.

* Returns a {@link ConfigMatchingProvider} that matches if the owning target's platform includes
* this constraint.
*
* <p>The {@link com.google.devtools.build.lib.rules.platform.ConstraintValue;ConstraintValue}
Copy link
Member

Choose a reason for hiding this comment

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

The @link syntax looks wrong here, what are you intending to do?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right. Just removing the part after the semi-colon works. I fully qualified it because otherwise an import on its package adds a dependency which messes with the BUILD dependency structure. Which isn't worth it just for a code link (I believe that's our actual style guidance too: to not add new dependencies just for doc links).

*
* <p>Instead, a target with a <code>select()</code> on a {@link
* com.google.devtools.build.lib.rules.platform.ConstraintValue} passes its platform info to this
* method.
Copy link
Member

Choose a reason for hiding this comment

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

That is really clever. :)

env,
ctgValue,
transitivePackagesForPackageRootResolution,
unloadedToolchainContexts == null
? null
: unloadedToolchainContexts.getDefaultToolchainContext().targetPlatform(),
Copy link
Member

Choose a reason for hiding this comment

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

All toolchain contexts for the same configured target, regardless of exec group, should have the same target platform (right @juliexxia ?)

We should consider enshrining that in the API by adding a unloadedToolchainContexts.targetPlatform() method.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah that sounds right and looks right according to https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java;l=531?q=ConfiguredTargetFunction&ss=bazel

@katre I like that idea. Do you think there's anything else to discuss there? If not I can mail something.

Copy link
Member

Choose a reason for hiding this comment

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

I don't think so, it makes sense. Go ahead if you have time, I was going to file an issue and then deal with it later :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To be clear, this suggestion is for a followup PR?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, nothing to do in this PR.

// If platformInfo == null, that means the owning target doesn't invoke toolchain
// resolution, in which case depending on a constraint_value is non-sensical.
configConditions.put(
entry.getLabel(), constraintValueInfo.configMatchingProvider(platformInfo));
Copy link
Member

Choose a reason for hiding this comment

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

Could we add a ConfigMatchingProvider.configMatchingProvider(???) method, so that we'd only have one branch here? We'd have to do some weird generic tricks to get the type right, and it might not be worth it, but if we ever add a third, we should consider a way to collapse the choices.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. Given the frequency of rule expansion (very infrequent), I vote for not supporting that much extra abstraction yet. But I added a note with your suggestion if this ever goes further.

@gregestren
Copy link
Contributor Author

This is really clever and I like it.

I assure you my first pass on this looked 10,000 times worse! I was surprised and happy to reduce this to something so non-invasive.

Most of my comments are not actionable, just ways I want to think about the API. I will probably come back tomorrow and turn some of them into standalone issues, sorry for adding my stream-of-consciousness to your PR review.

No worries, thanks for the comments. I'll follow up properly on them as soon as I can.

@bazel-io bazel-io closed this in 12b06b2 Sep 11, 2020
@gregestren gregestren deleted the select_on_constraints branch September 11, 2020 20:53
@pcjanzen
Copy link
Contributor

Is this supposed to work in a filegroup?

filegroup(
    name = "cv_in_filegroup",
    srcs = select({
        "@platforms//os:windows": ["dummy"],
        "//conditions:default": ["dummy"],
    }),
)

$ bazel-4.0.0-darwin-x86_64 build //:cv_in_filegroup
ERROR: BUILD:84:10: @platforms//os:windows is not a valid select() condition for //:cv_in_filegroup.
To inspect the select(), run: bazel query --output=build //:cv_in_filegroup.
For more help, see https://docs.bazel.build/be/functions.html#select.

but the corresponding version with a config_setting works correctly, as does the select clause in (for example) a sh_binary.

cc @UebelAndre

@gregestren
Copy link
Contributor Author

Interesting catch!

My first instinct was to say it shouldn't matter what rule uses the select - that's not where the logic kicks in. But lo and behold I replicated your exact error, then changed the filegroup to a cc_library and suddenly it worked. This calls for more digging...

@UebelAndre
Copy link
Contributor

One other thing I noticed is the ctx.attr.bool does not accept select statements. Not sure if that's directly related to this 😅

@gregestren
Copy link
Contributor Author

Found the problem!

} else if (constraintValueInfo != null && platformInfo != null) {

In this example platformInfo is null.

Matching the constraint_value with the platform requires knowing what the platform is. select() logic gets all its info from the target it's attached to. Most rules trigger platform resolution, but some don't. filegroup is one of the exceptions.

I think the idea is that filegroup is such a simple rule it doesn't matter what the platform is, since there's no filegroup toolchain to match it to. So Bazel avoids the extra work of platform resolution. As a side effect you get this bug.

i believe filegroup is one of the rare rules with this problem. CC @katre if there's any obvious fix to this blip.

ctx.attr.bool sounds like a separate issue. Can you file a distinct bug for it?

@katre
Copy link
Member

katre commented Jan 26, 2021

Filegroup was explicitly added to the set of rules that don't participate in toolchain resolution (and that thus don't have a target platform) back during the early development. As I recall, it led to a cycle in evaluation, because filegroups were needed at a low-enough level that we couldn't process loading platforms without them.

I'll take another look at this and see if we can turn it back on.

@gregestren
Copy link
Contributor Author

If that doesn't make sense conceptually, I think we could conditionally load the platform when we notice a constraint_value within the select() logic.

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 this pull request may close these issues.

Provide ability to directly select() on constraint_value
6 participants