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)