| // Copyright 2019 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. |
| // |
| |
| package com.google.devtools.build.lib.syntax; |
| |
| import com.google.auto.value.AutoValue; |
| import com.google.auto.value.extension.memoized.Memoized; |
| import com.google.common.base.Preconditions; |
| import com.google.common.collect.ImmutableList; |
| import java.util.List; |
| |
| /** |
| * Options that affect the dynamic behavior of Starlark execution and operators. |
| * |
| * <p>For descriptions of what these options do, see {@link packages.StarlarkSemanticsOptions}. |
| * |
| * <p>For options that affect the static behavior of the Starlark frontend (lexer, parser, |
| * validator, compiler), see FileOptions. |
| */ |
| // TODO(brandjon): User error messages that reference options should maybe be substituted with the |
| // option name outside of the core Starlark interpreter? |
| // TODO(brandjon): Eventually these should be documented in full here, and StarlarkSemanticsOptions |
| // should refer to this class for documentation. But this doesn't play nice with the options |
| // parser's annotation mechanism. |
| // |
| // TODO(adonovan): nearly all of these options are Bazel-isms. |
| // The only ones that affect the Starlark interpreter directly are are: |
| // - incompatibleRestrictNamedParams, which affects calls to many built-ins, |
| // but is used only by copybara and will be deleted soon (CL 298871155); |
| // - incompatibleRestrictStringEscapes, which affects the lexer and is thus |
| // properly one of the FileOptions, but piggybacks on the command-line flag |
| // plumbing of StarlarkSemantics; and |
| // - internalStarlarkFlagTestCanary, which is used to test propagation of Bazel |
| // command-line flags to the 'print' built-in, but this could easily be |
| // achieved using some other Bazel-specific built-in. |
| // Most of the rest are used generically to disable parameters to built-ins, |
| // or to disable fields of modules, based on flags. In both of those cases, |
| // a generic set-of-feature-strings representation would do. |
| // A few could be expressed as Bazel-specific thread state, |
| // though several are inspected by the implementations of operations |
| // such as StarlarkIndexable, StarlarkQueryable, and StarlarkClassObject. |
| // TODO(adonovan): move to lib.packages.BuildLanguageSemantics. |
| // |
| @AutoValue |
| public abstract class StarlarkSemantics { |
| |
| /** |
| * A set of names of boolean application flags each corresponding to a StarlarkSemantics feature. |
| */ |
| // TODO(adonovan): StarlarkSemantics, being part of the core frontend, shouldn't refer to Bazel |
| // features. There's no need for an enumeration to represent a set of boolean features. Instead, |
| // have StarlarkSemantics hold a set of enabled features (strings), and have callers query |
| // features by name. The features can be named string constants, defined close to the code they |
| // affect, to avoid accidential misspellings. |
| public static final class FlagIdentifier { |
| private FlagIdentifier() {} // uninstantiable |
| |
| // The strings here match the names of the StarlarkSemantics methods, |
| // which in turn match the actual flag names; they should be kept |
| // consistent as they may appear in error messages. |
| // TODO(adonovan): move these constants up into the relevant packages of |
| // Bazel, and make them identical to the strings used in flag declarations. |
| public static final String EXPERIMENTAL_ACTION_ARGS = "experimental_action_args"; |
| public static final String EXPERIMENTAL_ALLOW_INCREMENTAL_REPOSITORY_UPDATES = |
| "experimental_allow_incremental_repository_updates"; |
| public static final String EXPERIMENTAL_DISABLE_EXTERNAL_PACKGE = |
| "experimental_disable_external_package"; |
| public static final String EXPERIMENTAL_SIBLING_REPOSITORY_LAYOUT = |
| "experimental_sibling_repository_layout"; |
| public static final String EXPERIMENTAL_ENABLE_ANDROID_MIGRATION_APIS = |
| "experimental_enable_android_migration_apis"; |
| public static final String EXPERIMENTAL_GOOGLE_LEGACY_API = "experimental_google_legacy_api"; |
| public static final String EXPERIMENTAL_NINJA_ACTIONS = "experimental_ninja_actions"; |
| public static final String EXPERIMENTAL_PLATFORM_API = "experimental_platform_api"; |
| public static final String EXPERIMENTAL_STARLARK_CONFIG_TRANSITION = |
| "experimental_starlark_config_transition"; |
| public static final String EXPERIMENTAL_STARLARK_UNUSED_INPUTS_LIST = |
| "experimental_starlark_unused_inputs_list"; |
| public static final String EXPERIMENTAL_REPO_REMOTE_EXEC = "experimental_repo_remote_exec"; |
| public static final String EXPERIMENTAL_EXEC_GROUPS = "experimental_exec_groups"; |
| public static final String INCOMPATIBLE_APPLICABLE_LICENSES = |
| "incompatible_applicable_licenses"; |
| public static final String INCOMPATIBLE_DISABLE_DEPSET_INPUTS = |
| "incompatible_disable_depset_inputs"; |
| public static final String INCOMPATIBLE_NO_RULE_OUTPUTS_PARAM = |
| "incompatible_no_rule_outputs_param"; |
| public static final String INCOMPATIBLE_NO_ATTR_LICENSE = "incompatible_no_attr_license"; |
| public static final String INCOMPATIBLE_ALLOW_TAGS_PROPAGATION = |
| "incompatible_allow_tags_propagation"; |
| public static final String INCOMPATIBLE_REQUIRE_LINKER_INPUT_CC_API = |
| "incompatible_require_linker_input_cc_api"; |
| public static final String INCOMPATIBLE_LINKOPTS_TO_LINKLIBS = |
| "incompatible_linkopts_to_linklibs"; |
| public static final String RECORD_RULE_INSTANTIATION_CALLSTACK = |
| "record_rule_instantiation_callstack"; |
| } |
| |
| // TODO(adonovan): replace the fields of StarlarkSemantics |
| // by a map from string to object, and make it the clients's job |
| // to know the type. This function would then become simply: |
| // return Boolean.TRUE.equals(map.get(flag)). |
| public boolean flagValue(String flag) { |
| switch (flag) { |
| case FlagIdentifier.EXPERIMENTAL_ACTION_ARGS: |
| return experimentalActionArgs(); |
| case FlagIdentifier.EXPERIMENTAL_ALLOW_INCREMENTAL_REPOSITORY_UPDATES: |
| return experimentalAllowIncrementalRepositoryUpdates(); |
| case FlagIdentifier.EXPERIMENTAL_DISABLE_EXTERNAL_PACKGE: |
| return experimentalDisableExternalPackage(); |
| case FlagIdentifier.EXPERIMENTAL_SIBLING_REPOSITORY_LAYOUT: |
| return experimentalSiblingRepositoryLayout(); |
| case FlagIdentifier.EXPERIMENTAL_ENABLE_ANDROID_MIGRATION_APIS: |
| return experimentalEnableAndroidMigrationApis(); |
| case FlagIdentifier.EXPERIMENTAL_GOOGLE_LEGACY_API: |
| return experimentalGoogleLegacyApi(); |
| case FlagIdentifier.EXPERIMENTAL_NINJA_ACTIONS: |
| return experimentalNinjaActions(); |
| case FlagIdentifier.EXPERIMENTAL_PLATFORM_API: |
| return experimentalPlatformsApi(); |
| case FlagIdentifier.EXPERIMENTAL_STARLARK_CONFIG_TRANSITION: |
| return experimentalStarlarkConfigTransitions(); |
| case FlagIdentifier.EXPERIMENTAL_STARLARK_UNUSED_INPUTS_LIST: |
| return experimentalStarlarkUnusedInputsList(); |
| case FlagIdentifier.EXPERIMENTAL_REPO_REMOTE_EXEC: |
| return experimentalRepoRemoteExec(); |
| case FlagIdentifier.EXPERIMENTAL_EXEC_GROUPS: |
| return experimentalExecGroups(); |
| case FlagIdentifier.INCOMPATIBLE_APPLICABLE_LICENSES: |
| return incompatibleApplicableLicenses(); |
| case FlagIdentifier.INCOMPATIBLE_DISABLE_DEPSET_INPUTS: |
| return incompatibleDisableDepsetItems(); |
| case FlagIdentifier.INCOMPATIBLE_NO_RULE_OUTPUTS_PARAM: |
| return incompatibleNoRuleOutputsParam(); |
| case FlagIdentifier.INCOMPATIBLE_NO_ATTR_LICENSE: |
| return incompatibleNoAttrLicense(); |
| case FlagIdentifier.INCOMPATIBLE_ALLOW_TAGS_PROPAGATION: |
| return experimentalAllowTagsPropagation(); |
| case FlagIdentifier.INCOMPATIBLE_REQUIRE_LINKER_INPUT_CC_API: |
| return incompatibleRequireLinkerInputCcApi(); |
| case FlagIdentifier.INCOMPATIBLE_LINKOPTS_TO_LINKLIBS: |
| return incompatibleLinkoptsToLinkLibs(); |
| case FlagIdentifier.RECORD_RULE_INSTANTIATION_CALLSTACK: |
| return recordRuleInstantiationCallstack(); |
| default: |
| throw new IllegalArgumentException(flag); |
| } |
| } |
| |
| /** |
| * Returns true if a feature attached to the given toggling flags should be enabled. |
| * |
| * <ul> |
| * <li>If both parameters are empty, this indicates the feature is not controlled by flags, and |
| * should thus be enabled. |
| * <li>If the {@code enablingFlag} parameter is non-empty, this returns true if and only if that |
| * flag is true. (This represents a feature that is only on if a given flag is *on*). |
| * <li>If the {@code disablingFlag} parameter is non-empty, this returns true if and only if |
| * that flag is false. (This represents a feature that is only on if a given flag is *off*). |
| * <li>It is illegal to pass both parameters as non-empty. |
| * </ul> |
| */ |
| boolean isFeatureEnabledBasedOnTogglingFlags(String enablingFlag, String disablingFlag) { |
| Preconditions.checkArgument( |
| enablingFlag.isEmpty() || disablingFlag.isEmpty(), |
| "at least one of 'enablingFlag' or 'disablingFlag' must be empty"); |
| if (!enablingFlag.isEmpty()) { |
| return this.flagValue(enablingFlag); |
| } else if (!disablingFlag.isEmpty()) { |
| return !this.flagValue(disablingFlag); |
| } else { |
| return true; |
| } |
| } |
| |
| /** |
| * The AutoValue-generated concrete class implementing this one. |
| * |
| * <p>AutoValue implementation classes are usually package-private. We expose it here for the |
| * benefit of code that relies on reflection. |
| */ |
| public static final Class<? extends StarlarkSemantics> IMPL_CLASS = |
| AutoValue_StarlarkSemantics.class; |
| |
| // <== Add new options here in alphabetic order ==> |
| public abstract boolean experimentalActionArgs(); |
| |
| public abstract boolean experimentalAllowIncrementalRepositoryUpdates(); |
| |
| public abstract String experimentalBuiltinsBzlPath(); |
| |
| public abstract ImmutableList<String> experimentalCcStarlarkApiEnabledPackages(); |
| |
| public abstract boolean experimentalEnableAndroidMigrationApis(); |
| |
| public abstract boolean experimentalGoogleLegacyApi(); |
| |
| public abstract boolean experimentalNinjaActions(); |
| |
| public abstract boolean experimentalPlatformsApi(); |
| |
| public abstract boolean experimentalStarlarkConfigTransitions(); |
| |
| public abstract boolean experimentalStarlarkUnusedInputsList(); |
| |
| public abstract boolean experimentalCcSharedLibrary(); |
| |
| public abstract boolean experimentalRepoRemoteExec(); |
| |
| public abstract boolean experimentalDisableExternalPackage(); |
| |
| public abstract boolean experimentalSiblingRepositoryLayout(); |
| |
| public abstract boolean experimentalExecGroups(); |
| |
| public abstract boolean incompatibleAlwaysCheckDepsetElements(); |
| |
| public abstract boolean incompatibleApplicableLicenses(); |
| |
| public abstract boolean incompatibleDisableTargetProviderFields(); |
| |
| public abstract boolean incompatibleDisableThirdPartyLicenseChecking(); |
| |
| public abstract boolean incompatibleDisableDeprecatedAttrParams(); |
| |
| public abstract boolean incompatibleDisableDepsetItems(); |
| |
| public abstract boolean incompatibleDisallowEmptyGlob(); |
| |
| public abstract boolean incompatibleDisallowStructProviderSyntax(); |
| |
| public abstract boolean incompatibleNewActionsApi(); |
| |
| public abstract boolean incompatibleNoAttrLicense(); |
| |
| public abstract boolean incompatibleNoImplicitFileExport(); |
| |
| public abstract boolean incompatibleNoRuleOutputsParam(); |
| |
| public abstract boolean incompatibleNoSupportToolsInActionInputs(); |
| |
| public abstract boolean incompatibleRunShellCommandString(); |
| |
| public abstract boolean incompatibleStringReplaceCount(); |
| |
| public abstract boolean incompatibleVisibilityPrivateAttributesAtDefinition(); |
| |
| public abstract boolean internalStarlarkFlagTestCanary(); |
| |
| public abstract boolean incompatibleDoNotSplitLinkingCmdline(); |
| |
| public abstract boolean incompatibleDepsetForLibrariesToLinkGetter(); |
| |
| public abstract boolean incompatibleRequireLinkerInputCcApi(); |
| |
| public abstract boolean incompatibleRestrictStringEscapes(); |
| |
| public abstract boolean experimentalAllowTagsPropagation(); |
| |
| public abstract boolean incompatibleUseCcConfigureFromRulesCc(); |
| |
| public abstract boolean incompatibleLinkoptsToLinkLibs(); |
| |
| public abstract long maxComputationSteps(); |
| |
| public abstract boolean recordRuleInstantiationCallstack(); |
| |
| @Memoized |
| @Override |
| public abstract int hashCode(); |
| |
| /** Returns a {@link Builder} initialized with the values of this instance. */ |
| public abstract Builder toBuilder(); |
| |
| /** |
| * Returns a deterministic {@link String} representation of this object's values. |
| * |
| * <p>Strictly speaking, {@link AutoValue}'s generated toString implementations are unspecified. |
| * Therefore it is free to e.g. randomly shuffle the order of "property=value" entries on each |
| * call. In practice, it doesn't. The entries are printed in method declaration order. |
| * |
| * <p>We could attempt our own implementation via reflection but it's likely to be more fragile |
| * than relying on the unspecified behavior to be, at least, non-pathological. YAGNI. |
| */ |
| public String toDeterministicString() { |
| return toString(); |
| } |
| |
| public static Builder builder() { |
| return new AutoValue_StarlarkSemantics.Builder(); |
| } |
| |
| /** Returns a {@link Builder} initialized with default values for all options. */ |
| public static Builder builderWithDefaults() { |
| return DEFAULT.toBuilder(); |
| } |
| |
| public static final StarlarkSemantics DEFAULT = |
| builder() |
| // <== Add new options here in alphabetic order ==> |
| .experimentalActionArgs(true) |
| .experimentalAllowTagsPropagation(false) |
| .experimentalBuiltinsBzlPath("") |
| .experimentalCcStarlarkApiEnabledPackages(ImmutableList.of()) |
| .experimentalAllowIncrementalRepositoryUpdates(true) |
| .experimentalEnableAndroidMigrationApis(false) |
| .experimentalGoogleLegacyApi(false) |
| .experimentalNinjaActions(false) |
| .experimentalPlatformsApi(false) |
| .experimentalStarlarkConfigTransitions(true) |
| .experimentalStarlarkUnusedInputsList(true) |
| .experimentalCcSharedLibrary(false) |
| .experimentalRepoRemoteExec(false) |
| .experimentalDisableExternalPackage(false) |
| .experimentalSiblingRepositoryLayout(false) |
| .experimentalExecGroups(false) |
| .incompatibleAlwaysCheckDepsetElements(true) |
| .incompatibleApplicableLicenses(false) |
| .incompatibleDisableTargetProviderFields(false) |
| .incompatibleDisableThirdPartyLicenseChecking(true) |
| .incompatibleDisableDeprecatedAttrParams(true) |
| .incompatibleDisableDepsetItems(false) |
| .incompatibleDisallowEmptyGlob(false) |
| .incompatibleDisallowStructProviderSyntax(false) |
| .incompatibleNewActionsApi(true) |
| .incompatibleNoAttrLicense(true) |
| .incompatibleNoImplicitFileExport(false) |
| .incompatibleNoRuleOutputsParam(false) |
| .incompatibleNoSupportToolsInActionInputs(true) |
| .incompatibleRunShellCommandString(false) |
| .incompatibleStringReplaceCount(false) |
| .incompatibleVisibilityPrivateAttributesAtDefinition(false) |
| .internalStarlarkFlagTestCanary(false) |
| .incompatibleDoNotSplitLinkingCmdline(true) |
| .incompatibleDepsetForLibrariesToLinkGetter(true) |
| .incompatibleRequireLinkerInputCcApi(false) |
| .incompatibleRestrictStringEscapes(false) |
| .incompatibleUseCcConfigureFromRulesCc(false) |
| .incompatibleLinkoptsToLinkLibs(false) |
| .maxComputationSteps(0) |
| .recordRuleInstantiationCallstack(false) |
| .build(); |
| |
| /** Builder for {@link StarlarkSemantics}. All fields are mandatory. */ |
| @AutoValue.Builder |
| public abstract static class Builder { |
| |
| // <== Add new options here in alphabetic order ==> |
| public abstract Builder experimentalActionArgs(boolean value); |
| |
| public abstract Builder experimentalAllowIncrementalRepositoryUpdates(boolean value); |
| |
| public abstract Builder experimentalAllowTagsPropagation(boolean value); |
| |
| public abstract Builder experimentalBuiltinsBzlPath(String value); |
| |
| public abstract Builder experimentalCcStarlarkApiEnabledPackages(List<String> value); |
| |
| public abstract Builder experimentalEnableAndroidMigrationApis(boolean value); |
| |
| public abstract Builder experimentalGoogleLegacyApi(boolean value); |
| |
| public abstract Builder experimentalNinjaActions(boolean value); |
| |
| public abstract Builder experimentalPlatformsApi(boolean value); |
| |
| public abstract Builder experimentalStarlarkConfigTransitions(boolean value); |
| |
| public abstract Builder experimentalStarlarkUnusedInputsList(boolean value); |
| |
| public abstract Builder experimentalCcSharedLibrary(boolean value); |
| |
| public abstract Builder experimentalRepoRemoteExec(boolean value); |
| |
| public abstract Builder experimentalDisableExternalPackage(boolean value); |
| |
| public abstract Builder experimentalSiblingRepositoryLayout(boolean value); |
| |
| public abstract Builder experimentalExecGroups(boolean value); |
| |
| public abstract Builder incompatibleAlwaysCheckDepsetElements(boolean value); |
| |
| public abstract Builder incompatibleApplicableLicenses(boolean value); |
| |
| public abstract Builder incompatibleDisableTargetProviderFields(boolean value); |
| |
| public abstract Builder incompatibleDisableThirdPartyLicenseChecking(boolean value); |
| |
| public abstract Builder incompatibleDisableDeprecatedAttrParams(boolean value); |
| |
| public abstract Builder incompatibleDisableDepsetItems(boolean value); |
| |
| public abstract Builder incompatibleDisallowEmptyGlob(boolean value); |
| |
| public abstract Builder incompatibleDisallowStructProviderSyntax(boolean value); |
| |
| public abstract Builder incompatibleNewActionsApi(boolean value); |
| |
| public abstract Builder incompatibleNoAttrLicense(boolean value); |
| |
| public abstract Builder incompatibleNoImplicitFileExport(boolean value); |
| |
| public abstract Builder incompatibleNoRuleOutputsParam(boolean value); |
| |
| public abstract Builder incompatibleNoSupportToolsInActionInputs(boolean value); |
| |
| public abstract Builder incompatibleRunShellCommandString(boolean value); |
| |
| public abstract Builder incompatibleStringReplaceCount(boolean value); |
| |
| public abstract Builder incompatibleVisibilityPrivateAttributesAtDefinition(boolean value); |
| |
| public abstract Builder internalStarlarkFlagTestCanary(boolean value); |
| |
| public abstract Builder incompatibleDoNotSplitLinkingCmdline(boolean value); |
| |
| public abstract Builder incompatibleDepsetForLibrariesToLinkGetter(boolean value); |
| |
| public abstract Builder incompatibleRequireLinkerInputCcApi(boolean value); |
| |
| public abstract Builder incompatibleRestrictStringEscapes(boolean value); |
| |
| public abstract Builder incompatibleUseCcConfigureFromRulesCc(boolean value); |
| |
| public abstract Builder incompatibleLinkoptsToLinkLibs(boolean value); |
| |
| public abstract Builder maxComputationSteps(long value); |
| |
| public abstract Builder recordRuleInstantiationCallstack(boolean value); |
| |
| public abstract StarlarkSemantics build(); |
| } |
| } |