use of com.google.devtools.build.lib.actions.Artifact in project bazel by bazelbuild.
the class CppCompileAction method validateInclusions.
/**
* Enforce that the includes actually visited during the compile were properly
* declared in the rules.
*
* <p>The technique is to walk through all of the reported includes that gcc
* emits into the .d file, and verify that they came from acceptable
* relative include directories. This is done in two steps:
*
* <p>First, each included file is stripped of any include path prefix from
* {@code quoteIncludeDirs} to produce an effective relative include dir+name.
*
* <p>Second, the remaining directory is looked up in {@code declaredIncludeDirs},
* a list of acceptable dirs. This list contains a set of dir fragments that
* have been calculated by the configured target to be allowable for inclusion
* by this source. If no match is found, an error is reported and an exception
* is thrown.
*
* @throws ActionExecutionException iff there was an undeclared dependency
*/
@VisibleForTesting
public void validateInclusions(Iterable<Artifact> inputsForValidation, ArtifactExpander artifactExpander, EventHandler eventHandler) throws ActionExecutionException {
IncludeProblems errors = new IncludeProblems();
IncludeProblems warnings = new IncludeProblems();
Set<Artifact> allowedIncludes = new HashSet<>();
for (Artifact input : Iterables.concat(mandatoryInputs, prunableInputs)) {
if (input.isMiddlemanArtifact() || input.isTreeArtifact()) {
artifactExpander.expand(input, allowedIncludes);
}
allowedIncludes.add(input);
}
allowedIncludes.addAll(resolvedInputs);
if (optionalSourceFile != null) {
allowedIncludes.add(optionalSourceFile);
}
Iterable<PathFragment> ignoreDirs = cppConfiguration.isStrictSystemIncludes() ? cppConfiguration.getBuiltInIncludeDirectories() : getValidationIgnoredDirs();
// Copy the sets to hash sets for fast contains checking.
// Avoid immutable sets here to limit memory churn.
Set<PathFragment> declaredIncludeDirs = Sets.newHashSet(context.getDeclaredIncludeDirs());
Set<PathFragment> warnIncludeDirs = Sets.newHashSet(context.getDeclaredIncludeWarnDirs());
Set<Artifact> declaredIncludeSrcs = Sets.newHashSet(getDeclaredIncludeSrcs());
Set<Artifact> transitiveModules = Sets.newHashSet(context.getTransitiveModules(usePic));
for (Artifact input : inputsForValidation) {
if (context.getTransitiveCompilationPrerequisites().contains(input) || transitiveModules.contains(input) || allowedIncludes.contains(input)) {
// ignore our fixed source in mandatoryInput: we just want includes
continue;
}
// Ignore headers from built-in include directories.
if (FileSystemUtils.startsWithAny(input.getExecPath(), ignoreDirs)) {
continue;
}
if (!isDeclaredIn(input, declaredIncludeDirs, declaredIncludeSrcs)) {
// There are no declared include sources we need to warn about, so use an empty set here.
if (isDeclaredIn(input, warnIncludeDirs, ImmutableSet.<Artifact>of())) {
warnings.add(input.getPath().toString());
} else {
errors.add(input.getPath().toString());
}
}
}
if (VALIDATION_DEBUG_WARN) {
synchronized (System.err) {
if (VALIDATION_DEBUG >= 2 || errors.hasProblems() || warnings.hasProblems()) {
if (errors.hasProblems()) {
System.err.println("ERROR: Include(s) were not in declared srcs:");
} else if (warnings.hasProblems()) {
System.err.println("WARN: Include(s) were not in declared srcs:");
} else {
System.err.println("INFO: Include(s) were OK for '" + getSourceFile() + "', declared srcs:");
}
for (Artifact a : context.getDeclaredIncludeSrcs()) {
System.err.println(" '" + a.toDetailString() + "'");
}
System.err.println(" or under declared dirs:");
for (PathFragment f : Sets.newTreeSet(context.getDeclaredIncludeDirs())) {
System.err.println(" '" + f + "'");
}
System.err.println(" or under declared warn dirs:");
for (PathFragment f : Sets.newTreeSet(context.getDeclaredIncludeWarnDirs())) {
System.err.println(" '" + f + "'");
}
System.err.println(" with prefixes:");
for (PathFragment dirpath : context.getQuoteIncludeDirs()) {
System.err.println(" '" + dirpath + "'");
}
}
}
}
if (warnings.hasProblems()) {
eventHandler.handle(Event.warn(getOwner().getLocation(), warnings.getMessage(this, getSourceFile())).withTag(Label.print(getOwner().getLabel())));
}
errors.assertProblemFree(this, getSourceFile());
}
use of com.google.devtools.build.lib.actions.Artifact in project bazel by bazelbuild.
the class SkyframeAwareActionTest method testActionWithNonChangingInputAndNonChangingSkyframeDeps.
@Test
public void testActionWithNonChangingInputAndNonChangingSkyframeDeps() throws Exception {
final SkyKey skyframeDep = FileStateValue.key(createSkyframeDepOfAction());
// Assert that an action-cache-check-bypassing action is executed only once if neither its input
// nor its Skyframe dependency changes between builds.
assertActionExecutions(new ExecutionCountingActionFactory() {
@Override
public ExecutionCountingAction create(Artifact input, Artifact output, AtomicInteger executionCounter) {
return new SkyframeAwareExecutionCountingAction(input, output, executionCounter, skyframeDep);
}
}, ChangeArtifact.DONT_CHANGE, new Callable<Void>() {
@Override
public Void call() throws Exception {
// Invalidate the dependency but leave its value up-to-date, so the action should not
// be rebuilt.
differencer.invalidate(ImmutableList.of(skyframeDep));
return null;
}
}, ExpectActionIs.DIRTIED_BUT_VERIFIED_CLEAN);
}
use of com.google.devtools.build.lib.actions.Artifact in project bazel by bazelbuild.
the class SkyframeAwareActionTest method assertActionExecutions.
private void assertActionExecutions(ExecutionCountingActionFactory actionFactory, ChangeArtifact changeActionInput, Callable<Void> betweenBuilds, ExpectActionIs expectActionIs) throws Exception {
// Set up the action's input, output, owner and most importantly the execution counter.
Artifact actionInput = createSourceArtifact("foo/action-input.txt");
Artifact actionOutput = createDerivedArtifact("foo/action-output.txt");
AtomicInteger executionCounter = new AtomicInteger(0);
scratch.file(actionInput.getPath().getPathString(), "foo");
// Generating actions of artifacts are found by looking them up in the graph. The lookup value
// must be present in the graph before execution.
Action action = actionFactory.create(actionInput, actionOutput, executionCounter);
registerAction(action);
// Build the output for the first time.
builder.buildArtifacts(reporter, ImmutableSet.of(actionOutput), null, null, null, null, executor, null, false, null, null);
// Sanity check that our invalidation receiver is working correctly. We'll rely on it again.
SkyKey actionKey = ActionExecutionValue.key(action);
TrackingEvaluationProgressReceiver.EvaluatedEntry evaluatedAction = progressReceiver.getEvalutedEntry(actionKey);
assertThat(evaluatedAction).isNotNull();
SkyValue actionValue = evaluatedAction.value;
// Mutate the action input if requested.
maybeChangeFile(actionInput, changeActionInput);
// Execute user code before next build.
betweenBuilds.call();
// Rebuild the output.
progressReceiver.reset();
builder.buildArtifacts(reporter, ImmutableSet.of(actionOutput), null, null, null, null, executor, null, false, null, null);
if (expectActionIs.dirtied()) {
assertThat(progressReceiver.wasInvalidated(actionKey)).isTrue();
TrackingEvaluationProgressReceiver.EvaluatedEntry newEntry = progressReceiver.getEvalutedEntry(actionKey);
assertThat(newEntry).isNotNull();
if (expectActionIs.actuallyClean()) {
// Action was dirtied but verified clean.
assertThat(newEntry.state).isEqualTo(EvaluationState.CLEAN);
assertThat(newEntry.value).isEqualTo(actionValue);
} else {
// Action was dirtied and rebuilt. It was either reexecuted or was an action cache hit,
// doesn't matter here.
assertThat(newEntry.state).isEqualTo(EvaluationState.BUILT);
assertThat(newEntry.value).isNotEqualTo(actionValue);
}
} else {
// Action was not dirtied.
assertThat(progressReceiver.wasInvalidated(actionKey)).isFalse();
}
// Assert that the action was executed the right number of times. Whether the action execution
// function was called again is up for the test method to verify.
assertThat(executionCounter.get()).isEqualTo(expectActionIs.reexecuted() ? 2 : 1);
}
use of com.google.devtools.build.lib.actions.Artifact in project bazel by bazelbuild.
the class TreeArtifactBuildTest method testOneExpandedActionThrowsInActionTemplate.
@Test
public void testOneExpandedActionThrowsInActionTemplate() throws Throwable {
// expect errors
reporter.removeHandler(failFastHandler);
// artifact1 is a tree artifact generated by a TouchingTestAction.
Artifact artifact1 = createTreeArtifact("treeArtifact1");
TreeFileArtifact treeFileArtifactA = ActionInputHelper.treeFileArtifact(artifact1, new PathFragment("child1"));
TreeFileArtifact treeFileArtifactB = ActionInputHelper.treeFileArtifact(artifact1, new PathFragment("child2"));
registerAction(new TouchingTestAction(treeFileArtifactA, treeFileArtifactB));
// artifact2 is a tree artifact generated by an action template.
Artifact artifact2 = createTreeArtifact("treeArtifact2");
SpawnActionTemplate actionTemplate = ActionsTestUtil.createDummySpawnActionTemplate(artifact1, artifact2);
registerAction(actionTemplate);
// We mock out the action template function to expand into two actions:
// One Action that touches the output file.
// The other action that just throws when executed.
TreeFileArtifact expectedOutputTreeFileArtifact1 = ActionInputHelper.treeFileArtifact(artifact2, new PathFragment("child1"));
TreeFileArtifact expectedOutputTreeFileArtifact2 = ActionInputHelper.treeFileArtifact(artifact2, new PathFragment("child2"));
Action generateOutputAction = new DummyAction(ImmutableList.<Artifact>of(treeFileArtifactA), expectedOutputTreeFileArtifact1);
Action throwingAction = new ThrowingDummyAction(ImmutableList.<Artifact>of(treeFileArtifactB), ImmutableList.<Artifact>of(expectedOutputTreeFileArtifact2));
actionTemplateExpansionFunction = new DummyActionTemplateExpansionFunction(ImmutableMultimap.<ActionTemplate<?>, Action>of(actionTemplate, generateOutputAction, actionTemplate, throwingAction));
try {
buildArtifact(artifact2);
fail("Expected BuildFailedException");
} catch (BuildFailedException e) {
assertThat(e.getMessage()).contains("Throwing dummy action");
}
}
use of com.google.devtools.build.lib.actions.Artifact in project bazel by bazelbuild.
the class TreeArtifactBuildTest method testInputTreeArtifactPerActionFileCache.
@Test
public void testInputTreeArtifactPerActionFileCache() throws Exception {
TouchingTestAction actionOne = new TouchingTestAction(outOneFileOne, outOneFileTwo);
registerAction(actionOne);
final Artifact normalOutput = createDerivedArtifact("normal/out");
Action testAction = new TestAction(TestAction.NO_EFFECT, ImmutableList.of(outOne), ImmutableList.of(normalOutput)) {
@Override
public void execute(ActionExecutionContext actionExecutionContext) {
try {
// Check the file cache for input TreeFileArtifacts.
ActionInputFileCache fileCache = actionExecutionContext.getActionInputFileCache();
assertThat(fileCache.getDigest(outOneFileOne)).isNotNull();
assertThat(fileCache.getDigest(outOneFileTwo)).isNotNull();
// Touch the action output.
touchFile(normalOutput);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
registerAction(testAction);
buildArtifact(normalOutput);
}
Aggregations