github.com/bazelbuild/rules_go@v0.47.2-0.20240515105122-e7ddb9ea474e/go/private/rules/cross.bzl (about)

     1  # Copyright 2022 The Bazel Authors. All rights reserved.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #    http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  
    15  load(
    16      "//go/private:providers.bzl",
    17      "GoArchive",
    18      "GoLibrary",
    19      "GoSource",
    20  )
    21  load(
    22      "//go/private/rules:transition.bzl",
    23      "go_cross_transition",
    24  )
    25  
    26  def _is_windows(ctx):
    27      return ctx.configuration.host_path_separator == ";"
    28  
    29  WINDOWS_ERR_SCRIPT = """
    30  @echo off
    31  >&2 echo {}
    32  exit /b 1
    33  """
    34  UNIX_ERR_SCRIPT = """
    35  >&2 echo '{}'
    36  exit 1
    37  """
    38  
    39  def _error_script(ctx):
    40      errmsg = 'cannot run go_cross target "{}": underlying target "{}" is not executable'.format(
    41          ctx.attr.name,
    42          ctx.attr.target.label,
    43      )
    44      if _is_windows(ctx):
    45          error_script = ctx.actions.declare_file("fake_executable_for_bazel_run.bat")
    46          ctx.actions.write(error_script, WINDOWS_ERR_SCRIPT.format(errmsg), is_executable = True)
    47          return error_script
    48  
    49      error_script = ctx.actions.declare_file("fake_executable_for_bazel_run")
    50      ctx.actions.write(error_script, UNIX_ERR_SCRIPT.format(errmsg), is_executable = True)
    51      return error_script
    52  
    53  def _go_cross_impl(ctx):
    54      old_default_info = ctx.attr.target[DefaultInfo]
    55      old_executable = old_default_info.files_to_run.executable
    56  
    57      new_default_info = None
    58      if old_executable:
    59          # Bazel requires executable rules to created the executable themselves,
    60          # so we create a symlink in this rule so that it appears this rule created its executable.
    61          new_executable = ctx.actions.declare_file(ctx.attr.name)
    62          ctx.actions.symlink(output = new_executable, target_file = old_executable)
    63          new_default_info = DefaultInfo(
    64              files = depset([new_executable]),
    65              runfiles = old_default_info.default_runfiles,
    66              executable = new_executable,
    67          )
    68      else:
    69          # There's no way to determine if the underlying `go_binary` target is executable at loading time
    70          # so we must set the `go_cross` rule to be always executable. If the `go_binary` target is not
    71          # executable, we set the `go_cross` executable to a simple script that prints an error message
    72          # when executed. This way users can still run a `go_cross` target using `bazel run` as long as
    73          # the underlying `go_binary` target is executable.
    74          error_script = _error_script(ctx)
    75  
    76          # See the implementation of `go_binary` for an explanation of the need for default vs data runfiles here.
    77          new_default_info = DefaultInfo(
    78              files = depset([error_script] + old_default_info.files.to_list()),
    79              default_runfiles = old_default_info.default_runfiles,
    80              data_runfiles = old_default_info.data_runfiles.merge(ctx.runfiles([error_script])),
    81              executable = error_script,
    82          )
    83  
    84      providers = [
    85          ctx.attr.target[provider]
    86          for provider in [
    87              GoLibrary,
    88              GoSource,
    89              GoArchive,
    90              OutputGroupInfo,
    91              CcInfo,
    92          ]
    93          if provider in ctx.attr.target
    94      ]
    95      return [new_default_info] + providers
    96  
    97  _go_cross_kwargs = {
    98      "implementation": _go_cross_impl,
    99      "attrs": {
   100          "target": attr.label(
   101              doc = """Go binary target to transition to the given platform and/or sdk_version.
   102              """,
   103              providers = [GoLibrary, GoSource, GoArchive],
   104              mandatory = True,
   105          ),
   106          "platform": attr.label(
   107              doc = """The platform to cross compile the `target` for.
   108              If unspecified, the `target` will be compiled with the
   109              same platform as it would've with the original `go_binary` rule.
   110              """,
   111          ),
   112          "sdk_version": attr.string(
   113              doc = """The golang SDK version to use for compiling the `target`.
   114              Supports specifying major, minor, and/or patch versions, eg. `"1"`,
   115              `"1.17"`, or `"1.17.1"`. The first Go SDK provider installed in the
   116              repo's workspace (via `go_download_sdk`, `go_wrap_sdk`, etc) that
   117              matches the specified version will be used for compiling the given
   118              `target`. If unspecified, the `target` will be compiled with the same
   119              SDK as it would've with the original `go_binary` rule.
   120              Transitions `target` by changing the `--@io_bazel_rules_go//go/toolchain:sdk_version`
   121              build flag to the value provided for `sdk_version` here.
   122              """,
   123          ),
   124          "_allowlist_function_transition": attr.label(
   125              default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
   126          ),
   127      },
   128      "cfg": go_cross_transition,
   129      "doc": """This wraps an executable built by `go_binary` to cross compile it
   130      for a different platform, and/or compile it using a different version
   131      of the golang SDK.<br><br>
   132      **Providers:**
   133      <ul>
   134        <li>[GoLibrary]</li>
   135        <li>[GoSource]</li>
   136        <li>[GoArchive]</li>
   137      </ul>
   138      """,
   139  }
   140  
   141  go_cross_binary = rule(executable = True, **_go_cross_kwargs)