|  | # pylint: disable=g-bad-file-header | 
|  | # Copyright 2018 The Bazel Authors. All rights reserved. | 
|  | # | 
|  | # Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | # you may not use this file except in compliance with the License. | 
|  | # You may obtain a copy of the License at | 
|  | # | 
|  | #    http://www.apache.org/licenses/LICENSE-2.0 | 
|  | # | 
|  | # Unless required by applicable law or agreed to in writing, software | 
|  | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | # See the License for the specific language governing permissions and | 
|  | # limitations under the License. | 
|  | """Utility functions for writing crosstool files in Skylark""" | 
|  |  | 
|  | # All possible C++ compile actions | 
|  | COMPILE_ACTIONS = [ | 
|  | "c-compile", | 
|  | "c++-compile", | 
|  | "c++-header-parsing", | 
|  | "c++-module-compile", | 
|  | "c++-module-codegen", | 
|  | "assemble", | 
|  | "preprocess-assemble", | 
|  | "clif-match", | 
|  | "linkstamp-compile", | 
|  | "cc-flags-make-variable", | 
|  | ] | 
|  |  | 
|  | # All possible C++ link actions | 
|  | LINK_ACTIONS = [ | 
|  | "c++-link-executable", | 
|  | "c++-link-dynamic-library", | 
|  | "c++-link-nodeps-dynamic-library", | 
|  | ] | 
|  |  | 
|  | # All possible C++ archive actions | 
|  | ARCHIVE_ACTIONS = [ | 
|  | "c++-link-static-library", | 
|  | ] | 
|  |  | 
|  | # All remaining actions used by C++ rules that are configured in the CROSSTOOL | 
|  | OTHER_ACTIONS = [ | 
|  | "strip", | 
|  | ] | 
|  |  | 
|  | def action_config(action_name, tool_path): | 
|  | """Emit action_config message. | 
|  |  | 
|  | Examples: | 
|  | action_config("c-compile", "/usr/bin/gcc") -> | 
|  | action_config { | 
|  | config_name: 'c-compile' | 
|  | action_name: 'c-compile' | 
|  | tool { | 
|  | tool_path: '/usr/bin/gcc' | 
|  | } | 
|  | } | 
|  |  | 
|  | Args: | 
|  | action_name: name of the action | 
|  | tool_path: absolute or CROSSTOOL-relative path to the tool | 
|  |  | 
|  | Returns: | 
|  | a string to be placed into the CROSSTOOL | 
|  | """ | 
|  | if action_name == None or action_name == "": | 
|  | fail("action_name must be present") | 
|  | if tool_path == None or tool_path == "": | 
|  | fail("tool_path must be present") | 
|  | return """ | 
|  | action_config {{ | 
|  | config_name: '{action_name}' | 
|  | action_name: '{action_name}' | 
|  | tool {{ | 
|  | tool_path: '{tool_path}' | 
|  | }} | 
|  | }}""".format(action_name = action_name, tool_path = tool_path) | 
|  |  | 
|  | def feature(name, flag_sets, enabled = True, provides = None): | 
|  | """Emit feature message. | 
|  |  | 
|  | Examples: | 
|  | feature("fully_static_link", flag_sets, enabled = False) -> | 
|  | feature { | 
|  | name: 'fully_static_link' | 
|  | enabled = false | 
|  | <flags_sets> | 
|  | } | 
|  |  | 
|  | Args: | 
|  | name: name of the feature | 
|  | flag_sets: a collection of flag_set messages | 
|  | enabled: whether this feature is turned on by default | 
|  | provides: a symbol this feature provides, used to implement mutually incompatible features | 
|  |  | 
|  | Returns: | 
|  | a string to be placed into the CROSSTOOL | 
|  | """ | 
|  | if name == None or name == "": | 
|  | fail("feature name must be present") | 
|  | return """ | 
|  | feature {{ | 
|  | name: '{name}' | 
|  | enabled: {enabled}{provides}{flag_sets} | 
|  | }}""".format( | 
|  | provides = ("\n      provides: '%s'" % provides if provides != None else ""), | 
|  | name = name, | 
|  | enabled = _to_proto_value(enabled), | 
|  | flag_sets = "".join(flag_sets), | 
|  | ) | 
|  |  | 
|  | def simple_feature( | 
|  | name, | 
|  | actions, | 
|  | flags, | 
|  | enabled = True, | 
|  | provides = None, | 
|  | expand_if_all_available = [], | 
|  | iterate_over = None): | 
|  | """Sugar for emitting simple feature message. | 
|  |  | 
|  | Examples: | 
|  | simple_feature("foo", ['c-compile'], flags("-foo")) -> | 
|  | feature { | 
|  | name: 'foo' | 
|  | flag_set { | 
|  | action: 'c-compile' | 
|  | flag_group { | 
|  | flag: '-foo' | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | Args: | 
|  | name: name of the feature | 
|  | actions: for which actions should flags be emitted | 
|  | flags: a collection of flag messages | 
|  | enabled: whether this feature is turned on by default | 
|  | provides: a symbol this feature provides, used to implement mutually incompatible features | 
|  | expand_if_all_available: specify which build variables need to be present | 
|  | for this group to be expanded | 
|  | iterate_over: expand this flag_group for every item in the build variable | 
|  |  | 
|  | Returns: | 
|  | a string to be placed into the CROSSTOOL | 
|  | """ | 
|  | if len(flags) == 0: | 
|  | return feature(name, []) | 
|  | else: | 
|  | return feature( | 
|  | name, | 
|  | [flag_set( | 
|  | actions, | 
|  | [flag_group( | 
|  | [flag(f) for f in flags], | 
|  | iterate_over = iterate_over, | 
|  | expand_if_all_available = expand_if_all_available, | 
|  | )], | 
|  | )], | 
|  | enabled = enabled, | 
|  | provides = provides, | 
|  | ) | 
|  |  | 
|  | def flag_set(actions, flag_groups): | 
|  | """Emit flag_set message. | 
|  |  | 
|  | Examples: | 
|  | flag_set(['c-compile'], flag_groups) -> | 
|  | flag_set { | 
|  | action: 'c-compile' | 
|  | <flag_groups> | 
|  | } | 
|  |  | 
|  | Args: | 
|  | actions: for which actions should flags be emitted | 
|  | flag_groups: a collection of flag_group messages | 
|  |  | 
|  | Returns: | 
|  | a string to be placed into the CROSSTOOL | 
|  | """ | 
|  | if actions == None or len(actions) == 0: | 
|  | fail("empty actions list is not allowed for flag_set") | 
|  | if flag_groups == None or len(flag_groups) == 0: | 
|  | fail("empty flag_groups list is not allowed for flag_set") | 
|  | actions_string = "" | 
|  | for action in actions: | 
|  | actions_string += "\n      action: '%s'" % action | 
|  |  | 
|  | return """ | 
|  | flag_set {{{actions}{flag_groups} | 
|  | }}""".format(actions = actions_string, flag_groups = "".join(flag_groups)) | 
|  |  | 
|  | def flag_group( | 
|  | content, | 
|  | expand_if_all_available = [], | 
|  | expand_if_none_available = [], | 
|  | expand_if_true = [], | 
|  | expand_if_false = [], | 
|  | expand_if_equal = [], | 
|  | iterate_over = None): | 
|  | """Emit flag_group message. | 
|  |  | 
|  | Examples: | 
|  | flag_group(flags("-foo %{output_file}"), expand_if_all_available="output_file") -> | 
|  | flag_group { expand_if_all_available: "output_file" | 
|  | flag: "-foo %{output_file}" | 
|  | } | 
|  |  | 
|  | Args: | 
|  | content: a collection of flag messages or a collection of flag_group messages | 
|  | expand_if_all_available: specify which build variables need to be present | 
|  | for this group to be expanded | 
|  | expand_if_none_available: specify which build variables need to be missing | 
|  | for this group to be expanded | 
|  | expand_if_true: specify which build variables need to be truthy for this group | 
|  | to be expanded | 
|  | expand_if_false: specify which build variables need to be falsey for this group | 
|  | to be expanded | 
|  | expand_if_equal: [[var1, value1], [var2, value2]...] specify what values | 
|  | should specific build variables have for this group to be expanded | 
|  | iterate_over: expand this flag_group for every item in the build variable | 
|  |  | 
|  | Returns: | 
|  | a string to be placed into the CROSSTOOL | 
|  | """ | 
|  | if content == None or len(content) == 0: | 
|  | fail("flag_group without flags is not allowed") | 
|  | conditions = "" | 
|  | for var in expand_if_all_available: | 
|  | conditions += "\n        expand_if_all_available: '%s'" % var | 
|  | for var in expand_if_none_available: | 
|  | conditions += "\n        expand_if_none_available: '%s'" % var | 
|  | for var in expand_if_true: | 
|  | conditions += "\n        expand_if_true: '%s'" % var | 
|  | for var in expand_if_false: | 
|  | conditions += "\n        expand_if_false: '%s'" % var | 
|  | for var in expand_if_equal: | 
|  | conditions += "\n        expand_if_equal { variable: '%s' value: '%s' }" % (var[0], var[1]) | 
|  | return """ | 
|  | flag_group {{{conditions}{iterate_over}{content} | 
|  | }}""".format( | 
|  | content = "".join(content), | 
|  | iterate_over = ("\n        iterate_over: '%s'" % iterate_over if iterate_over != None else ""), | 
|  | conditions = conditions, | 
|  | ) | 
|  |  | 
|  | def flag(flag): | 
|  | """Emit flag field. | 
|  |  | 
|  | Examples: | 
|  | flag("-foo") -> flag: '-foo' | 
|  |  | 
|  | Args: | 
|  | flag: value to be emitted to the command line | 
|  |  | 
|  | Returns: | 
|  | a string to be placed into the CROSSTOOL | 
|  | """ | 
|  | return "\n        flag: '%s'" % flag | 
|  |  | 
|  | def flags(*flags): | 
|  | """Sugar for emitting sequence of flag fields. | 
|  |  | 
|  | Examples: | 
|  | flags("-foo", "-bar") -> | 
|  | flag: '-foo' | 
|  | flag: '-bar' | 
|  |  | 
|  | Args: | 
|  | *flags: values to be emitted to the command line | 
|  |  | 
|  | Returns: | 
|  | a string to be placed into the CROSSTOOL | 
|  | """ | 
|  | return [flag(f) for f in flags] | 
|  |  | 
|  | def _to_proto_value(boolean): | 
|  | if boolean: | 
|  | return "true" | 
|  | else: | 
|  | return "false" |