/** Returns true iff code coverage is enabled for the given target. */ private boolean isCodeCoverageEnabled() { if (configuration.isCodeCoverageEnabled()) { // If rule is matched by the instrumentation filter, enable instrumentation if (InstrumentedFilesCollector.shouldIncludeLocalSources(ruleContext)) { return true; } // At this point the rule itself is not matched by the instrumentation filter. However, we // might still want to instrument C++ rules if one of the targets listed in "deps" is // instrumented and, therefore, can supply header files that we would want to collect code // coverage for. For example, think about cc_test rule that tests functionality defined in a // header file that is supplied by the cc_library. // // Note that we only check direct prerequisites and not the transitive closure. This is done // for two reasons: // a) It is a good practice to declare libraries which you directly rely on. Including headers // from a library hidden deep inside the transitive closure makes build dependencies less // readable and can lead to unexpected breakage. // b) Traversing the transitive closure for each C++ compile action would require more complex // implementation (with caching results of this method) to avoid O(N^2) slowdown. if (ruleContext.getRule().isAttrDefined("deps", BuildType.LABEL_LIST)) { for (TransitiveInfoCollection dep : ruleContext.getPrerequisites("deps", Mode.TARGET)) { if (dep.getProvider(CppCompilationContext.class) != null && InstrumentedFilesCollector.shouldIncludeLocalSources(configuration, dep)) { return true; } } } } return false; }
private static ConfiguredTarget addStructFieldsAndBuild( RuleContext ruleContext, RuleConfiguredTargetBuilder builder, Object target, Artifact executable, Map<String, Class<? extends TransitiveInfoProvider>> registeredProviderTypes) throws EvalException { Location loc = null; Runfiles statelessRunfiles = null; Runfiles dataRunfiles = null; Runfiles defaultRunfiles = null; if (target instanceof SkylarkClassObject) { SkylarkClassObject struct = (SkylarkClassObject) target; loc = struct.getCreationLoc(); for (String key : struct.getKeys()) { if (key.equals("files")) { // If we specify files_to_build we don't have the executable in it by default. builder.setFilesToBuild( cast("files", struct, SkylarkNestedSet.class, Artifact.class, loc) .getSet(Artifact.class)); } else if (key.equals("runfiles")) { statelessRunfiles = cast("runfiles", struct, Runfiles.class, loc); } else if (key.equals("data_runfiles")) { dataRunfiles = cast("data_runfiles", struct, Runfiles.class, loc); } else if (key.equals("default_runfiles")) { defaultRunfiles = cast("default_runfiles", struct, Runfiles.class, loc); } else if (key.equals("output_groups")) { addOutputGroups(struct.getValue(key), loc, builder); } else if (key.equals("instrumented_files")) { SkylarkClassObject insStruct = cast("instrumented_files", struct, SkylarkClassObject.class, loc); Location insLoc = insStruct.getCreationLoc(); FileTypeSet fileTypeSet = FileTypeSet.ANY_FILE; if (insStruct.getKeys().contains("extensions")) { @SuppressWarnings("unchecked") List<String> exts = cast("extensions", insStruct, SkylarkList.class, String.class, insLoc); if (exts.isEmpty()) { fileTypeSet = FileTypeSet.NO_FILE; } else { FileType[] fileTypes = new FileType[exts.size()]; for (int i = 0; i < fileTypes.length; i++) { fileTypes[i] = FileType.of(exts.get(i)); } fileTypeSet = FileTypeSet.of(fileTypes); } } List<String> dependencyAttributes = Collections.emptyList(); if (insStruct.getKeys().contains("dependency_attributes")) { dependencyAttributes = cast("dependency_attributes", insStruct, SkylarkList.class, String.class, insLoc); } List<String> sourceAttributes = Collections.emptyList(); if (insStruct.getKeys().contains("source_attributes")) { sourceAttributes = cast("source_attributes", insStruct, SkylarkList.class, String.class, insLoc); } InstrumentationSpec instrumentationSpec = new InstrumentationSpec(fileTypeSet) .withSourceAttributes(sourceAttributes.toArray(new String[0])) .withDependencyAttributes(dependencyAttributes.toArray(new String[0])); InstrumentedFilesProvider instrumentedFilesProvider = InstrumentedFilesCollector.collect( ruleContext, instrumentationSpec, InstrumentedFilesCollector.NO_METADATA_COLLECTOR, Collections.<Artifact>emptySet()); builder.addProvider(InstrumentedFilesProvider.class, instrumentedFilesProvider); } else if (registeredProviderTypes.containsKey(key)) { Class<? extends TransitiveInfoProvider> providerType = registeredProviderTypes.get(key); TransitiveInfoProvider provider = cast(key, struct, providerType, loc); builder.addProvider(providerType, provider); } else if (key.equals("providers")) { Iterable iterable = cast(key, struct, Iterable.class, loc); for (Object o : iterable) { SkylarkClassObject declaredProvider = SkylarkType.cast( o, SkylarkClassObject.class, loc, "The value of 'providers' should be a sequence of declared providers"); builder.addSkylarkDeclaredProvider(declaredProvider, loc); } } else if (!key.equals("executable")) { // We handled executable already. builder.addSkylarkTransitiveInfo(key, struct.getValue(key), loc); } } } else if (target instanceof Iterable) { loc = ruleContext.getRule().getRuleClassObject().getConfiguredTargetFunction().getLocation(); for (Object o : (Iterable) target) { SkylarkClassObject declaredProvider = SkylarkType.cast( o, SkylarkClassObject.class, loc, "A return value of rule implementation function should be " + "a sequence of declared providers"); Location creationLoc = declaredProvider.getCreationLocOrNull(); builder.addSkylarkDeclaredProvider( declaredProvider, creationLoc != null ? creationLoc : loc); } } if ((statelessRunfiles != null) && (dataRunfiles != null || defaultRunfiles != null)) { throw new EvalException( loc, "Cannot specify the provider 'runfiles' " + "together with 'data_runfiles' or 'default_runfiles'"); } if (statelessRunfiles == null && dataRunfiles == null && defaultRunfiles == null) { // No runfiles specified, set default statelessRunfiles = Runfiles.EMPTY; } RunfilesProvider runfilesProvider = statelessRunfiles != null ? RunfilesProvider.simple(merge(statelessRunfiles, executable, ruleContext)) : RunfilesProvider.withData( // The executable doesn't get into the default runfiles if we have runfiles states. // This is to keep skylark genrule consistent with the original genrule. defaultRunfiles != null ? defaultRunfiles : Runfiles.EMPTY, dataRunfiles != null ? dataRunfiles : Runfiles.EMPTY); builder.addProvider(RunfilesProvider.class, runfilesProvider); Runfiles computedDefaultRunfiles = runfilesProvider.getDefaultRunfiles(); // This works because we only allowed to call a rule *_test iff it's a test type rule. boolean testRule = TargetUtils.isTestRuleName(ruleContext.getRule().getRuleClass()); if (testRule && computedDefaultRunfiles.isEmpty()) { throw new EvalException(loc, "Test rules have to define runfiles"); } if (executable != null || testRule) { RunfilesSupport runfilesSupport = computedDefaultRunfiles.isEmpty() ? null : RunfilesSupport.withExecutable(ruleContext, computedDefaultRunfiles, executable); builder.setRunfilesSupport(runfilesSupport, executable); } if (ruleContext.getRule().getRuleClassObject().isSkylarkTestable()) { SkylarkClassObject actions = ActionsProvider.create(ruleContext.getAnalysisEnvironment().getRegisteredActions()); builder.addSkylarkDeclaredProvider(actions, loc); } try { return builder.build(); } catch (IllegalArgumentException e) { throw new EvalException(loc, e.getMessage()); } }