blob: 9285092ad1c41a2de00f3e9a489e19ddb317c7a9 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
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
15package com.google.devtools.build.lib.analysis;
16
Dmitry Lomov8f45b7c2016-11-18 15:14:56 +000017import static com.google.devtools.build.lib.syntax.EvalUtils.SKYLARK_COMPARATOR;
18
dslomovf9697342017-05-02 16:26:39 +020019import com.google.common.collect.ImmutableCollection;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010020import com.google.common.collect.ImmutableMap;
Alex Humesky152feb02016-06-20 19:43:11 +000021import com.google.common.collect.ImmutableSortedSet;
22import com.google.common.collect.Sets;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010023import com.google.devtools.build.lib.actions.Artifact;
gregce2aee44b2017-09-16 07:16:44 +020024import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.DuplicateException;
ulfjack35625252017-08-08 19:45:46 +020025import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleConfiguredTargetUtil;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010026import com.google.devtools.build.lib.collect.nestedset.NestedSet;
Lukacs Berki6916be22015-02-19 13:36:06 +000027import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
28import com.google.devtools.build.lib.collect.nestedset.Order;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010029import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
Dmitry Lomov8f45b7c2016-11-18 15:14:56 +000030import com.google.devtools.build.lib.events.Location;
cparsons2d67cf92018-05-24 14:02:09 -070031import com.google.devtools.build.lib.packages.BuiltinProvider;
dslomovf1296572017-08-22 16:29:06 +020032import com.google.devtools.build.lib.packages.NativeInfo;
cpeyser10b1a5f2018-02-15 09:37:15 -080033import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
cparsons2d67cf92018-05-24 14:02:09 -070034import com.google.devtools.build.lib.skylarkbuildapi.OutputGroupInfoApi;
Googlera9c93632019-11-13 10:48:07 -080035import com.google.devtools.build.lib.syntax.Dict;
Dmitry Lomov8f45b7c2016-11-18 15:14:56 +000036import com.google.devtools.build.lib.syntax.EvalException;
37import com.google.devtools.build.lib.syntax.EvalUtils;
Dmitry Lomov8f45b7c2016-11-18 15:14:56 +000038import com.google.devtools.build.lib.syntax.SkylarkIndexable;
39import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
Dmitry Lomove2033b12015-08-19 16:57:49 +000040import java.util.HashSet;
Dmitry Lomov8f45b7c2016-11-18 15:14:56 +000041import java.util.Iterator;
Dmitry Lomove2033b12015-08-19 16:57:49 +000042import java.util.List;
dslomovf9697342017-05-02 16:26:39 +020043import java.util.Map;
Dmitry Lomove2033b12015-08-19 16:57:49 +000044import java.util.Set;
Dmitry Lomove2033b12015-08-19 16:57:49 +000045import javax.annotation.Nullable;
46
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010047/**
Lukacs Berkic1f894e2015-02-17 13:00:26 +000048 * {@code ConfiguredTarget}s implementing this interface can provide artifacts that <b>can</b> be
49 * built when the target is mentioned on the command line (as opposed to being always built, like
50 * {@link com.google.devtools.build.lib.analysis.FileProvider})
51 *
dslomovde965ac2017-07-31 21:07:51 +020052 * <p>The artifacts are grouped into "output groups". Which output groups are built is controlled by
53 * the {@code --output_groups} undocumented command line option, which in turn is added to the
Lukacs Berkic1f894e2015-02-17 13:00:26 +000054 * command line at the discretion of the build command being run.
Lukacs Berki6916be22015-02-19 13:36:06 +000055 *
56 * <p>Output groups starting with an underscore are "not important". This means that artifacts built
57 * because such an output group is mentioned in a {@code --output_groups} command line option are
58 * not mentioned on the output.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010059 */
60@Immutable
cpeyser10b1a5f2018-02-15 09:37:15 -080061@AutoCodec
dslomov69c45f82017-12-14 11:15:43 -050062public final class OutputGroupInfo extends NativeInfo
cparsons2d67cf92018-05-24 14:02:09 -070063 implements SkylarkIndexable, Iterable<String>, OutputGroupInfoApi {
vladmos360fb4d2017-04-11 11:14:22 +000064 public static final String SKYLARK_NAME = "output_groups";
Lukacs Berki1b18ae92015-02-24 10:48:38 +000065
cparsons2d67cf92018-05-24 14:02:09 -070066 public static final OutputGroupInfoProvider SKYLARK_CONSTRUCTOR = new OutputGroupInfoProvider();
dslomovf9697342017-05-02 16:26:39 +020067
Lukacs Berki1b18ae92015-02-24 10:48:38 +000068 /**
69 * Prefix for output groups that are not reported to the user on the terminal output of Blaze when
70 * they are built.
71 */
Lukacs Berki6916be22015-02-19 13:36:06 +000072 public static final String HIDDEN_OUTPUT_GROUP_PREFIX = "_";
Lukacs Berki1b18ae92015-02-24 10:48:38 +000073
74 /**
Cal Peysereb856432016-06-22 14:25:36 +000075 * Suffix for output groups that are internal to bazel and may not be referenced from a filegroup.
76 */
77 public static final String INTERNAL_SUFFIX = "_INTERNAL_";
78
79 /**
Lukacs Berki1b18ae92015-02-24 10:48:38 +000080 * Building these artifacts only results in the compilation (and not e.g. linking) of the
81 * associated target. Mostly useful for C++, less so for e.g. Java.
82 */
lberki1dcd8f02018-04-04 03:13:55 -070083 public static final String FILES_TO_COMPILE = "compilation_outputs";
Lukacs Berki1b18ae92015-02-24 10:48:38 +000084
85 /**
86 * These artifacts are the direct requirements for compilation, but building these does not
87 * actually compile the target. Mostly useful when IDEs want Blaze to emit generated code so that
88 * they can do the compilation in their own way.
89 */
Cal Peysereb856432016-06-22 14:25:36 +000090 public static final String COMPILATION_PREREQUISITES =
91 "compilation_prerequisites" + INTERNAL_SUFFIX;
Lukacs Berki6916be22015-02-19 13:36:06 +000092
Lukacs Berki1b18ae92015-02-24 10:48:38 +000093 /**
94 * These files are built when a target is mentioned on the command line, but are not reported to
95 * the user. This is mostly runfiles, which is necessary because we don't want a target to
96 * successfully build if a file in its runfiles is broken.
97 */
Cal Peysereb856432016-06-22 14:25:36 +000098 public static final String HIDDEN_TOP_LEVEL =
99 HIDDEN_OUTPUT_GROUP_PREFIX + "hidden_top_level" + INTERNAL_SUFFIX;
Lukacs Berki1b18ae92015-02-24 10:48:38 +0000100
Lukacs Berkib9e51302015-02-25 09:47:29 +0000101 /**
ahumesky60205bb2019-10-14 13:50:00 -0700102 * This output group contains artifacts that are the outputs of validation actions. These actions
103 * should be run even if no other action depends on their outputs, therefore this output group is:
104 *
105 * <ul>
106 * <li>built even if <code>--output_groups</code> overrides the default output groups
107 * <li>not affected by the subtraction operation of <code>--output_groups</code> (i.e. <code>
108 * "--output_groups=-_validation"</code>)
109 * </ul>
110 *
111 * The only way to disable this output group is with <code>--run_validations=false</code>.
112 */
113 public static final String VALIDATION = HIDDEN_OUTPUT_GROUP_PREFIX + "validation";
114
115 /**
Lukacs Berkib9e51302015-02-25 09:47:29 +0000116 * Temporary files created during building a rule, for example, .i, .d and .s files for C++
117 * compilation.
118 *
119 * <p>This output group is somewhat special: it is always built, but it only contains files when
120 * the {@code --save_temps} command line option present. I'm not sure if this is to save RAM by
121 * not creating the associated actions and artifacts if we don't need them or just historical
122 * baggage.
123 */
Cal Peysereb856432016-06-22 14:25:36 +0000124 public static final String TEMP_FILES = "temp_files" + INTERNAL_SUFFIX;
Lukacs Berkib9e51302015-02-25 09:47:29 +0000125
Lukacs Berki97f47ba2015-02-25 10:38:04 +0000126 /**
Lukacs Berki91ec2742015-03-10 09:09:20 +0000127 * The default group of files built by a target when it is mentioned on the command line.
Lukacs Berki97f47ba2015-02-25 10:38:04 +0000128 */
129 public static final String DEFAULT = "default";
130
Michajlo Matijkiwc1d94502015-03-18 12:17:22 +0000131 /**
132 * The default set of OutputGroups we typically want to build.
133 */
ulfjackf0009962018-07-23 01:19:20 -0700134 public static final ImmutableSortedSet<String> DEFAULT_GROUPS =
135 ImmutableSortedSet.of(DEFAULT, TEMP_FILES, HIDDEN_TOP_LEVEL);
Michajlo Matijkiwc1d94502015-03-18 12:17:22 +0000136
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100137 private final ImmutableMap<String, NestedSet<Artifact>> outputGroups;
138
dslomov69c45f82017-12-14 11:15:43 -0500139 public OutputGroupInfo(ImmutableMap<String, NestedSet<Artifact>> outputGroups) {
cparsonse70aafe2018-02-28 12:16:38 -0800140 super(SKYLARK_CONSTRUCTOR);
Lukacs Berkic1f894e2015-02-17 13:00:26 +0000141 this.outputGroups = outputGroups;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100142 }
143
dslomovf9697342017-05-02 16:26:39 +0200144 @Nullable
dslomov69c45f82017-12-14 11:15:43 -0500145 public static OutputGroupInfo get(TransitiveInfoCollection collection) {
146 return collection.get(OutputGroupInfo.SKYLARK_CONSTRUCTOR);
dslomovf9697342017-05-02 16:26:39 +0200147 }
148
149 @Nullable
dslomov69c45f82017-12-14 11:15:43 -0500150 public static OutputGroupInfo get(ConfiguredAspect aspect) {
151 return (OutputGroupInfo) aspect.get(SKYLARK_CONSTRUCTOR.getKey());
dslomovf9697342017-05-02 16:26:39 +0200152 }
153
154
Lukacs Berki6916be22015-02-19 13:36:06 +0000155 /** Return the artifacts in a particular output group.
156 *
157 * @return the artifacts in the output group with the given name. The return value is never null.
158 * If the specified output group is not present, the empty set is returned.
159 */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100160 public NestedSet<Artifact> getOutputGroup(String outputGroupName) {
Lukacs Berki6916be22015-02-19 13:36:06 +0000161 return outputGroups.containsKey(outputGroupName)
162 ? outputGroups.get(outputGroupName)
163 : NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100164 }
Dmitry Lomove2033b12015-08-19 16:57:49 +0000165
166 /**
167 * Merges output groups from two output providers. The set of output groups must be disjoint.
168 *
169 * @param providers providers to merge {@code this} with.
170 */
171 @Nullable
dslomov69c45f82017-12-14 11:15:43 -0500172 public static OutputGroupInfo merge(List<OutputGroupInfo> providers)
Dmitry Lomov9b2fc5c2016-11-11 11:18:48 +0000173 throws DuplicateException {
Dmitry Lomove2033b12015-08-19 16:57:49 +0000174 if (providers.size() == 0) {
175 return null;
176 }
177 if (providers.size() == 1) {
178 return providers.get(0);
179 }
180
181 ImmutableMap.Builder<String, NestedSet<Artifact>> resultBuilder = new ImmutableMap.Builder<>();
182 Set<String> seenGroups = new HashSet<>();
dslomov69c45f82017-12-14 11:15:43 -0500183 for (OutputGroupInfo provider : providers) {
Dmitry Lomove2033b12015-08-19 16:57:49 +0000184 for (String outputGroup : provider.outputGroups.keySet()) {
185 if (!seenGroups.add(outputGroup)) {
Dmitry Lomov9b2fc5c2016-11-11 11:18:48 +0000186 throw new DuplicateException(
187 "Output group " + outputGroup + " provided twice");
Dmitry Lomove2033b12015-08-19 16:57:49 +0000188 }
189
190 resultBuilder.put(outputGroup, provider.getOutputGroup(outputGroup));
191 }
192 }
dslomov69c45f82017-12-14 11:15:43 -0500193 return new OutputGroupInfo(resultBuilder.build());
Dmitry Lomove2033b12015-08-19 16:57:49 +0000194 }
Alex Humesky152feb02016-06-20 19:43:11 +0000195
ahumesky60205bb2019-10-14 13:50:00 -0700196 public static ImmutableSortedSet<String> determineOutputGroups(
197 List<String> outputGroups, boolean includeValidationOutputGroup) {
198 return determineOutputGroups(DEFAULT_GROUPS, outputGroups, includeValidationOutputGroup);
Alex Humesky152feb02016-06-20 19:43:11 +0000199 }
200
201 public static ImmutableSortedSet<String> determineOutputGroups(
ahumesky60205bb2019-10-14 13:50:00 -0700202 Set<String> defaultOutputGroups,
203 List<String> outputGroups,
204 boolean includeValidationOutputGroup) {
Alex Humesky152feb02016-06-20 19:43:11 +0000205
206 Set<String> current = Sets.newHashSet();
207
208 // If all of the requested output groups start with "+" or "-", then these are added or
209 // subtracted to the set of default output groups.
210 // If any of them don't start with "+" or "-", then the list of requested output groups
ahumesky60205bb2019-10-14 13:50:00 -0700211 // overrides the default set of output groups, except for the validation output group.
Alex Humesky152feb02016-06-20 19:43:11 +0000212 boolean addDefaultOutputGroups = true;
213 for (String outputGroup : outputGroups) {
214 if (!(outputGroup.startsWith("+") || outputGroup.startsWith("-"))) {
215 addDefaultOutputGroups = false;
216 break;
217 }
218 }
219 if (addDefaultOutputGroups) {
220 current.addAll(defaultOutputGroups);
221 }
222
223 for (String outputGroup : outputGroups) {
224 if (outputGroup.startsWith("+")) {
225 current.add(outputGroup.substring(1));
226 } else if (outputGroup.startsWith("-")) {
227 current.remove(outputGroup.substring(1));
228 } else {
229 current.add(outputGroup);
230 }
231 }
232
ahumesky60205bb2019-10-14 13:50:00 -0700233 // Add the validation output group regardless of the additions and subtractions above.
234 if (includeValidationOutputGroup) {
235 current.add(VALIDATION);
236 }
237
Alex Humesky152feb02016-06-20 19:43:11 +0000238 return ImmutableSortedSet.copyOf(current);
239 }
Dmitry Lomov8f45b7c2016-11-18 15:14:56 +0000240
241 @Override
Googler4ff29122019-09-04 21:14:38 -0700242 public Object getIndex(Object key, Location loc) throws EvalException {
Dmitry Lomov8f45b7c2016-11-18 15:14:56 +0000243 if (!(key instanceof String)) {
244 throw new EvalException(loc, String.format(
245 "Output grout names must be strings, got %s instead",
246 EvalUtils.getDataTypeName(key)));
247 }
248
249 NestedSet<Artifact> result = outputGroups.get(key);
250 if (result != null) {
251 return SkylarkNestedSet.of(Artifact.class, result);
252 } else {
253 throw new EvalException(loc, String.format(
254 "Output group %s not present", key
255 ));
256 }
Dmitry Lomov8f45b7c2016-11-18 15:14:56 +0000257 }
258
259 @Override
Googler4ff29122019-09-04 21:14:38 -0700260 public boolean containsKey(Object key, Location loc) throws EvalException {
Dmitry Lomov8f45b7c2016-11-18 15:14:56 +0000261 return outputGroups.containsKey(key);
262 }
263
264 @Override
265 public Iterator<String> iterator() {
266 return SKYLARK_COMPARATOR.sortedCopy(outputGroups.keySet()).iterator();
267 }
dslomovf9697342017-05-02 16:26:39 +0200268
269 @Override
270 public Object getValue(String name) {
271 NestedSet<Artifact> result = outputGroups.get(name);
272 if (result == null) {
273 return null;
274 }
275 return SkylarkNestedSet.of(Artifact.class, result);
276 }
277
278 @Override
brandjond331fa72017-12-28 07:38:31 -0800279 public ImmutableCollection<String> getFieldNames() {
dslomovf9697342017-05-02 16:26:39 +0200280 return outputGroups.keySet();
281 }
282
cparsons2d67cf92018-05-24 14:02:09 -0700283 /**
284 * Provider implementation for {@link OutputGroupInfoApi.OutputGroupInfoApiProvider}.
285 */
286 public static class OutputGroupInfoProvider extends BuiltinProvider<OutputGroupInfo>
287 implements OutputGroupInfoApi.OutputGroupInfoApiProvider {
288 private OutputGroupInfoProvider() {
289 super("OutputGroupInfo", OutputGroupInfo.class);
dslomovf9697342017-05-02 16:26:39 +0200290 }
291
292 @Override
Googlera9c93632019-11-13 10:48:07 -0800293 public OutputGroupInfoApi constructor(Dict<?, ?> kwargs, Location loc) throws EvalException {
cparsons2d67cf92018-05-24 14:02:09 -0700294 Map<String, Object> kwargsMap = kwargs.getContents(String.class, Object.class, "kwargs");
dslomovf9697342017-05-02 16:26:39 +0200295
296 ImmutableMap.Builder<String, NestedSet<Artifact>> builder = ImmutableMap.builder();
cparsons2d67cf92018-05-24 14:02:09 -0700297 for (Map.Entry<String, Object> entry : kwargsMap.entrySet()) {
vladmos97d67082017-07-13 14:54:03 +0200298 builder.put(
299 entry.getKey(),
300 SkylarkRuleConfiguredTargetUtil.convertToOutputGroupValue(
dslomovf9697342017-05-02 16:26:39 +0200301 loc, entry.getKey(), entry.getValue()));
dslomovf9697342017-05-02 16:26:39 +0200302 }
dslomov69c45f82017-12-14 11:15:43 -0500303 return new OutputGroupInfo(builder.build());
dslomovf9697342017-05-02 16:26:39 +0200304 }
dslomovf9697342017-05-02 16:26:39 +0200305 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100306}