-
Notifications
You must be signed in to change notification settings - Fork 4.1k
/
Copy pathConfiguredTargetKey.java
258 lines (226 loc) · 9.75 KB
/
ConfiguredTargetKey.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
// Copyright 2014 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.skyframe;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Interner;
import com.google.devtools.build.lib.actions.ActionLookupKey;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.concurrent.BlazeInterners;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.skyframe.SkyFunctionName;
import java.util.Objects;
import javax.annotation.Nullable;
/**
* In simple form, a ({@link Label}, {@link BuildConfigurationValue}) pair used to trigger immediate
* dependency resolution and the rule analysis.
*
* <p>In practice, a ({@link Label} and post-transition {@link BuildConfigurationKey}) pair plus a
* possible execution platform override {@link Label} with special constraints. To elaborate, in
* order of highest to lowest potential for concern:
*
* <p>1. The {@link BuildConfigurationKey} must be post-transition and thus ready for immediate use
* in dependency resolution and analysis. In practice, this means that if the rule has an
* incoming-edge transition (cfg in {@link RuleClass}) or there are global trimming transitions,
* THOSE TRANSITIONS MUST ALREADY BE DONE before creating the key. Failure to do so will lead to
* build graphs with ConfiguredTarget that have seemingly impossible {@link BuildConfigurationValue}
* (due to the skipped transitions).
*
* <p>2. A build should not request keys with equal ({@link Label}, {@link BuildConfigurationValue})
* pairs but different execution platform override {@link Label} if the invoked rule will register
* actions. (This is potentially OK if all outputs of all registered actions incorporate the
* execution platform in their name unless the build also requests keys without an override that
* happen to resolve to the same execution platform.) In practice, this issue has not been seen in
* any 'real' builds; however, pathologically failure could lead to multiple (potentially different)
* ConfiguredTarget that have the same ({@link Label}, {@link BuildConfigurationValue}) pair.
*
* <p>Note that this key may be used to look up the generating action of an artifact.
*
* <p>TODO(blaze-configurability-team): Consider just using BuildOptions over a
* BuildConfigurationKey.
*/
@AutoCodec
public class ConfiguredTargetKey implements ActionLookupKey {
/**
* Cache so that the number of ConfiguredTargetKey instances is {@code O(configured targets)} and
* not {@code O(edges between configured targets)}.
*/
private static final Interner<ConfiguredTargetKey> interner = BlazeInterners.newWeakInterner();
private final Label label;
@Nullable private final BuildConfigurationKey configurationKey;
private final transient int hashCode;
ConfiguredTargetKey(Label label, @Nullable BuildConfigurationKey configurationKey, int hashCode) {
this.label = checkNotNull(label);
this.configurationKey = configurationKey;
this.hashCode = hashCode;
}
@AutoCodec.VisibleForSerialization
@AutoCodec.Instantiator
static ConfiguredTargetKey create(Label label, @Nullable BuildConfigurationKey configurationKey) {
int hashCode = computeHashCode(label, configurationKey, /*executionPlatformLabel=*/ null);
return interner.intern(new ConfiguredTargetKey(label, configurationKey, hashCode));
}
public Builder toBuilder() {
return builder()
.setConfigurationKey(configurationKey)
.setLabel(label)
.setExecutionPlatformLabel(getExecutionPlatformLabel());
}
@Override
public final Label getLabel() {
return label;
}
@Override
public final SkyFunctionName functionName() {
return SkyFunctions.CONFIGURED_TARGET;
}
@Nullable
public final BuildConfigurationKey getConfigurationKey() {
return configurationKey;
}
@Nullable
public Label getExecutionPlatformLabel() {
return null;
}
@Override
public final int hashCode() {
return hashCode;
}
private static int computeHashCode(
Label label,
@Nullable BuildConfigurationKey configurationKey,
@Nullable Label executionPlatformLabel) {
int configVal = configurationKey == null ? 79 : configurationKey.hashCode();
int executionPlatformLabelVal =
executionPlatformLabel == null ? 47 : executionPlatformLabel.hashCode();
return 31 * label.hashCode() + configVal + executionPlatformLabelVal;
}
@Override
public final boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ConfiguredTargetKey)) {
return false;
}
ConfiguredTargetKey other = (ConfiguredTargetKey) obj;
return hashCode == other.hashCode
&& label.equals(other.label)
&& Objects.equals(configurationKey, other.configurationKey)
&& Objects.equals(getExecutionPlatformLabel(), other.getExecutionPlatformLabel());
}
public final String prettyPrint() {
if (label == null) {
return "null";
}
return String.format(
"%s (%s)",
label, configurationKey == null ? "null" : configurationKey.getOptions().checksum());
}
@Override
public final String toString() {
// TODO(b/162809183): consider reverting to less verbose toString when bug is resolved.
MoreObjects.ToStringHelper helper =
MoreObjects.toStringHelper(this).add("label", label).add("config", configurationKey);
if (getExecutionPlatformLabel() != null) {
helper.add("executionPlatformLabel", getExecutionPlatformLabel());
}
return helper.toString();
}
@AutoCodec.VisibleForSerialization
@AutoCodec
static class ToolchainDependencyConfiguredTargetKey extends ConfiguredTargetKey {
private static final Interner<ToolchainDependencyConfiguredTargetKey>
toolchainDependencyConfiguredTargetKeyInterner = BlazeInterners.newWeakInterner();
private final Label executionPlatformLabel;
private ToolchainDependencyConfiguredTargetKey(
Label label,
@Nullable BuildConfigurationKey configurationKey,
int hashCode,
Label executionPlatformLabel) {
super(label, configurationKey, hashCode);
this.executionPlatformLabel = checkNotNull(executionPlatformLabel);
}
@AutoCodec.VisibleForSerialization
@AutoCodec.Instantiator
static ToolchainDependencyConfiguredTargetKey create(
Label label,
@Nullable BuildConfigurationKey configurationKey,
Label executionPlatformLabel) {
int hashCode = computeHashCode(label, configurationKey, executionPlatformLabel);
return toolchainDependencyConfiguredTargetKeyInterner.intern(
new ToolchainDependencyConfiguredTargetKey(
label, configurationKey, hashCode, executionPlatformLabel));
}
@Override
public final Label getExecutionPlatformLabel() {
return executionPlatformLabel;
}
}
/** Returns a new {@link Builder} to create instances of {@link ConfiguredTargetKey}. */
public static Builder builder() {
return new Builder();
}
/** A helper class to create instances of {@link ConfiguredTargetKey}. */
public static final class Builder {
private Label label = null;
private BuildConfigurationKey configurationKey = null;
private Label executionPlatformLabel = null;
private Builder() {}
/** Sets the label for the target. */
public Builder setLabel(Label label) {
this.label = label;
return this;
}
/**
* Sets the {@link ConfiguredTarget} that we want a key for.
*
* <p>This sets both the label and configurationKey data.
*/
public Builder setConfiguredTarget(ConfiguredTarget configuredTarget) {
setLabel(configuredTarget.getOriginalLabel());
if (this.configurationKey == null) {
setConfigurationKey(configuredTarget.getConfigurationKey());
}
return this;
}
/** Sets the {@link BuildConfigurationValue} for the configured target. */
public Builder setConfiguration(@Nullable BuildConfigurationValue buildConfiguration) {
return setConfigurationKey(buildConfiguration == null ? null : buildConfiguration.getKey());
}
/** Sets the configuration key for the configured target. */
public Builder setConfigurationKey(@Nullable BuildConfigurationKey configurationKey) {
this.configurationKey = configurationKey;
return this;
}
/**
* Sets the execution platform {@link Label} this configured target should use for toolchain
* resolution. When present, this overrides the normally determined execution platform.
*/
public Builder setExecutionPlatformLabel(@Nullable Label executionPlatformLabel) {
this.executionPlatformLabel = executionPlatformLabel;
return this;
}
/** Builds a new {@link ConfiguredTargetKey} based on the supplied data. */
public ConfiguredTargetKey build() {
if (this.executionPlatformLabel != null) {
return ToolchainDependencyConfiguredTargetKey.create(
label, configurationKey, executionPlatformLabel);
}
return create(label, configurationKey);
}
}
}