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