aboutsummaryrefslogtreecommitdiff
path: root/cc/cc_toolchain_config_lib.bzl
diff options
context:
space:
mode:
Diffstat (limited to 'cc/cc_toolchain_config_lib.bzl')
-rw-r--r--cc/cc_toolchain_config_lib.bzl617
1 files changed, 617 insertions, 0 deletions
diff --git a/cc/cc_toolchain_config_lib.bzl b/cc/cc_toolchain_config_lib.bzl
new file mode 100644
index 0000000..3a259de
--- /dev/null
+++ b/cc/cc_toolchain_config_lib.bzl
@@ -0,0 +1,617 @@
+# 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.
+
+""" A library of functions creating structs for CcToolchainConfigInfo."""
+
+def _check_is_none(obj, parameter_name, method_name):
+ if obj != None:
+ fail("{} parameter of {} should be None, found {}."
+ .format(parameter_name, method_name, type(obj)))
+
+def _check_is_none_or_right_type(obj, obj_of_right_type, parameter_name, method_name):
+ if obj != None:
+ _check_same_type(obj, obj_of_right_type, parameter_name, method_name)
+
+def _check_right_type(obj, expected_type, parameter_name, method_name):
+ if type(obj) != expected_type:
+ fail("{} parameter of {} should be a {}, found {}."
+ .format(parameter_name, method_name, expected_type, type(obj)))
+
+def _check_same_type(obj, obj_of_right_type, parameter_name, method_name):
+ _check_right_type(obj, type(obj_of_right_type), parameter_name, method_name)
+
+def _check_is_nonempty_string(obj, parameter_name, method_name):
+ _check_same_type(obj, "", parameter_name, method_name)
+ if obj == "":
+ fail("{} parameter of {} must be a nonempty string."
+ .format(parameter_name, method_name))
+
+def _check_is_nonempty_list(obj, parameter_name, method_name):
+ _check_same_type(obj, [], parameter_name, method_name)
+ if len(obj) == 0:
+ fail("{} parameter of {} must be a nonempty list."
+ .format(parameter_name, method_name))
+
+EnvEntryInfo = provider(
+ "A key/value pair to be added as an environment variable.",
+ fields = ["key", "value", "expand_if_available", "type_name"],
+)
+
+def env_entry(key, value, expand_if_available = None):
+ """ A key/value pair to be added as an environment variable.
+
+ The returned EnvEntry provider finds its use in EnvSet creation through
+ the env_entries parameter of env_set(); EnvSet groups environment variables
+ that need to be expanded for specific actions.
+ The value of this pair is expanded in the same way as is described in
+ flag_group. The key remains an unexpanded string literal.
+
+ Args:
+ key: a string literal representing the name of the variable.
+ value: the value to be expanded.
+ expand_if_available: A build variable that needs to be available
+ in order to expand the env_entry.
+
+ Returns:
+ An EnvEntryInfo provider.
+ """
+ _check_is_nonempty_string(key, "key", "env_entry")
+ _check_is_nonempty_string(value, "value", "env_entry")
+ _check_is_none_or_right_type(expand_if_available, "string", "expand_if_available", "env_entry")
+ return EnvEntryInfo(
+ key = key,
+ value = value,
+ expand_if_available = expand_if_available,
+ type_name = "env_entry",
+ )
+
+VariableWithValueInfo = provider(
+ "Represents equality check between a variable and a certain value.",
+ fields = ["name", "value", "type_name"],
+)
+
+def variable_with_value(name, value):
+ """ Represents equality check between a variable and a certain value.
+
+ The returned provider finds its use through flag_group.expand_if_equal,
+ making the expansion of the flag_group conditional on the value of the
+ variable.
+
+ Args:
+ name: name of the variable.
+ value: the value the variable should be compared against.
+
+ Returns:
+ A VariableWithValueInfo provider.
+ """
+ _check_is_nonempty_string(name, "name", "variable_with_value")
+ _check_is_nonempty_string(value, "value", "variable_with_value")
+ return VariableWithValueInfo(
+ name = name,
+ value = value,
+ type_name = "variable_with_value",
+ )
+
+MakeVariableInfo = provider(
+ "A make variable that is made accessible to rules.",
+ fields = ["name", "value", "type_name"],
+)
+
+def make_variable(name, value):
+ """ A make variable that is made accessible to rules."""
+ _check_is_nonempty_string(name, "name", "make_variable")
+ _check_is_nonempty_string(value, "value", "make_variable")
+ return MakeVariableInfo(
+ name = name,
+ value = value,
+ type_name = "make_variable",
+ )
+
+FeatureSetInfo = provider(
+ "A set of features.",
+ fields = ["features", "type_name"],
+)
+
+def feature_set(features = []):
+ """ A set of features.
+
+ Used to support logical 'and' when specifying feature requirements in a
+ feature.
+
+ Args:
+ features: A list of unordered feature names.
+
+ Returns:
+ A FeatureSetInfo provider.
+ """
+ _check_same_type(features, [], "features", "feature_set")
+ return FeatureSetInfo(features = features, type_name = "feature_set")
+
+WithFeatureSetInfo = provider(
+ "A set of positive and negative features.",
+ fields = ["features", "not_features", "type_name"],
+)
+
+def with_feature_set(features = [], not_features = []):
+ """ A set of positive and negative features.
+
+ This stanza will evaluate to true when every 'feature' is enabled, and
+ every 'not_feature' is not enabled.
+
+ Args:
+ features: A list of feature names that need to be enabled.
+ not_features: A list of feature names that need to not be enabled.
+
+ Returns:
+ A WithFeatureSetInfo provider.
+ """
+ _check_same_type(features, [], "features", "with_feature_set")
+ _check_same_type(not_features, [], "not_features", "with_feature_set")
+ return WithFeatureSetInfo(
+ features = features,
+ not_features = not_features,
+ type_name = "with_feature_set",
+ )
+
+EnvSetInfo = provider(
+ "Groups a set of environment variables to apply for certain actions.",
+ fields = ["actions", "env_entries", "with_features", "type_name"],
+)
+
+def env_set(actions, env_entries = [], with_features = []):
+ """ Groups a set of environment variables to apply for certain actions.
+
+ EnvSet providers are passed to feature() and action_config(), to be applied to
+ the actions they are specified for.
+
+ Args:
+ actions: A list of actions this env set applies to; each env set must
+ specify at least one action.
+ env_entries: A list of EnvEntry - the environment variables applied
+ via this env set.
+ with_features: A list of feature sets defining when this env set gets
+ applied. The env set will be applied when any one of the feature
+ sets evaluate to true. (That is, when when every 'feature' is
+ enabled, and every 'not_feature' is not enabled.)
+ If 'with_features' is omitted, the env set will be applied
+ unconditionally for every action specified.
+
+ Returns:
+ An EnvSetInfo provider.
+ """
+ _check_is_nonempty_list(actions, "actions", "env_set")
+ _check_same_type(env_entries, [], "env_entries", "env_set")
+ _check_same_type(with_features, [], "with_features", "env_set")
+ return EnvSetInfo(
+ actions = actions,
+ env_entries = env_entries,
+ with_features = with_features,
+ type_name = "env_set",
+ )
+
+FlagGroupInfo = provider(
+ "A group of flags. Supports parametrization via variable expansion.",
+ fields = [
+ "flags",
+ "flag_groups",
+ "iterate_over",
+ "expand_if_available",
+ "expand_if_not_available",
+ "expand_if_true",
+ "expand_if_false",
+ "expand_if_equal",
+ "type_name",
+ ],
+)
+
+def flag_group(
+ flags = [],
+ flag_groups = [],
+ iterate_over = None,
+ expand_if_available = None,
+ expand_if_not_available = None,
+ expand_if_true = None,
+ expand_if_false = None,
+ expand_if_equal = None):
+ """ A group of flags. Supports parametrization via variable expansion.
+
+ To expand a variable of list type, flag_group has to be annotated with
+ `iterate_over` message. Then all nested flags or flag_groups will be
+ expanded repeatedly for each element of the list.
+ For example:
+ flag_group(
+ iterate_over = 'include_path',
+ flags = ['-I', '%{include_path}'],
+ )
+ ... will get expanded to -I /to/path1 -I /to/path2 ... for each
+ include_path /to/pathN.
+
+ To expand a variable of structure type, use dot-notation, e.g.:
+ flag_group(
+ iterate_over = "libraries_to_link",
+ flag_groups = [
+ flag_group(
+ iterate_over = "libraries_to_link.libraries",
+ flags = ["-L%{libraries_to_link.libraries.directory}"],
+ )
+ ]
+ )
+
+ Flag groups can be nested; if they are, the flag group must only contain
+ other flag groups (no flags) so the order is unambiguously specified.
+ In order to expand a variable of nested lists, 'iterate_over' can be used.
+ For example:
+ flag_group (
+ iterate_over = 'object_files',
+ flag_groups = [
+ flag_group (
+ flags = ['--start-lib'],
+ ),
+ flag_group (
+ iterate_over = 'object_files',
+ flags = ['%{object_files}'],
+ ),
+ flag_group (
+ flags = ['--end-lib'],
+ )
+ ]
+ )
+ ... will get expanded to
+ --start-lib a1.o a2.o ... --end-lib --start-lib b1.o b2.o .. --end-lib
+ with %{object_files} being a variable of nested list type
+ [['a1.o', 'a2.o', ...], ['b1.o', 'b2.o', ...], ...].
+
+ Args:
+ flags: a string list, representing flags. Only one of flags and
+ flag_groups can be set, as to avoid ambiguity.
+ flag_groups: a list of FlagGroup entries. Only one of flags and
+ flag_groups can be set, as to avoid ambiguity.
+ iterate_over: a string, representing a variable of list type.
+ expand_if_available: A build variable that needs to be available
+ in order to expand the flag_group.
+ expand_if_not_available: A build variable that needs to be
+ unavailable in order for this flag_group to be expanded.
+ expand_if_true: if set, this variable needs to evaluate to True in
+ order for the flag_group to be expanded.
+ expand_if_false: if set, this variable needs to evalate to False in
+ order for the flag_group to be expanded.
+ expand_if_equal: a VariableWithValue, the flag_group is expanded in
+ case of equality.
+
+ Returns:
+ A FlagGroupInfo provider.
+ """
+
+ _check_same_type(flags, [], "flags", "flag_group")
+ _check_same_type(flag_groups, [], "flag_groups", "flag_group")
+ if len(flags) > 0 and len(flag_groups) > 0:
+ fail("flag_group must not contain both a flag and another flag_group.")
+ if len(flags) == 0 and len(flag_groups) == 0:
+ fail("flag_group must contain either a list of flags or a list of flag_groups.")
+ _check_is_none_or_right_type(expand_if_true, "string", "expand_if_true", "flag_group")
+ _check_is_none_or_right_type(expand_if_false, "string", "expand_if_false", "flag_group")
+ _check_is_none_or_right_type(expand_if_available, "string", "expand_if_available", "flag_group")
+ _check_is_none_or_right_type(
+ expand_if_not_available,
+ "string",
+ "expand_if_not_available",
+ "flag_group",
+ )
+ _check_is_none_or_right_type(iterate_over, "string", "iterate_over", "flag_group")
+
+ return FlagGroupInfo(
+ flags = flags,
+ flag_groups = flag_groups,
+ iterate_over = iterate_over,
+ expand_if_available = expand_if_available,
+ expand_if_not_available = expand_if_not_available,
+ expand_if_true = expand_if_true,
+ expand_if_false = expand_if_false,
+ expand_if_equal = expand_if_equal,
+ type_name = "flag_group",
+ )
+
+FlagSetInfo = provider(
+ "A set of flags to be expanded in the command line for specific actions.",
+ fields = [
+ "actions",
+ "with_features",
+ "flag_groups",
+ "type_name",
+ ],
+)
+
+def flag_set(
+ actions = [],
+ with_features = [],
+ flag_groups = []):
+ """ A set of flags to be expanded in the command line for specific actions.
+
+ Args:
+ actions: The actions this flag set applies to; each flag set must
+ specify at least one action.
+ with_features: A list of feature sets defining when this flag set gets
+ applied. The flag set will be applied when any one of the feature
+ sets evaluate to true. (That is, when when every 'feature' is
+ enabled, and every 'not_feature' is not enabled.)
+ If 'with_feature' is omitted, the flag set will be applied
+ unconditionally for every action specified.
+ flag_groups: A FlagGroup list - the flags applied via this flag set.
+
+ Returns:
+ A FlagSetInfo provider.
+ """
+ _check_same_type(actions, [], "actions", "flag_set")
+ _check_same_type(with_features, [], "with_features", "flag_set")
+ _check_same_type(flag_groups, [], "flag_groups", "flag_set")
+ return FlagSetInfo(
+ actions = actions,
+ with_features = with_features,
+ flag_groups = flag_groups,
+ type_name = "flag_set",
+ )
+
+FeatureInfo = provider(
+ "Contains all flag specifications for one feature.",
+ fields = [
+ "name",
+ "enabled",
+ "flag_sets",
+ "env_sets",
+ "requires",
+ "implies",
+ "provides",
+ "type_name",
+ ],
+)
+
+def feature(
+ name,
+ enabled = False,
+ flag_sets = [],
+ env_sets = [],
+ requires = [],
+ implies = [],
+ provides = []):
+ """ Contains all flag specifications for one feature.
+
+ Args:
+ name: The feature's name. It is possible to introduce a feature without
+ a change to Bazel by adding a 'feature' section to the toolchain
+ and adding the corresponding string as feature in the BUILD file.
+ enabled: If 'True', this feature is enabled unless a rule type
+ explicitly marks it as unsupported.
+ flag_sets: A FlagSet list - If the given feature is enabled, the flag
+ sets will be applied for the actions are specified for.
+ env_sets: an EnvSet list - If the given feature is enabled, the env
+ sets will be applied for the actions they are specified for.
+ requires: A list of feature sets defining when this feature is
+ supported by the toolchain. The feature is supported if any of the
+ feature sets fully apply, that is, when all features of a feature
+ set are enabled.
+ If 'requires' is omitted, the feature is supported independently of
+ which other features are enabled.
+ Use this for example to filter flags depending on the build mode
+ enabled (opt / fastbuild / dbg).
+ implies: A string list of features or action configs that are
+ automatically enabled when this feature is enabled. If any of the
+ implied features or action configs cannot be enabled, this feature
+ will (silently) not be enabled either.
+ provides: A list of names this feature conflicts with.
+ A feature cannot be enabled if:
+ - 'provides' contains the name of a different feature or action
+ config that we want to enable.
+ - 'provides' contains the same value as a 'provides' in a
+ different feature or action config that we want to enable.
+ Use this in order to ensure that incompatible features cannot be
+ accidentally activated at the same time, leading to hard to
+ diagnose compiler errors.
+
+ Returns:
+ A FeatureInfo provider.
+ """
+ _check_same_type(enabled, True, "enabled", "feature")
+ _check_same_type(flag_sets, [], "flag_sets", "feature")
+ _check_same_type(env_sets, [], "env_sets", "feature")
+ _check_same_type(requires, [], "requires", "feature")
+ _check_same_type(provides, [], "provides", "feature")
+ _check_same_type(implies, [], "implies", "feature")
+ return FeatureInfo(
+ name = name,
+ enabled = enabled,
+ flag_sets = flag_sets,
+ env_sets = env_sets,
+ requires = requires,
+ implies = implies,
+ provides = provides,
+ type_name = "feature",
+ )
+
+ToolPathInfo = provider(
+ "Tool locations.",
+ fields = ["name", "path", "type_name"],
+)
+
+def tool_path(name, path):
+ """ Tool locations.
+
+ Args:
+ name: Name of the tool.
+ path: Location of the tool; Can be absolute path (in case of non hermetic
+ toolchain), or path relative to the cc_toolchain's package.
+
+ Returns:
+ A ToolPathInfo provider.
+
+ Deprecated:
+ Prefer specifying an ActionConfig for the action that needs the tool.
+ TODO(b/27903698) migrate to ActionConfig.
+ """
+ _check_is_nonempty_string(name, "name", "tool_path")
+ _check_is_nonempty_string(path, "path", "tool_path")
+ return ToolPathInfo(name = name, path = path, type_name = "tool_path")
+
+ToolInfo = provider(
+ doc = "Tool information. This differs from ToolPathInfo as it is intended to be used\
+ in action_configs and can accept labels.",
+ fields = [
+ "path",
+ "tool",
+ "with_features",
+ "execution_requirements",
+ "type_name",
+ ],
+)
+
+def tool(path = None, with_features = [], execution_requirements = [], tool = None):
+ """ Describes a tool associated with a crosstool action config.
+
+ Args:
+ path: Location of the tool; Can be absolute path (in case of non hermetic
+ toolchain), or path relative to the cc_toolchain's package. If this
+ parameter is set, tool must not be set.
+ tool: The built-artifact that should be used as this tool. If this is
+ set, path must not be set.
+ with_features: A list of feature sets defining when this tool is
+ applicable. The tool will used when any one of the feature sets
+ evaluate to true. (That is, when when every 'feature' is enabled,
+ and every 'not_feature' is not enabled.)
+ If 'with_feature' is omitted, the tool will apply for any feature
+ configuration.
+ execution_requirements: Requirements on the execution environment for
+ the execution of this tool, to be passed as out-of-band "hints" to
+ the execution backend.
+ Ex. "requires-darwin"
+
+ Returns:
+ A ToolInfo provider.
+ """
+ if path == None and tool == None:
+ fail("Parameter path or parameter tool of tool should not be None.")
+
+ if path != None:
+ _check_is_nonempty_string(path, "path", "tool")
+ _check_is_none(tool, "tool", "tool")
+ if tool != None:
+ _check_is_none(path, "path", "tool")
+ _check_right_type(tool, "File", "tool", "tool")
+
+ _check_same_type(with_features, [], "with_features", "tool")
+ _check_same_type(execution_requirements, [], "execution_requirements", "tool")
+ return ToolInfo(
+ path = path,
+ tool = tool,
+ with_features = with_features,
+ execution_requirements = execution_requirements,
+ type_name = "tool",
+ )
+
+ActionConfigInfo = provider(
+ "Configuration of a Bazel action.",
+ fields = [
+ "config_name",
+ "action_name",
+ "enabled",
+ "tools",
+ "flag_sets",
+ "implies",
+ "type_name",
+ ],
+)
+
+def action_config(
+ action_name,
+ enabled = False,
+ tools = [],
+ flag_sets = [],
+ implies = []):
+ """ Configuration of a Bazel action.
+
+ An action config corresponds to a Bazel action, and allows selection of
+ a tool based on activated features.
+ Action config activation occurs by the same semantics as features: a
+ feature can 'require' or 'imply' an action config in the same way that it
+ would another feature.
+
+ Args:
+ action_name: The name of the Bazel action that this config applies to,
+ ex. 'c-compile' or 'c-module-compile'.
+ enabled: If 'True', this action is enabled unless a rule type
+ explicitly marks it as unsupported.
+ tools: The tool applied to the action will be the first Tool with a
+ feature set that matches the feature configuration. An error will
+ be thrown if no tool matches a provided feature configuration - for
+ that reason, it's a good idea to provide a default tool with an
+ empty feature set.
+ flag_sets: If the given action config is enabled, the flag sets will be
+ applied to the corresponding action.
+ implies: A list of features or action configs that are automatically
+ enabled when this action config is enabled. If any of the implied
+ features or action configs cannot be enabled, this action config
+ will (silently) not be enabled either.
+
+ Returns:
+ An ActionConfigInfo provider.
+ """
+ _check_is_nonempty_string(action_name, "name", "action_config")
+ _check_same_type(enabled, True, "enabled", "action_config")
+ _check_same_type(tools, [], "tools", "action_config")
+ _check_same_type(flag_sets, [], "flag_sets", "action_config")
+ _check_same_type(implies, [], "implies", "action_config")
+ return ActionConfigInfo(
+ action_name = action_name,
+ enabled = enabled,
+ tools = tools,
+ flag_sets = flag_sets,
+ implies = implies,
+ type_name = "action_config",
+ )
+
+ArtifactNamePatternInfo = provider(
+ "The name for an artifact of a given category of input or output artifacts to an action.",
+ fields = [
+ "category_name",
+ "prefix",
+ "extension",
+ "type_name",
+ ],
+)
+
+def artifact_name_pattern(category_name, prefix, extension):
+ """ The name for an artifact of a given category of input or output artifacts to an action.
+
+ Args:
+ category_name: The category of artifacts that this selection applies
+ to. This field is compared against a list of categories defined
+ in bazel. Example categories include "linked_output" or
+ "debug_symbols". An error is thrown if no category is matched.
+ prefix: The prefix for creating the artifact for this selection.
+ Together with the extension it is used to create an artifact name
+ based on the target name.
+ extension: The extension for creating the artifact for this selection.
+ Together with the prefix it is used to create an artifact name
+ based on the target name.
+
+ Returns:
+ An ArtifactNamePatternInfo provider
+ """
+ _check_is_nonempty_string(category_name, "category_name", "artifact_name_pattern")
+ _check_is_none_or_right_type(prefix, "", "prefix", "artifact_name_pattern")
+ _check_is_none_or_right_type(extension, "", "extension", "artifact_name_pattern")
+ return ArtifactNamePatternInfo(
+ category_name = category_name,
+ prefix = prefix,
+ extension = extension,
+ type_name = "artifact_name_pattern",
+ )