Skip to content

Commit 79989f9

Browse files
gregestrencopybara-github
authored andcommitted
Roll forward config_setting visibility enforcement behind a flag.
This was rolled back in 36d228b because of depot breakages. This version adds incompatible flags to safely introduce enforcement. See #12932 and #12933 for flag settings. *** Original change description *** Roll back #12877. *** Fixes #12669. RELNOTES: enforce config_setting visibility. See #12932 for details. PiperOrigin-RevId: 354930807
1 parent 4fc4868 commit 79989f9

File tree

19 files changed

+495
-60
lines changed

19 files changed

+495
-60
lines changed

site/docs/visibility.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,25 @@ specified in the [`package`](be/functions.html#package) statement of the
6262
target's BUILD file. If there is no such `default_visibility` declaration, the
6363
visibility is `//visibility:private`.
6464

65+
`config_setting` visibility has historically not been enforced.
66+
`--incompatible_enforce_config_setting_visibility` and
67+
`--incompatible_config_setting_private_default_visibility` provide migration
68+
logic for converging with other rules.
69+
70+
If `--incompatible_enforce_config_setting_visibility=false`, every
71+
`config_setting` is unconditionally visible to all targets.
72+
73+
Else if `--incompatible_config_setting_private_default_visibility=false`, any
74+
`config_setting` that doesn't explicitly set visibility is `//visibility:public`
75+
(ignoring package [`default_visibility`](be/functions.html#package.default_visibility)).
76+
77+
Else if `--incompatible_config_setting_private_default_visibility=true`,
78+
`config_setting` uses the same visibility logic as all other rules.
79+
80+
Best practice is to treat all `config_setting` targets like other rules:
81+
explicitly set `visibility` on any `config_setting` used anywhere outside its
82+
package.
83+
6584
### Example
6685

6786
File `//frobber/bin/BUILD`:

src/main/java/com/google/devtools/build/lib/analysis/BUILD

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ java_library(
292292
":buildinfo/build_info_key",
293293
":config/build_configuration",
294294
":config/build_options",
295+
":config/config_conditions",
295296
":config/config_matching_provider",
296297
":config/core_options",
297298
":config/execution_transition_factory",
@@ -1607,6 +1608,20 @@ java_library(
16071608
],
16081609
)
16091610

1611+
java_library(
1612+
name = "config/config_conditions",
1613+
srcs = ["config/ConfigConditions.java"],
1614+
deps = [
1615+
":config/config_matching_provider",
1616+
":configured_target",
1617+
"//src/main/java/com/google/devtools/build/lib/analysis/platform",
1618+
"//src/main/java/com/google/devtools/build/lib/cmdline",
1619+
"//src/main/java/com/google/devtools/build/lib/skyframe:configured_target_and_data",
1620+
"//third_party:auto_value",
1621+
"//third_party:guava",
1622+
],
1623+
)
1624+
16101625
java_library(
16111626
name = "config/core_option_converters",
16121627
srcs = ["config/CoreOptionConverters.java"],

src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
2828
import com.google.devtools.build.lib.analysis.RuleContext.InvalidExecGroupException;
2929
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
30-
import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
30+
import com.google.devtools.build.lib.analysis.config.ConfigConditions;
3131
import com.google.devtools.build.lib.analysis.config.Fragment;
3232
import com.google.devtools.build.lib.analysis.config.RequiredFragmentsUtil;
3333
import com.google.devtools.build.lib.analysis.configuredtargets.EnvironmentGroupConfiguredTarget;
@@ -181,7 +181,7 @@ public final ConfiguredTarget createConfiguredTarget(
181181
BuildConfiguration hostConfig,
182182
ConfiguredTargetKey configuredTargetKey,
183183
OrderedSetMultimap<DependencyKind, ConfiguredTargetAndData> prerequisiteMap,
184-
ImmutableMap<Label, ConfigMatchingProvider> configConditions,
184+
ConfigConditions configConditions,
185185
@Nullable ToolchainCollection<ResolvedToolchainContext> toolchainContexts)
186186
throws InterruptedException, ActionConflictException, InvalidExecGroupException {
187187
if (target instanceof Rule) {
@@ -287,7 +287,7 @@ private ConfiguredTarget createRule(
287287
BuildConfiguration hostConfiguration,
288288
ConfiguredTargetKey configuredTargetKey,
289289
OrderedSetMultimap<DependencyKind, ConfiguredTargetAndData> prerequisiteMap,
290-
ImmutableMap<Label, ConfigMatchingProvider> configConditions,
290+
ConfigConditions configConditions,
291291
@Nullable ToolchainCollection<ResolvedToolchainContext> toolchainContexts)
292292
throws InterruptedException, ActionConflictException, InvalidExecGroupException {
293293
ConfigurationFragmentPolicy configurationFragmentPolicy =
@@ -318,7 +318,7 @@ private ConfiguredTarget createRule(
318318
configuration,
319319
ruleClassProvider.getUniversalFragments(),
320320
configurationFragmentPolicy,
321-
configConditions,
321+
configConditions.asProviders(),
322322
prerequisiteMap.values()))
323323
.build();
324324

@@ -495,7 +495,7 @@ public ConfiguredAspect createAspect(
495495
ConfiguredAspectFactory aspectFactory,
496496
Aspect aspect,
497497
OrderedSetMultimap<DependencyKind, ConfiguredTargetAndData> prerequisiteMap,
498-
ImmutableMap<Label, ConfigMatchingProvider> configConditions,
498+
ConfigConditions configConditions,
499499
@Nullable ResolvedToolchainContext toolchainContext,
500500
BuildConfiguration aspectConfiguration,
501501
BuildConfiguration hostConfiguration,
@@ -540,7 +540,7 @@ public ConfiguredAspect createAspect(
540540
aspectConfiguration,
541541
ruleClassProvider.getUniversalFragments(),
542542
aspect.getDefinition().getConfigurationFragmentPolicy(),
543-
configConditions,
543+
configConditions.asProviders(),
544544
prerequisiteMap.values()))
545545
.build();
546546

src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
4747
import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoKey;
4848
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
49+
import com.google.devtools.build.lib.analysis.config.ConfigConditions;
4950
import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
5051
import com.google.devtools.build.lib.analysis.config.CoreOptions;
5152
import com.google.devtools.build.lib.analysis.config.CoreOptions.IncludeConfigFragmentsEnum;
@@ -80,6 +81,7 @@
8081
import com.google.devtools.build.lib.packages.Info;
8182
import com.google.devtools.build.lib.packages.InputFile;
8283
import com.google.devtools.build.lib.packages.OutputFile;
84+
import com.google.devtools.build.lib.packages.Package.ConfigSettingVisibilityPolicy;
8385
import com.google.devtools.build.lib.packages.PackageSpecification.PackageGroupContents;
8486
import com.google.devtools.build.lib.packages.RawAttributeMapper;
8587
import com.google.devtools.build.lib.packages.RequiredProviders;
@@ -1766,7 +1768,7 @@ public static final class Builder implements RuleErrorConsumer {
17661768
private final PrerequisiteValidator prerequisiteValidator;
17671769
private final RuleErrorConsumer reporter;
17681770
private OrderedSetMultimap<Attribute, ConfiguredTargetAndData> prerequisiteMap;
1769-
private ImmutableMap<Label, ConfigMatchingProvider> configConditions = ImmutableMap.of();
1771+
private ConfigConditions configConditions;
17701772
private String toolsRepository;
17711773
private StarlarkSemantics starlarkSemantics;
17721774
private Mutability mutability;
@@ -1815,11 +1817,21 @@ public RuleContext build() throws InvalidExecGroupException {
18151817
Preconditions.checkNotNull(visibility);
18161818
Preconditions.checkNotNull(constraintSemantics);
18171819
AttributeMap attributes =
1818-
ConfiguredAttributeMapper.of(target.getAssociatedRule(), configConditions);
1820+
ConfiguredAttributeMapper.of(target.getAssociatedRule(), configConditions.asProviders());
18191821
checkAttributesNonEmpty(attributes);
18201822
ListMultimap<String, ConfiguredTargetAndData> targetMap = createTargetMap();
1823+
// This conditionally checks visibility on config_setting rules based on
1824+
// --config_setting_visibility_policy. This should be removed as soon as it's deemed safe
1825+
// to unconditionally check visibility. See https://github.com/bazelbuild/bazel/issues/12669.
1826+
if (target.getPackage().getConfigSettingVisibilityPolicy()
1827+
!= ConfigSettingVisibilityPolicy.LEGACY_OFF) {
1828+
Attribute configSettingAttr = attributes.getAttributeDefinition("$config_dependencies");
1829+
for (ConfiguredTargetAndData condition : configConditions.asConfiguredTargets().values()) {
1830+
validateDirectPrerequisite(configSettingAttr, condition);
1831+
}
1832+
}
18211833
ListMultimap<String, ConfiguredFilesetEntry> filesetEntryMap =
1822-
createFilesetEntryMap(target.getAssociatedRule(), configConditions);
1834+
createFilesetEntryMap(target.getAssociatedRule(), configConditions.asProviders());
18231835
if (rawExecProperties == null) {
18241836
if (!attributes.has(RuleClass.EXEC_PROPERTIES, Type.STRING_DICT)) {
18251837
rawExecProperties = ImmutableMap.of();
@@ -1833,7 +1845,7 @@ public RuleContext build() throws InvalidExecGroupException {
18331845
attributes,
18341846
targetMap,
18351847
filesetEntryMap,
1836-
configConditions,
1848+
configConditions.asProviders(),
18371849
universalFragments,
18381850
getRuleClassNameForLogging(),
18391851
actionOwnerSymbol,
@@ -1908,11 +1920,10 @@ public Builder setAspectAttributes(Map<String, Attribute> aspectAttributes) {
19081920
}
19091921

19101922
/**
1911-
* Sets the configuration conditions needed to determine which paths to follow for this
1912-
* rule's configurable attributes.
1923+
* Sets the configuration conditions needed to determine which paths to follow for this rule's
1924+
* configurable attributes.
19131925
*/
1914-
public Builder setConfigConditions(
1915-
ImmutableMap<Label, ConfigMatchingProvider> configConditions) {
1926+
public Builder setConfigConditions(ConfigConditions configConditions) {
19161927
this.configConditions = Preconditions.checkNotNull(configConditions);
19171928
return this;
19181929
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright 2021 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+
package com.google.devtools.build.lib.analysis.config;
15+
16+
import com.google.auto.value.AutoValue;
17+
import com.google.common.collect.ImmutableMap;
18+
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
19+
import com.google.devtools.build.lib.analysis.platform.ConstraintValueInfo;
20+
import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
21+
import com.google.devtools.build.lib.cmdline.Label;
22+
import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
23+
24+
/**
25+
* Utility class for temporarily tracking {@code select()} keys' {@link ConfigMatchingProvider}s and
26+
* {@link ConfiguredTarget}s.
27+
*
28+
* <p>This is a utility class because its only purpose is to maintain {@link ConfiguredTarget} long
29+
* enough for {@link RuleContext.Builder} to do prerequisite validation on it (for example,
30+
* visibility checks).
31+
*
32+
* <p>Once {@link RuleContext} is instantiated, it should only have access to {@link
33+
* ConfigMatchingProvider}, on the principle that providers are the correct interfaces for storing
34+
* and sharing target metadata. {@link ConfiguredTarget} isn't meant to persist that long.
35+
*/
36+
@AutoValue
37+
public abstract class ConfigConditions {
38+
public abstract ImmutableMap<Label, ConfiguredTargetAndData> asConfiguredTargets();
39+
40+
public abstract ImmutableMap<Label, ConfigMatchingProvider> asProviders();
41+
42+
public static ConfigConditions create(
43+
ImmutableMap<Label, ConfiguredTargetAndData> asConfiguredTargets,
44+
ImmutableMap<Label, ConfigMatchingProvider> asProviders) {
45+
return new AutoValue_ConfigConditions(asConfiguredTargets, asProviders);
46+
}
47+
48+
public static final ConfigConditions EMPTY =
49+
ConfigConditions.create(ImmutableMap.of(), ImmutableMap.of());
50+
51+
/** Exception for when a {@code select()} has an invalid key (for example, wrong target type). */
52+
public static class InvalidConditionException extends Exception {}
53+
54+
/**
55+
* Returns a {@link ConfigMatchingProvider} from the given configured target if appropriate, else
56+
* triggers a {@link InvalidConditionException}.
57+
*
58+
* <p>This is the canonical place to extract {@link ConfigMatchingProvider}s from configured
59+
* targets. It's not as simple as {@link ConfiguredTarget#getProvider}.
60+
*/
61+
public static ConfigMatchingProvider fromConfiguredTarget(
62+
ConfiguredTargetAndData selectKey, PlatformInfo targetPlatform)
63+
throws InvalidConditionException {
64+
ConfiguredTarget selectable = selectKey.getConfiguredTarget();
65+
// The below handles config_setting (which natively provides ConfigMatchingProvider) and
66+
// constraint_value (which needs a custom-built ConfigMatchingProvider).
67+
ConfigMatchingProvider matchingProvider = selectable.getProvider(ConfigMatchingProvider.class);
68+
if (matchingProvider != null) {
69+
return matchingProvider;
70+
}
71+
ConstraintValueInfo constraintValueInfo = selectable.get(ConstraintValueInfo.PROVIDER);
72+
if (constraintValueInfo != null && targetPlatform != null) {
73+
// If platformInfo == null, that means the owning target doesn't invoke toolchain
74+
// resolution, in which case depending on a constraint_value is nonsensical.
75+
return constraintValueInfo.configMatchingProvider(targetPlatform);
76+
}
77+
78+
// Not a valid provider for configuration conditions.
79+
throw new InvalidConditionException();
80+
}
81+
}

src/main/java/com/google/devtools/build/lib/packages/Package.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,24 @@ private NameConflictException(String message) {
143143
private RuleVisibility defaultVisibility;
144144
private boolean defaultVisibilitySet;
145145

146+
/**
147+
* How to enforce config_setting visibility settings.
148+
*
149+
* <p>This is a temporary setting in service of https://github.com/bazelbuild/bazel/issues/12669.
150+
* After enough depot cleanup, config_setting will have the same visibility enforcement as all
151+
* other rules.
152+
*/
153+
public enum ConfigSettingVisibilityPolicy {
154+
/** Don't enforce visibility for any config_setting. */
155+
LEGACY_OFF,
156+
/** Honor explicit visibility settings on config_setting, else use //visibility:public. */
157+
DEFAULT_PUBLIC,
158+
/** Enforce config_setting visibility exactly the same as all other rules. */
159+
DEFAULT_STANDARD
160+
}
161+
162+
private ConfigSettingVisibilityPolicy configSettingVisibilityPolicy;
163+
146164
/**
147165
* Default package-level 'testonly' value for rules that do not specify it.
148166
*/
@@ -436,6 +454,7 @@ private void finishInit(Builder builder) {
436454
this.targets = ImmutableSortedKeyMap.copyOf(builder.targets);
437455
this.defaultVisibility = builder.defaultVisibility;
438456
this.defaultVisibilitySet = builder.defaultVisibilitySet;
457+
this.configSettingVisibilityPolicy = builder.configSettingVisibilityPolicy;
439458
if (builder.defaultCopts == null) {
440459
this.defaultCopts = ImmutableList.of();
441460
} else {
@@ -700,6 +719,14 @@ public RuleVisibility getDefaultVisibility() {
700719
return defaultVisibility;
701720
}
702721

722+
/**
723+
* How to enforce visibility on <code>config_setting</code> See
724+
* {@link ConfigSettingVisibilityPolicy} for details.
725+
*/
726+
public ConfigSettingVisibilityPolicy getConfigSettingVisibilityPolicy() {
727+
return configSettingVisibilityPolicy;
728+
}
729+
703730
/**
704731
* Returns the default testonly value.
705732
*/
@@ -920,6 +947,7 @@ public boolean recordLoadedModules() {
920947
// serialized representation is deterministic.
921948
private final TreeMap<String, String> makeEnv = new TreeMap<>();
922949
private RuleVisibility defaultVisibility = ConstantRuleVisibility.PRIVATE;
950+
private ConfigSettingVisibilityPolicy configSettingVisibilityPolicy;
923951
private boolean defaultVisibilitySet;
924952
private List<String> defaultCopts = null;
925953
private final List<String> features = new ArrayList<>();
@@ -1163,6 +1191,12 @@ public Builder setDefaultVisibilitySet(boolean defaultVisibilitySet) {
11631191
return this;
11641192
}
11651193

1194+
/** Sets visibility enforcement policy for <code>config_setting</code>. */
1195+
public Builder setConfigSettingVisibilityPolicy(ConfigSettingVisibilityPolicy policy) {
1196+
this.configSettingVisibilityPolicy = policy;
1197+
return this;
1198+
}
1199+
11661200
/** Sets the default value of 'testonly'. Rule-level 'testonly' will override this. */
11671201
Builder setDefaultTestonly(boolean defaultTestonly) {
11681202
pkg.setDefaultTestOnly(defaultTestonly);

src/main/java/com/google/devtools/build/lib/packages/Rule.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.google.devtools.build.lib.events.EventHandler;
3535
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.StarlarkImplicitOutputsFunction;
3636
import com.google.devtools.build.lib.packages.License.DistributionType;
37+
import com.google.devtools.build.lib.packages.Package.ConfigSettingVisibilityPolicy;
3738
import com.google.devtools.build.lib.util.BinaryPredicate;
3839
import java.util.Collection;
3940
import java.util.HashSet;
@@ -842,10 +843,27 @@ public String toString() {
842843
*/
843844
@Override
844845
public RuleVisibility getVisibility() {
846+
// Temporary logic to relax config_setting's visibility enforcement while depot migrations set
847+
// visibility settings properly (legacy code may have visibility settings that would break if
848+
// enforced). See https://github.com/bazelbuild/bazel/issues/12669. Ultimately this entire
849+
// conditional should be removed.
850+
if (ruleClass.getName().equals("config_setting")) {
851+
ConfigSettingVisibilityPolicy policy = getPackage().getConfigSettingVisibilityPolicy();
852+
if (policy == ConfigSettingVisibilityPolicy.LEGACY_OFF) {
853+
return ConstantRuleVisibility.PUBLIC; // Always public, no matter what.
854+
} else if (visibility != null) {
855+
return visibility; // Use explicitly set visibility
856+
} else if (policy == ConfigSettingVisibilityPolicy.DEFAULT_PUBLIC) {
857+
return ConstantRuleVisibility.PUBLIC; // Default: //visibility:public.
858+
} else {
859+
return pkg.getDefaultVisibility(); // Default: same as all other rules.
860+
}
861+
}
862+
863+
// All other rules.
845864
if (visibility != null) {
846865
return visibility;
847866
}
848-
849867
return pkg.getDefaultVisibility();
850868
}
851869

0 commit comments

Comments
 (0)