1# Copyright 2018 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""" A library of functions creating structs for CcToolchainConfigInfo.""" 16 17def _check_is_none(obj, parameter_name, method_name): 18 if obj != None: 19 fail("{} parameter of {} should be None, found {}." 20 .format(parameter_name, method_name, type(obj))) 21 22def _check_is_none_or_right_type(obj, obj_of_right_type, parameter_name, method_name): 23 if obj != None: 24 _check_same_type(obj, obj_of_right_type, parameter_name, method_name) 25 26def _check_right_type(obj, expected_type, parameter_name, method_name): 27 if type(obj) != expected_type: 28 fail("{} parameter of {} should be a {}, found {}." 29 .format(parameter_name, method_name, expected_type, type(obj))) 30 31def _check_same_type(obj, obj_of_right_type, parameter_name, method_name): 32 _check_right_type(obj, type(obj_of_right_type), parameter_name, method_name) 33 34def _check_is_nonempty_string(obj, parameter_name, method_name): 35 _check_same_type(obj, "", parameter_name, method_name) 36 if obj == "": 37 fail("{} parameter of {} must be a nonempty string." 38 .format(parameter_name, method_name)) 39 40def _check_is_nonempty_list(obj, parameter_name, method_name): 41 _check_same_type(obj, [], parameter_name, method_name) 42 if len(obj) == 0: 43 fail("{} parameter of {} must be a nonempty list." 44 .format(parameter_name, method_name)) 45 46EnvEntryInfo = provider( 47 "A key/value pair to be added as an environment variable.", 48 fields = ["key", "value", "expand_if_available", "type_name"], 49) 50 51def env_entry(key, value, expand_if_available = None): 52 """ A key/value pair to be added as an environment variable. 53 54 The returned EnvEntry provider finds its use in EnvSet creation through 55 the env_entries parameter of env_set(); EnvSet groups environment variables 56 that need to be expanded for specific actions. 57 The value of this pair is expanded in the same way as is described in 58 flag_group. The key remains an unexpanded string literal. 59 60 Args: 61 key: a string literal representing the name of the variable. 62 value: the value to be expanded. 63 expand_if_available: A build variable that needs to be available 64 in order to expand the env_entry. 65 66 Returns: 67 An EnvEntryInfo provider. 68 """ 69 _check_is_nonempty_string(key, "key", "env_entry") 70 _check_is_nonempty_string(value, "value", "env_entry") 71 _check_is_none_or_right_type(expand_if_available, "string", "expand_if_available", "env_entry") 72 return EnvEntryInfo( 73 key = key, 74 value = value, 75 expand_if_available = expand_if_available, 76 type_name = "env_entry", 77 ) 78 79VariableWithValueInfo = provider( 80 "Represents equality check between a variable and a certain value.", 81 fields = ["name", "value", "type_name"], 82) 83 84def variable_with_value(name, value): 85 """ Represents equality check between a variable and a certain value. 86 87 The returned provider finds its use through flag_group.expand_if_equal, 88 making the expansion of the flag_group conditional on the value of the 89 variable. 90 91 Args: 92 name: name of the variable. 93 value: the value the variable should be compared against. 94 95 Returns: 96 A VariableWithValueInfo provider. 97 """ 98 _check_is_nonempty_string(name, "name", "variable_with_value") 99 _check_is_nonempty_string(value, "value", "variable_with_value") 100 return VariableWithValueInfo( 101 name = name, 102 value = value, 103 type_name = "variable_with_value", 104 ) 105 106MakeVariableInfo = provider( 107 "A make variable that is made accessible to rules.", 108 fields = ["name", "value", "type_name"], 109) 110 111def make_variable(name, value): 112 """ A make variable that is made accessible to rules.""" 113 _check_is_nonempty_string(name, "name", "make_variable") 114 _check_is_nonempty_string(value, "value", "make_variable") 115 return MakeVariableInfo( 116 name = name, 117 value = value, 118 type_name = "make_variable", 119 ) 120 121FeatureSetInfo = provider( 122 "A set of features.", 123 fields = ["features", "type_name"], 124) 125 126def feature_set(features = []): 127 """ A set of features. 128 129 Used to support logical 'and' when specifying feature requirements in a 130 feature. 131 132 Args: 133 features: A list of unordered feature names. 134 135 Returns: 136 A FeatureSetInfo provider. 137 """ 138 _check_same_type(features, [], "features", "feature_set") 139 return FeatureSetInfo(features = features, type_name = "feature_set") 140 141WithFeatureSetInfo = provider( 142 "A set of positive and negative features.", 143 fields = ["features", "not_features", "type_name"], 144) 145 146def with_feature_set(features = [], not_features = []): 147 """ A set of positive and negative features. 148 149 This stanza will evaluate to true when every 'feature' is enabled, and 150 every 'not_feature' is not enabled. 151 152 Args: 153 features: A list of feature names that need to be enabled. 154 not_features: A list of feature names that need to not be enabled. 155 156 Returns: 157 A WithFeatureSetInfo provider. 158 """ 159 _check_same_type(features, [], "features", "with_feature_set") 160 _check_same_type(not_features, [], "not_features", "with_feature_set") 161 return WithFeatureSetInfo( 162 features = features, 163 not_features = not_features, 164 type_name = "with_feature_set", 165 ) 166 167EnvSetInfo = provider( 168 "Groups a set of environment variables to apply for certain actions.", 169 fields = ["actions", "env_entries", "with_features", "type_name"], 170) 171 172def env_set(actions, env_entries = [], with_features = []): 173 """ Groups a set of environment variables to apply for certain actions. 174 175 EnvSet providers are passed to feature() and action_config(), to be applied to 176 the actions they are specified for. 177 178 Args: 179 actions: A list of actions this env set applies to; each env set must 180 specify at least one action. 181 env_entries: A list of EnvEntry - the environment variables applied 182 via this env set. 183 with_features: A list of feature sets defining when this env set gets 184 applied. The env set will be applied when any one of the feature 185 sets evaluate to true. (That is, when when every 'feature' is 186 enabled, and every 'not_feature' is not enabled.) 187 If 'with_features' is omitted, the env set will be applied 188 unconditionally for every action specified. 189 190 Returns: 191 An EnvSetInfo provider. 192 """ 193 _check_is_nonempty_list(actions, "actions", "env_set") 194 _check_same_type(env_entries, [], "env_entries", "env_set") 195 _check_same_type(with_features, [], "with_features", "env_set") 196 return EnvSetInfo( 197 actions = actions, 198 env_entries = env_entries, 199 with_features = with_features, 200 type_name = "env_set", 201 ) 202 203FlagGroupInfo = provider( 204 "A group of flags. Supports parametrization via variable expansion.", 205 fields = [ 206 "flags", 207 "flag_groups", 208 "iterate_over", 209 "expand_if_available", 210 "expand_if_not_available", 211 "expand_if_true", 212 "expand_if_false", 213 "expand_if_equal", 214 "type_name", 215 ], 216) 217 218def flag_group( 219 flags = [], 220 flag_groups = [], 221 iterate_over = None, 222 expand_if_available = None, 223 expand_if_not_available = None, 224 expand_if_true = None, 225 expand_if_false = None, 226 expand_if_equal = None): 227 """ A group of flags. Supports parametrization via variable expansion. 228 229 To expand a variable of list type, flag_group has to be annotated with 230 `iterate_over` message. Then all nested flags or flag_groups will be 231 expanded repeatedly for each element of the list. 232 For example: 233 flag_group( 234 iterate_over = 'include_path', 235 flags = ['-I', '%{include_path}'], 236 ) 237 ... will get expanded to -I /to/path1 -I /to/path2 ... for each 238 include_path /to/pathN. 239 240 To expand a variable of structure type, use dot-notation, e.g.: 241 flag_group( 242 iterate_over = "libraries_to_link", 243 flag_groups = [ 244 flag_group( 245 iterate_over = "libraries_to_link.libraries", 246 flags = ["-L%{libraries_to_link.libraries.directory}"], 247 ) 248 ] 249 ) 250 251 Flag groups can be nested; if they are, the flag group must only contain 252 other flag groups (no flags) so the order is unambiguously specified. 253 In order to expand a variable of nested lists, 'iterate_over' can be used. 254 For example: 255 flag_group ( 256 iterate_over = 'object_files', 257 flag_groups = [ 258 flag_group ( 259 flags = ['--start-lib'], 260 ), 261 flag_group ( 262 iterate_over = 'object_files', 263 flags = ['%{object_files}'], 264 ), 265 flag_group ( 266 flags = ['--end-lib'], 267 ) 268 ] 269 ) 270 ... will get expanded to 271 --start-lib a1.o a2.o ... --end-lib --start-lib b1.o b2.o .. --end-lib 272 with %{object_files} being a variable of nested list type 273 [['a1.o', 'a2.o', ...], ['b1.o', 'b2.o', ...], ...]. 274 275 Args: 276 flags: a string list, representing flags. Only one of flags and 277 flag_groups can be set, as to avoid ambiguity. 278 flag_groups: a list of FlagGroup entries. Only one of flags and 279 flag_groups can be set, as to avoid ambiguity. 280 iterate_over: a string, representing a variable of list type. 281 expand_if_available: A build variable that needs to be available 282 in order to expand the flag_group. 283 expand_if_not_available: A build variable that needs to be 284 unavailable in order for this flag_group to be expanded. 285 expand_if_true: if set, this variable needs to evaluate to True in 286 order for the flag_group to be expanded. 287 expand_if_false: if set, this variable needs to evalate to False in 288 order for the flag_group to be expanded. 289 expand_if_equal: a VariableWithValue, the flag_group is expanded in 290 case of equality. 291 292 Returns: 293 A FlagGroupInfo provider. 294 """ 295 296 _check_same_type(flags, [], "flags", "flag_group") 297 _check_same_type(flag_groups, [], "flag_groups", "flag_group") 298 if len(flags) > 0 and len(flag_groups) > 0: 299 fail("flag_group must not contain both a flag and another flag_group.") 300 if len(flags) == 0 and len(flag_groups) == 0: 301 fail("flag_group must contain either a list of flags or a list of flag_groups.") 302 _check_is_none_or_right_type(expand_if_true, "string", "expand_if_true", "flag_group") 303 _check_is_none_or_right_type(expand_if_false, "string", "expand_if_false", "flag_group") 304 _check_is_none_or_right_type(expand_if_available, "string", "expand_if_available", "flag_group") 305 _check_is_none_or_right_type( 306 expand_if_not_available, 307 "string", 308 "expand_if_not_available", 309 "flag_group", 310 ) 311 _check_is_none_or_right_type(iterate_over, "string", "iterate_over", "flag_group") 312 313 return FlagGroupInfo( 314 flags = flags, 315 flag_groups = flag_groups, 316 iterate_over = iterate_over, 317 expand_if_available = expand_if_available, 318 expand_if_not_available = expand_if_not_available, 319 expand_if_true = expand_if_true, 320 expand_if_false = expand_if_false, 321 expand_if_equal = expand_if_equal, 322 type_name = "flag_group", 323 ) 324 325FlagSetInfo = provider( 326 "A set of flags to be expanded in the command line for specific actions.", 327 fields = [ 328 "actions", 329 "with_features", 330 "flag_groups", 331 "type_name", 332 ], 333) 334 335def flag_set( 336 actions = [], 337 with_features = [], 338 flag_groups = []): 339 """ A set of flags to be expanded in the command line for specific actions. 340 341 Args: 342 actions: The actions this flag set applies to; each flag set must 343 specify at least one action. 344 with_features: A list of feature sets defining when this flag set gets 345 applied. The flag set will be applied when any one of the feature 346 sets evaluate to true. (That is, when when every 'feature' is 347 enabled, and every 'not_feature' is not enabled.) 348 If 'with_feature' is omitted, the flag set will be applied 349 unconditionally for every action specified. 350 flag_groups: A FlagGroup list - the flags applied via this flag set. 351 352 Returns: 353 A FlagSetInfo provider. 354 """ 355 _check_same_type(actions, [], "actions", "flag_set") 356 _check_same_type(with_features, [], "with_features", "flag_set") 357 _check_same_type(flag_groups, [], "flag_groups", "flag_set") 358 return FlagSetInfo( 359 actions = actions, 360 with_features = with_features, 361 flag_groups = flag_groups, 362 type_name = "flag_set", 363 ) 364 365FeatureInfo = provider( 366 "Contains all flag specifications for one feature.", 367 fields = [ 368 "name", 369 "enabled", 370 "flag_sets", 371 "env_sets", 372 "requires", 373 "implies", 374 "provides", 375 "type_name", 376 ], 377) 378 379def feature( 380 name, 381 enabled = False, 382 flag_sets = [], 383 env_sets = [], 384 requires = [], 385 implies = [], 386 provides = []): 387 """ Contains all flag specifications for one feature. 388 389 Args: 390 name: The feature's name. It is possible to introduce a feature without 391 a change to Bazel by adding a 'feature' section to the toolchain 392 and adding the corresponding string as feature in the BUILD file. 393 enabled: If 'True', this feature is enabled unless a rule type 394 explicitly marks it as unsupported. 395 flag_sets: A FlagSet list - If the given feature is enabled, the flag 396 sets will be applied for the actions are specified for. 397 env_sets: an EnvSet list - If the given feature is enabled, the env 398 sets will be applied for the actions they are specified for. 399 requires: A list of feature sets defining when this feature is 400 supported by the toolchain. The feature is supported if any of the 401 feature sets fully apply, that is, when all features of a feature 402 set are enabled. 403 If 'requires' is omitted, the feature is supported independently of 404 which other features are enabled. 405 Use this for example to filter flags depending on the build mode 406 enabled (opt / fastbuild / dbg). 407 implies: A string list of features or action configs that are 408 automatically enabled when this feature is enabled. If any of the 409 implied features or action configs cannot be enabled, this feature 410 will (silently) not be enabled either. 411 provides: A list of names this feature conflicts with. 412 A feature cannot be enabled if: 413 - 'provides' contains the name of a different feature or action 414 config that we want to enable. 415 - 'provides' contains the same value as a 'provides' in a 416 different feature or action config that we want to enable. 417 Use this in order to ensure that incompatible features cannot be 418 accidentally activated at the same time, leading to hard to 419 diagnose compiler errors. 420 421 Returns: 422 A FeatureInfo provider. 423 """ 424 _check_same_type(enabled, True, "enabled", "feature") 425 _check_same_type(flag_sets, [], "flag_sets", "feature") 426 _check_same_type(env_sets, [], "env_sets", "feature") 427 _check_same_type(requires, [], "requires", "feature") 428 _check_same_type(provides, [], "provides", "feature") 429 _check_same_type(implies, [], "implies", "feature") 430 return FeatureInfo( 431 name = name, 432 enabled = enabled, 433 flag_sets = flag_sets, 434 env_sets = env_sets, 435 requires = requires, 436 implies = implies, 437 provides = provides, 438 type_name = "feature", 439 ) 440 441ToolPathInfo = provider( 442 "Tool locations.", 443 fields = ["name", "path", "type_name"], 444) 445 446def tool_path(name, path): 447 """ Tool locations. 448 449 Args: 450 name: Name of the tool. 451 path: Location of the tool; Can be absolute path (in case of non hermetic 452 toolchain), or path relative to the cc_toolchain's package. 453 454 Returns: 455 A ToolPathInfo provider. 456 457 Deprecated: 458 Prefer specifying an ActionConfig for the action that needs the tool. 459 TODO(b/27903698) migrate to ActionConfig. 460 """ 461 _check_is_nonempty_string(name, "name", "tool_path") 462 _check_is_nonempty_string(path, "path", "tool_path") 463 return ToolPathInfo(name = name, path = path, type_name = "tool_path") 464 465ToolInfo = provider( 466 doc = "Tool information. This differs from ToolPathInfo as it is intended to be used\ 467 in action_configs and can accept labels.", 468 fields = [ 469 "path", 470 "tool", 471 "with_features", 472 "execution_requirements", 473 "type_name", 474 ], 475) 476 477def tool(path = None, with_features = [], execution_requirements = [], tool = None): 478 """ Describes a tool associated with a crosstool action config. 479 480 Args: 481 path: Location of the tool; Can be absolute path (in case of non hermetic 482 toolchain), or path relative to the cc_toolchain's package. If this 483 parameter is set, tool must not be set. 484 tool: The built-artifact that should be used as this tool. If this is 485 set, path must not be set. 486 with_features: A list of feature sets defining when this tool is 487 applicable. The tool will used when any one of the feature sets 488 evaluate to true. (That is, when when every 'feature' is enabled, 489 and every 'not_feature' is not enabled.) 490 If 'with_feature' is omitted, the tool will apply for any feature 491 configuration. 492 execution_requirements: Requirements on the execution environment for 493 the execution of this tool, to be passed as out-of-band "hints" to 494 the execution backend. 495 Ex. "requires-mem:24g" 496 497 Returns: 498 A ToolInfo provider. 499 """ 500 if path == None and tool == None: 501 fail("Parameter path or parameter tool of tool should not be None.") 502 503 if path != None: 504 _check_is_nonempty_string(path, "path", "tool") 505 _check_is_none(tool, "tool", "tool") 506 if tool != None: 507 _check_is_none(path, "path", "tool") 508 _check_right_type(tool, "File", "tool", "tool") 509 510 _check_same_type(with_features, [], "with_features", "tool") 511 _check_same_type(execution_requirements, [], "execution_requirements", "tool") 512 return ToolInfo( 513 path = path, 514 tool = tool, 515 with_features = with_features, 516 execution_requirements = execution_requirements, 517 type_name = "tool", 518 ) 519 520ActionConfigInfo = provider( 521 "Configuration of a Bazel action.", 522 fields = [ 523 "config_name", 524 "action_name", 525 "enabled", 526 "tools", 527 "flag_sets", 528 "implies", 529 "type_name", 530 ], 531) 532 533def action_config( 534 action_name, 535 enabled = False, 536 tools = [], 537 flag_sets = [], 538 implies = []): 539 """ Configuration of a Bazel action. 540 541 An action config corresponds to a Bazel action, and allows selection of 542 a tool based on activated features. 543 Action config activation occurs by the same semantics as features: a 544 feature can 'require' or 'imply' an action config in the same way that it 545 would another feature. 546 547 Args: 548 action_name: The name of the Bazel action that this config applies to, 549 ex. 'c-compile' or 'c-module-compile'. 550 enabled: If 'True', this action is enabled unless a rule type 551 explicitly marks it as unsupported. 552 tools: The tool applied to the action will be the first Tool with a 553 feature set that matches the feature configuration. An error will 554 be thrown if no tool matches a provided feature configuration - for 555 that reason, it's a good idea to provide a default tool with an 556 empty feature set. 557 flag_sets: If the given action config is enabled, the flag sets will be 558 applied to the corresponding action. 559 implies: A list of features or action configs that are automatically 560 enabled when this action config is enabled. If any of the implied 561 features or action configs cannot be enabled, this action config 562 will (silently) not be enabled either. 563 564 Returns: 565 An ActionConfigInfo provider. 566 """ 567 _check_is_nonempty_string(action_name, "name", "action_config") 568 _check_same_type(enabled, True, "enabled", "action_config") 569 _check_same_type(tools, [], "tools", "action_config") 570 _check_same_type(flag_sets, [], "flag_sets", "action_config") 571 _check_same_type(implies, [], "implies", "action_config") 572 return ActionConfigInfo( 573 action_name = action_name, 574 enabled = enabled, 575 tools = tools, 576 flag_sets = flag_sets, 577 implies = implies, 578 type_name = "action_config", 579 ) 580 581ArtifactNamePatternInfo = provider( 582 "The name for an artifact of a given category of input or output artifacts to an action.", 583 fields = [ 584 "category_name", 585 "prefix", 586 "extension", 587 "type_name", 588 ], 589) 590 591def artifact_name_pattern(category_name, prefix, extension): 592 """ The name for an artifact of a given category of input or output artifacts to an action. 593 594 Args: 595 category_name: The category of artifacts that this selection applies 596 to. This field is compared against a list of categories defined 597 in bazel. Example categories include "linked_output" or 598 "debug_symbols". An error is thrown if no category is matched. 599 prefix: The prefix for creating the artifact for this selection. 600 Together with the extension it is used to create an artifact name 601 based on the target name. 602 extension: The extension for creating the artifact for this selection. 603 Together with the prefix it is used to create an artifact name 604 based on the target name. 605 606 Returns: 607 An ArtifactNamePatternInfo provider 608 """ 609 _check_is_nonempty_string(category_name, "category_name", "artifact_name_pattern") 610 _check_is_none_or_right_type(prefix, "", "prefix", "artifact_name_pattern") 611 _check_is_none_or_right_type(extension, "", "extension", "artifact_name_pattern") 612 return ArtifactNamePatternInfo( 613 category_name = category_name, 614 prefix = prefix, 615 extension = extension, 616 type_name = "artifact_name_pattern", 617 ) 618