1# Copyright 2019 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"""native_binary() and native_test() rule implementations. 16 17These rules let you wrap a pre-built binary or script in a conventional binary 18and test rule respectively. They fulfill the same goal as sh_binary and sh_test 19do, but they run the wrapped binary directly, instead of through Bash, so they 20don't depend on Bash and work with --shell_executable="". 21""" 22 23def _impl_rule(ctx): 24 out = ctx.actions.declare_file(ctx.attr.out if (ctx.attr.out != "") else ctx.attr.name + ".exe") 25 ctx.actions.symlink( 26 target_file = ctx.executable.src, 27 output = out, 28 is_executable = True, 29 ) 30 runfiles = ctx.runfiles(files = ctx.files.data) 31 32 # Bazel 4.x LTS does not support `merge_all`. 33 # TODO: remove `merge` branch once we drop support for Bazel 4.x. 34 if hasattr(runfiles, "merge_all"): 35 runfiles = runfiles.merge_all([ 36 d[DefaultInfo].default_runfiles 37 for d in ctx.attr.data + [ctx.attr.src] 38 ]) 39 else: 40 for d in ctx.attr.data: 41 runfiles = runfiles.merge(d[DefaultInfo].default_runfiles) 42 runfiles = runfiles.merge(ctx.attr.src[DefaultInfo].default_runfiles) 43 44 return DefaultInfo( 45 executable = out, 46 files = depset([out]), 47 runfiles = runfiles, 48 ) 49 50_ATTRS = { 51 "src": attr.label( 52 executable = True, 53 # This must be used instead of `allow_single_file` because otherwise a 54 # target with multiple default outputs (e.g. py_binary) would not be 55 # allowed. 56 allow_files = True, 57 mandatory = True, 58 cfg = "target", 59 doc = "path of the pre-built executable", 60 ), 61 "data": attr.label_list( 62 allow_files = True, 63 doc = "data dependencies. See" + 64 " https://bazel.build/reference/be/common-definitions#typical.data", 65 ), 66 # "out" is attr.string instead of attr.output, so that it is select()'able. 67 "out": attr.string( 68 default = "", 69 doc = "An output name for the copy of the binary. Defaults to " + 70 "name.exe. (We add .exe to the name by default because it's " + 71 "required on Windows and tolerated on other platforms.)", 72 ), 73} 74 75native_binary = rule( 76 implementation = _impl_rule, 77 attrs = _ATTRS, 78 executable = True, 79 doc = """ 80Wraps a pre-built binary or script with a binary rule. 81 82You can "bazel run" this rule like any other binary rule, and use it as a tool 83in genrule.tools for example. You can also augment the binary with runfiles. 84""", 85) 86 87native_test = rule( 88 implementation = _impl_rule, 89 attrs = _ATTRS, 90 test = True, 91 doc = """ 92Wraps a pre-built binary or script with a test rule. 93 94You can "bazel test" this rule like any other test rule. You can also augment 95the binary with runfiles. 96""", 97) 98