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

label_flag cannot refer to a platform #25440

Open
keybuk opened this issue Mar 3, 2025 · 7 comments
Open

label_flag cannot refer to a platform #25440

keybuk opened this issue Mar 3, 2025 · 7 comments
Labels
team-Configurability platforms, toolchains, cquery, select(), config transitions type: bug untriaged

Comments

@keybuk
Copy link

keybuk commented Mar 3, 2025

Description of the bug:

When attempting to use label_flag to select a platform via a command-line flag, the following error occurs:

ERROR: BUILD.bazel:14:14: Target :with_secondary_platform was referenced as a platform, but does not provide PlatformInfo

Which category does this issue belong to?

Configurability

What's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.

To support microcontroller packages with multiple cores, we can pass the platform for the primary/startup core on the command line with --platforms; but can't make the platform for the secondary/co-processor core configurable in the same way:

Would like to be able to build with:

bazel build \
    --platforms=@//:primary_platform \
    --@//:with_secondary_platform=@//:secondary_platform \
    @//:primary_binary
load("@rules_platform//platform_data:defs.bzl", "platform_data")

# Platform for primary core specified with --platforms=@//:primary_platform
platform(
    name = "primary_platform",
    constraint_values = [
        "@platforms//cpu:armv8-m",
    ],
)

cc_binary(
    name = "primary_binary",
    target_compatible_with = [
        "@platforms//cpu:armv8-m",
    ],
    # Primary core binary builds and links secondary core binary via transition.
    deps = ["secondary_firmware"],
)

platform_data(
    name = "secondary_firmware",
    # We want the platform for the secondary code binary to be configurable,
    # e.g. with --@//:with_secondary_platform=@//:secondary_platform
    platform = ":with_secondary_platform",
    target = ":secondary_binary",
)

label_flag(
    name = "with_secondary_platform",
    # Set default to anything.
    build_setting_default = "@platforms//host",
)

platform(
    name = "secondary_platform",
    constraint_values = [
        "@platforms//cpu:armv6-m",
    ],
)

cc_binary(
    name = "secondary_binary",
    target_compatible_with = [
        "@platforms//cpu:armv6-m",
    ],
)

Which operating system are you running Bazel on?

Linux

What is the output of bazel info release?

release 8.1.0

If bazel info release returns development version or (@non-git), tell us how you built Bazel.

No response

What's the output of git remote get-url origin; git rev-parse HEAD ?


If this is a regression, please try to identify the Bazel commit where the bug was introduced with bazelisk --bisect.

No response

Have you found anything relevant by searching the web?

No response

Any other information, logs, or outputs that you want to share?

No response

@sgowroji sgowroji added the team-Configurability platforms, toolchains, cquery, select(), config transitions label Mar 4, 2025
@katre
Copy link
Member

katre commented Mar 4, 2025

Hmm, interesting.

The core problem is technical: when the target :secondary_firnmware is analyzed, the configuration has the flag --platforms=//:with_secondary_platform. However, to resolve the label_flag, it also needs to be analyzed, with a --platforms flag that points to itself, leading to a cycle and a failure.

What you really need is to resolve the label_flag before you set the --platforms flag in the transition. I would suggest writing a custom rule and transition that does exactly that. The code for platform_data is actually pretty simple, can you try giving that a shot?

I'm not sure this is something Bazel can easily do automatically, the core issue is that the ordering of analysis is backwards in your example.

@keybuk
Copy link
Author

keybuk commented Mar 4, 2025

I can definitely modify platform_data to suit our needs, but I don’t know how to go about resolving the label_flag within the rule implementation. Do you have an example or sample code that I can reference to get started?

@fmeum
Copy link
Collaborator

fmeum commented Mar 4, 2025

You probably don't even need a label_flag: You can use a string_flag instead, make it an implicit dependency of your rule and then access it in a custom transition to set --platforms to the value of the flag.

@keybuk
Copy link
Author

keybuk commented Mar 5, 2025

Whether I use a label_flag or string_flag, the transition implementation function always gets the name of the label_flag or string_flag, not the value of the flag

@fmeum
Copy link
Collaborator

fmeum commented Mar 5, 2025

That doesn't seem right, could you post your code?

@keybuk
Copy link
Author

keybuk commented Mar 5, 2025

@fmeum sure, here's the BUILD.bazel:

load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
load(":defs.bzl", "platform_target")

string_flag(
    name = "target_platform",
    build_setting_default = "@//platforms:host",
)

platform_target(
    name = "my_target",
    binary = "//anything",  # any cc_binary
)

and defs.bzl:

load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")

def _platform_target_transition_impl(settings, attr):
    print("platform: " + repr(attr._platform))
    return {
        "//command_line_option:platforms": str(attr._platform),
    }

_platform_target_transition = transition(
    implementation = _platform_target_transition_impl,
    inputs = ["//:target_platform"],
    outputs = [
        "//command_line_option:platforms",
    ],
)

def _platform_target_impl(ctx):
    print("Impl")
    print("- binary: " + repr(ctx.executable.binary))
    print("- platform: " + repr(ctx.attr._platform))
    return DefaultInfo(
        files = depset(ctx.files.binary),
    )

platform_target = rule(
    implementation = _platform_target_impl,
    cfg = _platform_target_transition,
    attrs = {
        "binary": attr.label(
            mandatory = True,
            executable = True,
            cfg = "target",
        ),
        "_platform": attr.label(default = Label("//test:target_platform")),
        "_allowlist_function_transition": attr.label(
            default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
        ),
    },
)

Then bazel build --@//:target_platform=//any/platform @//:my_target

DEBUG: defs.bzl:4:10: platform: Label("//test:target_platform")
ERROR: BUILD.bazel:9:16: Target //test:target_platform was referenced as a platform, but does not provide PlatformInfo
ERROR: Analysis of target '//:my_target' failed; build aborted

See how in the transition impl, only the label name is available, not the value. There's no way to get providers here either

@fmeum
Copy link
Collaborator

fmeum commented Mar 6, 2025

Oh, I see. Does attr._platform not have BuildSettingInfo available? You may have to switch to a transition on a dependency edge rather than a transition on the rule to get access to providers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
team-Configurability platforms, toolchains, cquery, select(), config transitions type: bug untriaged
Projects
None yet
Development

No branches or pull requests

6 participants