Best way to discover the host platform from the rule implementation function

923 views
Skip to first unread message

Konstantin

unread,
Oct 13, 2022, 8:44:30 PM10/13/22
to bazel-discuss
It is frequently necessary to know current target platform and host platform in the rule implementation function. Historically I was doing it by adding "platform" attribute to the rule and setting it with select statement.

Recently I discovered that I can use "ctx.fragments.platform.platform" to find current target platform and it is much nicer than extra attribute and select to set it.

There is also ctx.fragments.platform.host_platform but unfortunately it seems to always return @local_config_platform//:host and I don't understand how this is helpful. Am I missing anything?

Thank you!
Konstantin

David Turner

unread,
Oct 17, 2022, 5:39:06 AM10/17/22
to Konstantin, bazel-discuss
This is intentional, a platform label points to a special item whose purpose is to set the values of specific constraint dimensions like "@platforms//os:os" or "@platforms//cpu:cpu".
The labels themselves could point anywhere, depending on a project's specific configuration, and are not meant for direct comparison at all.

@local_config_platform//:host is a label that points to a platform() definition that is part of the auto-generated @local_config_platform repository, whose content is created automatically by Bazel by probing the host system,
but one could use --host_platform=<label> in their .bazelrc file to point to something else (e.g. in my project, that would be something like --host_platform=//build/bazel/platforms:linux_x64)

So in other words, you cannot use these values in rule implementation functions to guess the host platform. Frankly I have no idea why these are exposed in fragments.

An alternative that would work for you is to have a custom repository that generates a .bzl file that exports the host system name as a constant, to be loaded in the .bzl files that implement your own rule implementation functions, e.g. something like:

# From your //:repository_rules.bzl
def _host_config_repository_rule_impl_(repo_ctx):
    repo_ctx.file('WORKSPACE.bazel', '')
    repo_ctx.file('BUILD.bazel', '')
    repo_ctx.file('defs.bzl', 'host_platform = %s'\n % repo_ctx.os.name)
 
host_config_repository = repository_rule(
    implementation = _host_config_repository_rule_impl)

# From your //:WORKSPACE.bzl
...
load("//:repository_rules.bzl", "host_config_repository")
host_config_repository(
    name = "host_config",
)

# From your own .bzl file defining rule implementation functions
load("@host_config//:defs.bzl", "host_platform")

def _my_rule_impl(ctx):
    if host_platform == "llinux":
       ....
   etc..

By this requires project-specific configuration. If you need to write something portable (i.e. a Bazel module that could be a dependency of any Bazel proejct), you should instead use select() statements that point to constraint dimensions directly,
e.g. select({ "@platforms//os:linux": [ .... ], "@platforms//os:mac": [ ... ], ...) that appear in rule definitions instead.

Hope this helps.

Thank you!
Konstantin

--
You received this message because you are subscribed to the Google Groups "bazel-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bazel-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/bazel-discuss/dbdeaa86-8620-481a-910c-9c698e5ef7edn%40googlegroups.com.

Konstantin

unread,
Oct 17, 2022, 12:28:08 PM10/17/22
to bazel-discuss
Thank you David for the explanation! 

To help other people who may find this conversation later I created a sample repo which demonstrates both techniques:  https://github.com/Bazel-snippets/host_platform

Konstantin

Reply all
Reply to author
Forward
0 new messages