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"""Bazel Flags.""" 16 17load("@rules_android//rules:utils.bzl", "utils") 18 19_BoolFlagInfo = provider( 20 doc = "Provides information about a boolean flag", 21 fields = dict( 22 name = "flag name", 23 value = "flag value", 24 explicit = "whether value was set explicitly", 25 ), 26) 27_BoolFlagGroupInfo = provider( 28 doc = "Provides information about a boolean flag group", 29 fields = dict( 30 name = "group name", 31 value = "group value", 32 flags = "flag names that belong to this group", 33 ), 34) 35_IntFlagInfo = provider( 36 doc = "Provides information about an integer flag", 37 fields = dict( 38 name = "flag name", 39 value = "flag value", 40 ), 41) 42_NativeBoolFlagInfo = provider( 43 doc = "Provides information about a native boolean flag", 44 fields = dict( 45 name = "flag name, the name of the native flag being accessed.", 46 value = "flag value, derived from config_setting targets that access the value", 47 ), 48) 49FlagsInfo = provider( 50 doc = "Provides all flags", 51) 52 53def _native_bool_impl(ctx): 54 return _NativeBoolFlagInfo( 55 name = ctx.label.name, 56 value = ctx.attr.value, 57 ) 58 59native_bool_flag = rule( 60 implementation = _native_bool_impl, 61 attrs = dict( 62 value = attr.bool(mandatory = True), 63 ), 64 provides = [_NativeBoolFlagInfo], 65) 66 67def native_bool_flag_macro(name, description): 68 """Provides access to a native boolean flag from Starlark. 69 70 Args: 71 name: The name of the native flag to access. 72 description: The description of the flag. 73 """ 74 native.config_setting( 75 name = name + "_on", 76 values = {name: "True"}, 77 ) 78 native.config_setting( 79 name = name + "_off", 80 values = {name: "False"}, 81 ) 82 native_bool_flag( 83 name = name, 84 value = select({ 85 (":" + name + "_on"): True, 86 (":" + name + "_off"): False, 87 }), 88 ) 89 90def _get_bool(v): 91 v = v.lower() 92 if v == "true": 93 return True 94 if v == "false": 95 return False 96 fail("Unknown bool: " + v) 97 98def _bool_impl(ctx): 99 if ctx.label.name in ctx.var: 100 value = _get_bool(ctx.var[ctx.label.name]) 101 return _BoolFlagInfo( 102 name = ctx.label.name, 103 value = value, 104 explicit = True, 105 ) 106 return _BoolFlagInfo( 107 name = ctx.label.name, 108 value = ctx.attr.default, 109 explicit = False, 110 ) 111 112bool_flag = rule( 113 implementation = _bool_impl, 114 attrs = dict( 115 default = attr.bool( 116 mandatory = True, 117 ), 118 description = attr.string( 119 mandatory = True, 120 ), 121 ), 122 provides = [_BoolFlagInfo], 123) 124 125def _bool_group_impl(ctx): 126 if ctx.label.name in ctx.var: 127 value = _get_bool(ctx.var[ctx.label.name]) 128 return _BoolFlagGroupInfo( 129 name = ctx.label.name, 130 value = value, 131 flags = [f[_BoolFlagInfo].name for f in ctx.attr.flags], 132 ) 133 return _BoolFlagGroupInfo( 134 name = ctx.label.name, 135 value = ctx.attr.default, 136 flags = [f[_BoolFlagInfo].name for f in ctx.attr.flags], 137 ) 138 139bool_flag_group = rule( 140 implementation = _bool_group_impl, 141 attrs = dict( 142 default = attr.bool( 143 mandatory = True, 144 ), 145 description = attr.string( 146 mandatory = True, 147 ), 148 flags = attr.label_list( 149 mandatory = True, 150 providers = [_BoolFlagInfo], 151 ), 152 ), 153 provides = [_BoolFlagGroupInfo], 154) 155 156def _int_impl(ctx): 157 if ctx.label.name in ctx.var: 158 value = int(ctx.var[ctx.label.name]) 159 else: 160 value = ctx.attr.default 161 return _IntFlagInfo( 162 name = ctx.label.name, 163 value = value, 164 ) 165 166int_flag = rule( 167 implementation = _int_impl, 168 attrs = dict( 169 default = attr.int( 170 mandatory = True, 171 ), 172 description = attr.string( 173 mandatory = True, 174 ), 175 ), 176 provides = [_IntFlagInfo], 177) 178 179def _flags_impl_internal(bool_flags, bool_flag_groups, int_flags, native_bool_flags): 180 flags = dict() 181 182 # For each group, set all flags to the group value 183 for fg in bool_flag_groups: 184 for f in fg.flags: 185 if f in flags: 186 fail("Flag '%s' referenced in multiple flag groups" % f) 187 flags[f] = fg.value 188 189 # Set booleans 190 for b in bool_flags: 191 # Always set explicitly specified flags 192 if b.explicit: 193 flags[b.name] = b.value 194 # If not explicit, only set when not set by a group 195 196 elif b.name not in flags: 197 flags[b.name] = b.value 198 199 # Set ints 200 for i in int_flags: 201 flags[i.name] = i.value 202 203 # Set native bool flags 204 for n in native_bool_flags: 205 if n.name in flags: 206 fail("Flag '%s' defined as both native and non-native flag type" % n.name) 207 flags[n.name] = n.value 208 209 return FlagsInfo(**flags) 210 211def _flags_impl(ctx): 212 return _flags_impl_internal( 213 utils.collect_providers(_BoolFlagInfo, ctx.attr.targets), 214 utils.collect_providers(_BoolFlagGroupInfo, ctx.attr.targets), 215 utils.collect_providers(_IntFlagInfo, ctx.attr.targets), 216 utils.collect_providers(_NativeBoolFlagInfo, ctx.attr.targets), 217 ) 218 219flags_rule = rule( 220 implementation = _flags_impl, 221 attrs = dict( 222 targets = attr.label_list(), 223 ), 224) 225 226def _flags_macro(): 227 flags_rule( 228 name = "flags", 229 targets = native.existing_rules().keys(), 230 visibility = ["//visibility:public"], 231 ) 232 233def _get_flags(ctx): 234 return ctx.attr._flags[FlagsInfo] 235 236flags = struct( 237 DEFINE_bool = bool_flag, 238 DEFINE_bool_group = bool_flag_group, 239 DEFINE_int = int_flag, 240 EXPOSE_native_bool = native_bool_flag_macro, 241 FLAGS = _flags_macro, 242 FlagsInfo = FlagsInfo, 243 get = _get_flags, 244) 245 246exported_for_test = struct( 247 BoolFlagGroupInfo = _BoolFlagGroupInfo, 248 BoolFlagInfo = _BoolFlagInfo, 249 IntFlagInfo = _IntFlagInfo, 250 NativeBoolFlagInfo = _NativeBoolFlagInfo, 251 bool_impl = _bool_impl, 252 flags_impl_internal = _flags_impl_internal, 253 int_impl = _int_impl, 254 native_bool_flag_macro = native_bool_flag_macro, 255) 256