-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[ABLD-395] Framework to create toolchains for OS provided tools #54177
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
Changes from 12 commits
89d365f
446ae55
f40e478
cad9410
3f1e8f1
c2c8ed3
92c9996
c6e763d
33693b5
8626718
37609a1
b8787a5
3c43004
97bc86b
63df4c2
b9814f4
055806a
d9d76a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| """toolchain to wrap the codesign binary. | ||
|
|
||
| Type: @codesign//:codesign_toolchain_type | ||
|
|
||
| Toolchains: | ||
| - @codesign//:codesign_toolchain: provides the tool | ||
| - @codesign//:codesign_missing_toolchain: provides a fallback toolchain for | ||
| exec platforms where codesign might not be available. | ||
| """ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| """Repository rule to autoconfigure a toolchain using the system codesign.""" | ||
|
|
||
| load("//bazel/toolchains/common:defs.bzl", "make_repo_builder") | ||
|
|
||
| # This must match the repository name used by register_toolchains in consuming MODULE.bazel files. | ||
| NAME = "macos_codesign" | ||
|
|
||
| find_macos_codesign = make_repo_builder(name = NAME, tool_name = "codesign") |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| # //bazel/toolchains/common |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| """Utilitites for creating toolchains to wrap system provided tools.""" | ||
|
|
||
| def _write_toolchain_repo(rctx, repo_name, tool_name, tool_path, tool_version = "<unknown>", exec_compatible_with = None): | ||
| if not tool_path: | ||
| tool_path = "" | ||
| rctx.template( | ||
| "BUILD", | ||
| Label("@@//bazel/toolchains/common:toolchain_BUILD.tpl"), | ||
| substitutions = { | ||
| "{AVAILABLE}": "1" if tool_path else "0", | ||
| "{EXEC_COMPATIBLE_WITH}": repr(exec_compatible_with), | ||
| "{GENERATOR}": "//bazel/toolchains/common:defs.bzl", | ||
| "{REPO_NAME}": repo_name, | ||
| "{TOOL_NAME}": tool_name, | ||
| "{TOOL_PATH}": str(tool_path), | ||
| "{TOOL_VERSION}": tool_version, | ||
| }, | ||
| executable = False, | ||
| ) | ||
| rctx.template( | ||
| "defs.bzl", | ||
| Label("@@//bazel/toolchains/common:toolchain_defs.bzl.tpl"), | ||
| substitutions = { | ||
| "{AVAILABLE}": "1" if tool_path else "0", | ||
| "{GENERATOR}": "//bazel/toolchains/common:defs.bzl", | ||
| "{REPO_NAME}": repo_name, | ||
| "{TOOL_NAME}": tool_name, | ||
| }, | ||
| executable = False, | ||
| ) | ||
|
|
||
| def _default_repo_builder_impl(rctx): | ||
| tool_name = rctx.attr.tool_name | ||
| tool_path = rctx.which(tool_name) | ||
| if rctx.attr.verbose: | ||
| if tool_path: | ||
| print("Found %s at '%s'" % (tool_name, tool_path)) # buildifier: disable=print | ||
| else: | ||
| print("No system %s found." % tool_name) # buildifier: disable=print | ||
| _write_toolchain_repo( | ||
| rctx = rctx, | ||
| repo_name = rctx.original_name, | ||
| tool_name = rctx.attr.tool_name, | ||
| tool_path = tool_path, | ||
| exec_compatible_with = rctx.attr.exec_compatible_with, | ||
| ) | ||
|
|
||
| def make_repo_builder(name, tool_name, impl = _default_repo_builder_impl): | ||
| return repository_rule( | ||
| implementation = impl, | ||
| doc = """Create a repository that defines a {name} toolchain based on tool in the default $PATH.""".format(name = name), | ||
| local = True, | ||
| environ = ["PATH"], | ||
| attrs = { | ||
| "tool_name": attr.string(doc = "The name of the tool to find.", default = tool_name), | ||
| "exec_compatible_with": attr.string_list( | ||
| doc = "exec_compatible_with list to apply to the created toolchain.", | ||
| ), | ||
| "verbose": attr.bool( | ||
| doc = "If true, print status messages.", | ||
| ), | ||
| }, | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # This content is generated by {GENERATOR} | ||
| load(":defs.bzl", "is_{TOOL_NAME}_available", "{TOOL_NAME}_toolchain") | ||
|
|
||
| toolchain_type( | ||
| name = "{TOOL_NAME}_toolchain_type", | ||
| visibility = ["//visibility:public"], | ||
| ) | ||
|
|
||
| {TOOL_NAME}_toolchain( | ||
| name = "{TOOL_NAME}_auto", | ||
| path = "{TOOL_PATH}", | ||
| version = "{TOOL_VERSION}", | ||
| ) | ||
|
|
||
| toolchain( | ||
| name = "{TOOL_NAME}_toolchain", | ||
| toolchain = ":{TOOL_NAME}_auto", | ||
| toolchain_type = ":{TOOL_NAME}_toolchain_type", | ||
| exec_compatible_with = {EXEC_COMPATIBLE_WITH}, | ||
| ) | ||
|
alopezz marked this conversation as resolved.
|
||
|
|
||
| # {TOOL_NAME}_missing_toolchain provides a fallback toolchain so that toolchain | ||
| # resolution can succeed even on platforms that do not have that tool. | ||
| # If this toolchain is selected, the constraint ":have_{TOOL_NAME}" will not be satistifed, | ||
| # so that can be used with with exec_compatible_with clauses. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you check whether it can actually be used in According to https://bazel.build/reference/be/platforms-and-toolchains#toolchain_args, only
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right it can't be used there. I got ahead of myself. We were going to unify constraint_value and config_setting but never got around to it. A rule using it would have to examine the valid field. |
||
| {TOOL_NAME}_toolchain( | ||
| name = "no_{TOOL_NAME}", | ||
| ) | ||
|
|
||
| toolchain( | ||
| name = "zzz_{TOOL_NAME}_missing_toolchain", # keep name lexicographically last | ||
| toolchain = ":no_{TOOL_NAME}", | ||
| toolchain_type = ":{TOOL_NAME}_toolchain_type", | ||
| ) | ||
|
|
||
| # Expose the availability of the actual tool as a flag, so we can | ||
| # create a config_setting from it. | ||
| is_{TOOL_NAME}_available( | ||
|
alopezz marked this conversation as resolved.
|
||
| name = "is_{TOOL_NAME}_available", | ||
| build_setting_default = {AVAILABLE}, | ||
|
alopezz marked this conversation as resolved.
|
||
| ) | ||
|
|
||
| # Expose the availability of the toolchain as a config_setting, so we can | ||
| # select() on it. | ||
| config_setting( | ||
| name = "have_{TOOL_NAME}", | ||
| flag_values = { | ||
| ":is_{TOOL_NAME}_available": "1", | ||
| }, | ||
| visibility = ["//visibility:public"], | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| """toolchain to provide the {TOOL_NAME} binary.""" | ||
|
|
||
| load("@@//bazel/toolchains:toolchain_info.bzl", "ToolInfo") | ||
|
|
||
| def _{TOOL_NAME}_toolchain_impl(ctx): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And another question that I have is whether we actually need to be templated with the TOOL_NAME baked in or whether a single common rule can be used to define all these toolchains instead.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For just the two I have done, yes. But that gets in the way of future expansion, where I want different things to customize the template. pkgbuild and codesign, do not have I have that ready in another PR, but it's not needed yet. Essentially the repo_builder call will use a private impl function instead of the default, and your private impl will call do the lookup and then call |
||
| if ctx.attr.label and ctx.attr.path: | ||
| fail("{TOOL_NAME}_toolchain must not specify both label and path.") | ||
| valid = bool(ctx.attr.label) or bool(ctx.attr.path) | ||
| toolchain_info = platform_common.ToolchainInfo( | ||
| {TOOL_NAME} = ToolInfo( | ||
| name = str(ctx.label), | ||
| valid = valid, | ||
| label = ctx.attr.label, | ||
| path = ctx.attr.path, | ||
| version = ctx.attr.version, | ||
| ), | ||
| ) | ||
| return [toolchain_info] | ||
|
|
||
| {TOOL_NAME}_toolchain = rule( | ||
| implementation = _{TOOL_NAME}_toolchain_impl, | ||
| attrs = { | ||
| "label": attr.label( | ||
| doc = "A valid label of a target to build or a prebuilt binary. Mutually exclusive with path.", | ||
| cfg = "exec", | ||
| executable = True, | ||
| allow_files = True, | ||
| ), | ||
| "path": attr.string( | ||
| doc = "The path to the executable. Mutually exclusive with label.", | ||
| ), | ||
| "version": attr.string( | ||
| doc = "The version string of the executable. This should be manually set.", | ||
| ), | ||
| }, | ||
| ) | ||
|
|
||
| # Expose the presence of {TOOL_NAME} as a flag. | ||
| def _is_{TOOL_NAME}_available_impl(ctx): | ||
| return [config_common.FeatureFlagInfo( | ||
| value = ("1" if ctx.build_setting_value else "0"), | ||
| )] | ||
|
|
||
| is_{TOOL_NAME}_available = rule( | ||
| implementation = _is_{TOOL_NAME}_available_impl, | ||
| attrs = {}, | ||
| build_setting = config.bool(flag = False), | ||
| ) | ||
|
aiuto marked this conversation as resolved.
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| """Toolchain to wrap the pkgbuild binary. | ||
|
|
||
| Type: @macos_pkgbuild//:tool_toolchain_type | ||
|
|
||
| Toolchains: | ||
| - @macos_pkgbuild//:macos_pkgbuild_toolchain: provides the tool | ||
| - @macos_pkgbuild//:macos_pkgbuild_missing_toolchain: provides a fallback toolchain for exec platforms where pkgbuild might not be available. | ||
| """ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| """Repository rule to autoconfigure a toolchain using the system pkgbuild.""" | ||
|
|
||
| load("//bazel/toolchains/common:defs.bzl", "make_repo_builder") | ||
|
|
||
| # This must match the name used by register_toolchains in MODULE.bazel. | ||
| NAME = "macos_pkgbuild" | ||
|
|
||
| find_macos_pkgbuild = make_repo_builder(name = NAME, tool_name = "pkgbuild") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This name seems to describe the function poorly. Probably something like
local_toolchain_repositorywould be more apt.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not that either, because it doesn't make the repository. It returns a rule, that you have to call to make the thing you want. So it's really a builder pattern. Think of the expansion in MODULE.bazel. It would be
So, maybe we rename
find_macos_pkgbuild. Maybe "os_provided_macos_pkgbuild".That's wordy, but more accurate.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair, but the name is still a bit too generic, it could be something like
make_local_toolchain_repository_ruleormake_os_provided_tool_repo_ruleor similar, at least something that points at this being intended to wrap local tools would be desirable in my opinion.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to
make_local_toolchain_repository_rule