Skip to content

Commit

Permalink
Windows: Make runfiles symlink tree actions depend on the runfiles ar…
Browse files Browse the repository at this point in the history
…tifacts.

Windows distinguishes between symlinks to files and symlinks to directories. The
code to create symlink trees on Windows thus inspects the targets of the links
to learn what kind of symlink to make. Unfortunately, the symlinking code did
not depend on the link targets actually being created. This race could lead to
non-deterministic and non-functional symlink trees.

Fix this problem by depending on runfiles artifacts in the SymtreeTreeAction
when the host platform is Windows.

It's certainly possible to avoid this os-dependent input dependency—by using
in-memory Artifact state for the in-process implementation and extending the
runfiles manifest format to indicate target type for build-runfiles-windows—but
this commit is the most straightforward change that remediates the serious
correctness issue represented by the previous state.

This topic has a long history. When Windows runfiles trees were actually copies
of artifacts, the "symlink" action obviously had to depend on the origin
artifacts (41f4456). That code was removed in
an interregnum period where runfiles trees weren't supported at all on Windows
(0885abd). However, the dependency was not
added back when Windows symlinked runfiles trees support was finally added
(b592dbd).

Closes #12018.

PiperOrigin-RevId: 330496487
  • Loading branch information
benjaminp authored and copybara-github committed Sep 8, 2020
1 parent 0cdd71f commit 6363bb4
Showing 1 changed file with 21 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.Runfiles;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.util.OS;
import com.google.devtools.build.lib.vfs.PathFragment;
import javax.annotation.Nullable;

Expand Down Expand Up @@ -106,9 +107,7 @@ public SymlinkTreeAction(
boolean skipRunfilesManifests) {
super(
owner,
skipRunfilesManifests && enableRunfiles && (filesetRoot == null)
? NestedSetBuilder.emptySet(Order.STABLE_ORDER)
: NestedSetBuilder.create(Order.STABLE_ORDER, inputManifest),
computeInputs(enableRunfiles, skipRunfilesManifests, runfiles, inputManifest),
ImmutableSet.of(outputManifest),
env);
Preconditions.checkArgument(outputManifest.getPath().getBaseName().equals("MANIFEST"));
Expand All @@ -124,6 +123,24 @@ public SymlinkTreeAction(
this.inputManifest = this.skipRunfilesManifests ? null : inputManifest;
}

private static NestedSet<Artifact> computeInputs(
boolean enableRunfiles,
boolean skipRunfilesManifests,
Runfiles runfiles,
Artifact inputManifest) {
NestedSetBuilder<Artifact> inputs = NestedSetBuilder.<Artifact>stableOrder();
if (!skipRunfilesManifests || !enableRunfiles || runfiles == null) {
inputs.add(inputManifest);
}
// All current strategies (in-process and build-runfiles-windows) for
// making symlink trees on Windows depend on the target files
// existing, so directory or file links can be made as appropriate.
if (enableRunfiles && runfiles != null && OS.getCurrent() == OS.WINDOWS) {
inputs.addTransitive(runfiles.getAllArtifacts());
}
return inputs.build();
}

public Artifact getInputManifest() {
return inputManifest;
}
Expand Down

0 comments on commit 6363bb4

Please sign in to comment.